@greese/mcp 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +7 -0
- package/dist/data.d.ts +60 -0
- package/dist/data.js +3 -0
- package/dist/data.json +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/search.d.ts +17 -0
- package/dist/search.js +58 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +301 -0
- package/package.json +66 -4
package/dist/data.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"0.1.1","components":[{"name":"Accordion","category":"Content","description":"A stack of collapsible sections. Each AccordionItem is a native\n`<details>`, so keyboard, screen-reader and find-in-page support is built in.\nA Server Component: it ships no JavaScript.\n\nIt hands its items the shared `name` (with `exclusive`) and its icons\ndirectly, so they reach the AccordionItems among its children (in fragments\nand lists too). An item inside a component of your own isn't one of them:\ngive it `name` and icons itself.\n\n```tsx\n<Accordion exclusive icon={<PlusIcon />} openIcon={<MinusIcon />}>\n <AccordionItem title=\"Shipping\">…</AccordionItem>\n <AccordionItem title=\"Returns\">…</AccordionItem>\n</Accordion>\n```","file":"packages/react/src/components/Accordion/Accordion.tsx","props":[{"name":"exclusive","type":"boolean","required":false,"default":"false","description":"Only one item open at a time. Native: the items share a `<details name>`,\nso the browser closes the others. No JS involved."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"default":"a downward chevron","description":"Every item's icon, closed (or both states without `openIcon`). An item\nthat sets `icon` or `openIcon` uses its own pair instead, never half of\neach."},{"name":"iconTransition","type":"CollapsibleIconTransition","required":false,"default":"'rotate', or 'fade' with an `openIcon`","description":"How every item's icon changes state, unless the item sets its own icons\nor transition."},{"name":"openIcon","type":"ReactNode","required":false,"description":"Every item's open-state icon, unless the item sets its own icons."}],"styles":{"className":"greese-Accordion","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { CSSProperties } from 'react'\nimport type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Accordion, AccordionItem } from '@greese/react'\nimport { ChevronRightIcon, MinusIcon, PlusIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Content/Accordion',\n component: Accordion,\n subcomponents: { AccordionItem },\n args: {\n exclusive: true,\n style: { maxInlineSize: '36rem' },\n children: (\n <>\n <AccordionItem title=\"How long does shipping take?\" defaultOpen>\n Two to four business days within the country.\n </AccordionItem>\n <AccordionItem title=\"Can I return an item?\">\n Yes, within 30 days, in its original condition.\n </AccordionItem>\n <AccordionItem title=\"Do you ship internationally?\">\n To most countries.\n </AccordionItem>\n </>\n ),\n },\n} satisfies Meta<typeof Accordion>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native `<details name>`: opening one closes the others, with no JavaScript. */\nexport const Playground: Story = {}\n\nexport const Independent: Story = { args: { exclusive: false } }\n\n/** An icon per state: a plus that crossfades to a minus as each item opens. */\nexport const PlusAndMinus: Story = {\n args: { icon: <PlusIcon />, openIcon: <MinusIcon /> },\n}\n\n/** One icon of your own that turns: here a chevron pointing on, turned a quarter to point down. */\nexport const OwnIcon: Story = {\n args: {\n icon: <ChevronRightIcon />,\n iconTransition: 'rotate',\n style: {\n maxInlineSize: '36rem',\n '--greese-collapsible-icon-turn': '90deg',\n } as CSSProperties,\n },\n}\n"},{"name":"AccordionItem","category":"Content","description":"One section of an Accordion: a Collapsible, which takes the Accordion's\n`name` and icons when it doesn't set its own. Takes every Collapsible prop.\n\n```tsx\n<AccordionItem title=\"Shipping\">Ships in two days.</AccordionItem>\n```","file":"packages/react/src/components/Accordion/Accordion.tsx","props":[{"name":"title","type":"ReactNode","required":true,"description":"The always-visible summary that toggles the content."},{"name":"defaultOpen","type":"boolean","required":false,"description":"Initial state when uncontrolled."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"default":"a downward chevron","description":"The icon beside the title: the closed state's, or both states' when there\nis no `openIcon`. `null` shows none."},{"name":"iconTransition","type":"CollapsibleIconTransition","required":false,"default":"'rotate' with one icon, 'fade' with an `openIcon`","description":"How the icon changes state: `rotate` turns it (by\n`--greese-collapsible-icon-turn`, 180deg), `fade` crossfades the closed\nand open icons, `none` switches at once. Under reduced motion every one\nswitches at once."},{"name":"name","type":"string","required":false,"description":"Exclusive group name: only one `<details>` with the same name is open at\na time (native, no JS). Accordion sets it for you."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes."},{"name":"open","type":"boolean","required":false,"description":"Controlled state; pair with `onOpenChange`."},{"name":"openIcon","type":"ReactNode","required":false,"description":"The open state's icon. With one, the two icons swap as it opens and closes."}],"styles":{"className":"greese-AccordionItem","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Accordion, AccordionItem } from '@greese/react'\n\n/** One item of an Accordion: a Collapsible that shares the group's name. */\nconst meta = {\n title: 'Content/AccordionItem',\n component: AccordionItem,\n args: {\n title: 'How long does shipping take?',\n defaultOpen: true,\n children: 'Two to four business days within the country.',\n },\n decorators: [\n (Story) => (\n <Accordion style={{ maxInlineSize: '36rem' }}>\n <Story />\n <AccordionItem title=\"Can I return an item?\">\n Yes, within 30 days, in its original condition.\n </AccordionItem>\n </Accordion>\n ),\n ],\n} satisfies Meta<typeof AccordionItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The first item; the second is there for context. */\nexport const Playground: Story = {}\n\nexport const Closed: Story = { args: { defaultOpen: false } }\n"},{"name":"ActionSelect","category":"Forms","description":"An icon button joined to a select: one control to act and one to choose,\nsuch as \"new project\" beside a project switcher, or \"export\" beside a\nformat picker (run the picked option from `onValueChange` and the last one\nfrom `onAction`).\n\n```tsx\n<ActionSelect\n icon={<PlusIcon />} actionLabel=\"New project\" onAction={create}\n selectLabel=\"Project\" options={projects} value={id} onValueChange={open}\n/>\n```\n\nThe select is native: the platform picker on phones, typeahead everywhere.","file":"packages/react/src/components/ActionSelect/ActionSelect.tsx","props":[{"name":"actionLabel","type":"string","required":true,"description":"The button's accessible name, e.g. \"Create project\"."},{"name":"icon","type":"ReactNode","required":true,"description":"The button's icon: any element, from any icon set."},{"name":"onAction","type":"() => void","required":true,"description":"Runs when the button is pressed."},{"name":"selectLabel","type":"string","required":true,"description":"The select's accessible name, e.g. \"Project\"."},{"name":"children","type":"ReactNode","required":false,"description":"`<option>` and `<optgroup>` elements, instead of `options`."},{"name":"defaultValue","type":"string","required":false,"description":"The option chosen at first, when the component keeps its own state."},{"name":"disabled","type":"boolean","required":false,"description":"Disables both the button and the select."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onValueChange","type":"((value: string) => void)","required":false,"description":"Called with the new value when the user chooses an option."},{"name":"options","type":"readonly ActionSelectOption[]","required":false,"description":"The choices. Or pass `<option>` / `<optgroup>` children instead."},{"name":"selectProps","type":"Omit<SelectProps, \"children\" | \"defaultValue\" | \"onChange\" | \"value\" | \"size\">","required":false,"description":"Extra props for the Select (name, required, placeholder…)."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height and text size of the button and select together."},{"name":"value","type":"string","required":false,"description":"The chosen option's value, when you control it. Pair with `onValueChange`."}],"styles":{"className":"greese-ActionSelect","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\nimport { ActionSelect, toast, Toaster } from '@greese/react'\nimport { ArrowRightIcon, PlusIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/ActionSelect',\n component: ActionSelect,\n args: {\n icon: <PlusIcon />,\n actionLabel: 'New project',\n onAction: () => {},\n selectLabel: 'Project',\n defaultValue: 'greese',\n options: [\n { value: 'greese', label: 'Greese UI', group: 'Recent' },\n { value: 'docs', label: 'Docs site', group: 'Recent' },\n { value: 'api', label: 'Public API' },\n { value: 'archive', label: 'Archive', disabled: true },\n ],\n },\n argTypes: { size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] } },\n decorators: [(Story) => <div style={{ maxInlineSize: '20rem' }}>{Story()}</div>],\n} satisfies Meta<typeof ActionSelect>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Act with the button, choose with the native select. */\nexport const Playground: Story = {}\n\n/**\n * A recipe: picking a format runs the export, and the button repeats the\n * last one.\n */\nexport const RepeatLastAction: Story = {\n render: function Render() {\n const [format, setFormat] = useState('png')\n const run = (value: string) => {\n setFormat(value)\n toast({ title: `Exported as ${value.toUpperCase()}`, tone: 'positive' })\n }\n return (\n <>\n <ActionSelect\n icon={<ArrowRightIcon />}\n actionLabel={`Export as ${format.toUpperCase()}`}\n onAction={() => run(format)}\n selectLabel=\"Export format\"\n value={format}\n onValueChange={run}\n options={[\n { value: 'png', label: 'PNG' },\n { value: 'svg', label: 'SVG' },\n { value: 'pdf', label: 'PDF' },\n ]}\n />\n <Toaster />\n </>\n )\n },\n}\n"},{"name":"Alert","category":"Content","description":"A message about the page or a task: info, success, warning or error.\n\n```tsx\n<Alert tone=\"warning\" title=\"Payment failed\" onDismiss={hide}>\n Update your card to keep your plan.\n</Alert>\n```","file":"packages/react/src/components/Alert/Alert.tsx","props":[{"name":"actions","type":"ReactNode","required":false,"description":"Actions (buttons, links) shown after the message."},{"name":"announce","type":"boolean","required":false,"description":"Announce to screen readers when it appears: `role=\"alert\"` for negative\nand warning tones, `role=\"status\"` otherwise. Off by default, because a\nmessage present on page load should not interrupt."},{"name":"dismissLabel","type":"string","required":false,"default":"Dismiss","description":"Accessible name for the dismiss button."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"description":"Leading icon from your icon set. Decorative: the text carries the meaning."},{"name":"onDismiss","type":"(() => void)","required":false,"description":"Shows a dismiss button that calls this."},{"name":"title","type":"ReactNode","required":false,"description":"A short heading shown in bold above the message."},{"name":"tone","type":"FeedbackTone","required":false,"default":"info","description":"What kind of message it is, which sets its color: info, positive,\nwarning, negative, neutral, or a brand color (primary, secondary,\ntertiary) for announcements."},{"name":"variant","type":"\"soft\" | \"outline\"","required":false,"default":"soft","description":"`soft` fills the background with a tint of the tone; `outline` draws only a\nborder."}],"styles":{"className":"greese-Alert","parts":["actions","body","dismiss","icon","title"],"modifiers":["info","negative","neutral","outline","positive","primary","secondary","soft","tertiary","warning"],"attributes":[],"variables":["--greese-alert-tone","--greese-alert-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Alert, Button, Stack } from '@greese/react'\nimport { InfoIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Content/Alert',\n component: Alert,\n args: {\n tone: 'info',\n title: 'Scheduled maintenance',\n icon: <InfoIcon />,\n children: 'The dashboard will be read-only on Sunday from 02:00 to 03:00 UTC.',\n },\n argTypes: {\n tone: {\n control: 'inline-radio',\n options: [\n 'info',\n 'positive',\n 'warning',\n 'negative',\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n ],\n },\n variant: { control: 'inline-radio', options: ['soft', 'outline'] },\n },\n} satisfies Meta<typeof Alert>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Tones: Story = {\n render: () => (\n <Stack gap={3} maxW=\"36rem\">\n <Alert tone=\"positive\" title=\"Payment received\" onDismiss={() => {}} />\n <Alert\n tone=\"warning\"\n title=\"Your trial ends in 3 days\"\n actions={\n <Button size=\"sm\" variant=\"outline\" tone=\"neutral\">\n Upgrade\n </Button>\n }\n />\n <Alert tone=\"negative\" variant=\"outline\" title=\"Couldn't save\">\n Check your connection and try again.\n </Alert>\n <Alert tone=\"secondary\" title=\"New: dark mode\">\n A brand tone, for announcements rather than status.\n </Alert>\n </Stack>\n ),\n}\n"},{"name":"AppBar","category":"Navigation","description":"The top bar: a `<header>` row for brand, navigation and actions. Padded for\nnotches and the status bar (safe-area insets). Lay out its contents with\nStack and Spacer.\n\n```tsx\n<AppBar sticky elevateOnScroll>\n <SidebarTrigger />\n <Heading level={1} variant=\"h5\">Inbox</Heading>\n</AppBar>\n```","file":"packages/react/src/components/AppBar/AppBar.tsx","props":[{"name":"elevateOnScroll","type":"boolean","required":false,"default":"true","description":"Gain a shadow once the page scrolls (CSS scroll-driven; static where unsupported)."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"sticky","type":"boolean","required":false,"default":"true","description":"Stay at the top while scrolling."}],"styles":{"className":"greese-AppBar","parts":[],"modifiers":["elevate","sticky"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { AppBar, Button, Spacer, Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Navigation/AppBar',\n component: AppBar,\n parameters: { layout: 'fullscreen' },\n args: {\n children: (\n <>\n <Text weight=\"semibold\">Greese</Text>\n <Spacer />\n <Button size=\"sm\" variant=\"outline\" tone=\"neutral\">\n Sign out\n </Button>\n </>\n ),\n },\n // A box that scrolls on its own, so the bar has something to stick to\n // wherever the story is shown (a page's canvas only scrolls sideways).\n render: (args) => (\n <div style={{ blockSize: '24rem', overflowY: 'auto' }}>\n <AppBar {...args} />\n <Stack gap={4} p={5}>\n <Text tone=\"muted\">\n Scroll this box: the bar sticks and gains a shadow, with no scroll listener.\n </Text>\n {Array.from({ length: 12 }, (_, i) => (\n <Text key={i}>\n Row {i + 1}. Content scrolls under the bar while it stays at the top.\n </Text>\n ))}\n </Stack>\n </div>\n ),\n} satisfies Meta<typeof AppBar>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Static: Story = { args: { sticky: false, elevateOnScroll: false } }\n"},{"name":"AspectRatio","category":"Layout","description":"A media frame with a fixed aspect ratio, reserving space before the media\nloads so the layout never shifts (no CLS).\n\n```tsx\n<AspectRatio ratio={{ xs: 1, md: 16 / 9 }}><img src={src} alt=\"\" /></AspectRatio>\n```","file":"packages/react/src/components/AspectRatio/AspectRatio.tsx","props":[{"name":"ratio","type":"Responsive<string | number>","required":true,"description":"Width / height, e.g. `16 / 9` or `'4 / 3'`. Per breakpoint if needed."},{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"fit","type":"\"cover\" | \"contain\"","required":false,"default":"cover","description":"How a direct image or video child fills the frame."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-AspectRatio","parts":[],"modifiers":["contain"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { AspectRatio, Box } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Layout/AspectRatio',\n component: AspectRatio,\n args: { ratio: { xs: 1, md: 16 / 9 } },\n render: (args) => (\n <Box maxW=\"32rem\">\n <AspectRatio {...args} style={{ borderRadius: 'var(--greese-radius-lg)' }}>\n <img alt=\"\" src={art(210)} />\n </AspectRatio>\n </Box>\n ),\n} satisfies Meta<typeof AspectRatio>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Square on phones, 16:9 from md. Space is reserved before media loads. */\nexport const Playground: Story = {}\n\n/** `fit=\"contain\"` letterboxes instead of cropping. */\nexport const Contain: Story = { args: { ratio: 1, fit: 'contain' } }\n"},{"name":"AutoLayout","category":"Layout","description":"Rows of items sized in columns that may grow into spare room: each item\ntakes at least `size` columns and stretches up to `maxSize`, wrapping to a\nnew row when it no longer fits. Both may change per breakpoint.\n\n```tsx\n<AutoLayout gap={3}>\n <AutoLayoutItem size={{ xs: 12, md: 4 }} maxSize={{ md: 6 }}>…</AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 4 }}>…</AutoLayoutItem>\n</AutoLayout>\n```\n\nGrid suits fixed tracks; AutoLayout suits rows whose items share leftover\nspace, such as a form whose fields widen when a row has room.","file":"packages/react/src/components/AutoLayout/AutoLayout.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"columns","type":"number","required":false,"default":"12","description":"Columns in a row: the unit for each item's `size`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between items, both ways: a scale token (`0`–`8`) or any CSS length."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"rowGap","type":"Responsive<SpaceValue>","required":false,"description":"Space between rows, where it differs from `gap`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-AutoLayout","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-autolayout-column-gap","--greese-autolayout-columns"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { AutoLayout, AutoLayoutItem, Field, Input, Select, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/AutoLayout',\n component: AutoLayout,\n subcomponents: { AutoLayoutItem },\n args: { gap: 3 },\n} satisfies Meta<typeof AutoLayout>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * Full width on phones. From md, items take 4 of 12 columns; the first may\n * grow to 6 and the last to 8 when their row has room.\n */\nexport const Playground: Story = {\n render: (args) => (\n <AutoLayout {...args}>\n <AutoLayoutItem size={{ xs: 12, md: 4 }} maxSize={{ md: 6 }}>\n <Tile>4 → 6</Tile>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 4 }}>\n <Tile>4</Tile>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 4 }}>\n <Tile>4</Tile>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 4 }} maxSize={{ md: 8 }}>\n <Tile>4 → 8 (alone on its row)</Tile>\n </AutoLayoutItem>\n </AutoLayout>\n ),\n}\n\n/** A form whose fields widen into whatever their row leaves over. */\nexport const Form: Story = {\n render: (args) => (\n <AutoLayout {...args} gap={{ xs: 3, md: 4 }}>\n <AutoLayoutItem size={{ xs: 12, sm: 6 }}>\n <Field label=\"First name\">\n <Input />\n </Field>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, sm: 6 }}>\n <Field label=\"Last name\">\n <Input />\n </Field>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 7 }} maxSize={{ md: 12 }}>\n <Field label=\"Street\">\n <Input />\n </Field>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 8, md: 3 }} maxSize={{ xs: 12 }}>\n <Field label=\"City\">\n <Input />\n </Field>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 4, md: 2 }}>\n <Field label=\"Code\">\n <Input />\n </Field>\n </AutoLayoutItem>\n <AutoLayoutItem size={{ xs: 12, md: 4 }}>\n <Field label=\"Country\">\n <Select placeholder=\"Choose…\">\n <option>Norway</option>\n </Select>\n </Field>\n </AutoLayoutItem>\n </AutoLayout>\n ),\n}\n\n/** `columns` changes the unit: here a row of 5. */\nexport const Columns: Story = {\n render: () => (\n <AutoLayout columns={5} gap={2}>\n {[1, 2, 3, 4, 5, 6, 7].map((n) => (\n <AutoLayoutItem key={n} size={1} maxSize={n > 5 ? 5 : 1}>\n <Tile>{n}</Tile>\n </AutoLayoutItem>\n ))}\n </AutoLayout>\n ),\n}\n"},{"name":"AutoLayoutItem","category":"Layout","description":"One item of an AutoLayout.","file":"packages/react/src/components/AutoLayout/AutoLayout.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxSize","type":"Size","required":false,"description":"Columns the item may grow to when its row has room. Defaults to `size` at\neach breakpoint, so an item never grows unless asked to."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"size","type":"Size","required":false,"description":"Columns the item always takes. Unset: the whole row."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-AutoLayoutItem","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-autolayoutitem-columns","--greese-autolayoutitem-gap","--greese-autolayoutitem-m","--greese-autolayoutitem-max","--greese-autolayoutitem-p","--greese-autolayoutitem-p-gap","--greese-autolayoutitem-q","--greese-autolayoutitem-q-gap","--greese-autolayoutitem-s","--greese-autolayoutitem-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { AutoLayout, AutoLayoutItem, Tile } from '@greese/react'\n\n/** An AutoLayout item: a size in twelfths, and how far it may grow. */\nconst meta = {\n title: 'Layout/AutoLayoutItem',\n component: AutoLayoutItem,\n args: {\n size: { xs: 12, md: 4 },\n maxSize: { md: 8 },\n children: <Tile>4, grows to 8</Tile>,\n },\n decorators: [\n (Story) => (\n <AutoLayout gap={3}>\n <AutoLayoutItem size={{ xs: 12, md: 4 }}>\n <Tile>4</Tile>\n </AutoLayoutItem>\n <Story />\n </AutoLayout>\n ),\n ],\n} satisfies Meta<typeof AutoLayoutItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** From md, it widens into the room its row leaves. */\nexport const Playground: Story = {}\n"},{"name":"Avatar","category":"Content","description":"A person's picture, falling back to their initials if missing or broken.\n\n```tsx\n<Avatar name=\"Ada Lovelace\" src=\"/ada.jpg\" />\n```","file":"packages/react/src/components/Avatar/Avatar.tsx","props":[{"name":"name","type":"string","required":true,"description":"The person or thing: used for the alt text and the initials fallback."},{"name":"fallback","type":"ReactNode","required":false,"description":"Shown instead of initials when there is no image (an icon, say)."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"shape","type":"\"circle\" | \"square\"","required":false,"default":"circle","description":"`circle`, or `square` with rounded corners (for organisations and things)."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Diameter: `xs` to `xl`, from 1.5rem to 4rem."},{"name":"src","type":"string","required":false,"description":"Image URL. If it's missing or fails to load, initials from `name` (or\n`fallback`) show instead."}],"styles":{"className":"greese-Avatar","parts":["fallback"],"modifiers":["count","lg","md","sm","square","xl","xs"],"attributes":[],"variables":["--greese-avatar-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, Stack } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Content/Avatar',\n component: Avatar,\n args: { name: 'Ada Lovelace', size: 'lg' },\n argTypes: {\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg', 'xl'] },\n shape: { control: 'inline-radio', options: ['circle', 'square'] },\n },\n} satisfies Meta<typeof Avatar>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Initials when there is no image. */\nexport const Playground: Story = {}\n\nexport const Variants: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} align=\"center\">\n {(['sm', 'md', 'lg', 'xl'] as const).map((size) => (\n <Avatar key={size} name=\"Ada Lovelace\" size={size} />\n ))}\n <Avatar name=\"Grace Hopper\" src={art(320, '1 1')} size=\"lg\" />\n <Avatar name=\"Broken Image\" src=\"/does-not-exist.png\" size=\"lg\" />\n <Avatar name=\"Square\" shape=\"square\" size=\"lg\" />\n </Stack>\n ),\n}\n"},{"name":"AvatarGroup","category":"Content","description":"Overlapping avatars, e.g. a document's collaborators. Give it an\n`aria-label` such as \"Shared with\".\n\n```tsx\n<AvatarGroup max={3}>\n {team.map((p) => <Avatar key={p.id} name={p.name} src={p.photo} />)}\n</AvatarGroup>\n```","file":"packages/react/src/components/Avatar/AvatarGroup.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The Avatars, overlapping in order."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"max","type":"number","required":false,"description":"Show at most this many, then a \"+N\" count for the rest. A count of one\nwould take the place an avatar could have, so with only one left over\nevery avatar shows instead."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Size of every avatar in the group, overriding their own."}],"styles":{"className":"greese-AvatarGroup","parts":["item"],"modifiers":["lg","md","sm","xl","xs"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, AvatarGroup } from '@greese/react'\n\nconst meta = {\n title: 'Content/AvatarGroup',\n component: AvatarGroup,\n args: {\n 'aria-label': 'Shared with',\n max: 3,\n children: [\n 'Ada Lovelace',\n 'Grace Hopper',\n 'Alan Turing',\n 'Katherine Johnson',\n 'Edsger Dijkstra',\n ].map((name) => <Avatar key={name} name={name} />),\n },\n} satisfies Meta<typeof AvatarGroup>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Overlapping avatars with a \"+N\" count beyond `max`. */\nexport const Playground: Story = {}\n\nexport const Large: Story = { args: { size: 'lg', max: 4 } }\n"},{"name":"Badge","category":"Content","description":"A short status label: \"New\", \"Beta\", \"3\". Not interactive; for removable or\nselectable labels use Chip.\n\n```tsx\n<Badge tone=\"positive\">Paid</Badge>\n```","file":"packages/react/src/components/Badge/Badge.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"tone","type":"BadgeTone","required":false,"default":"neutral","description":"The color and meaning: neutral, accent, a brand color (primary,\nsecondary, tertiary), positive, negative, warning or info."},{"name":"variant","type":"\"soft\" | \"outline\" | \"solid\"","required":false,"default":"soft","description":"`soft` (a light tint), `solid` (filled) or `outline` (border only)."}],"styles":{"className":"greese-Badge","parts":[],"modifiers":["accent","info","negative","neutral","outline","positive","primary","secondary","soft","solid","tertiary","warning"],"attributes":[],"variables":["--greese-badge-surface","--greese-badge-tone","--greese-badge-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Badge, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/Badge',\n component: Badge,\n args: { children: 'New', tone: 'primary' },\n argTypes: {\n tone: {\n control: 'select',\n options: [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ],\n },\n variant: { control: 'inline-radio', options: ['soft', 'solid', 'outline'] },\n },\n} satisfies Meta<typeof Badge>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const All: Story = {\n render: () => (\n <Stack gap={3}>\n {(['soft', 'solid', 'outline'] as const).map((variant) => (\n <Stack key={variant} direction=\"row\" gap={2} wrap=\"wrap\">\n {(\n [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ] as const\n ).map((tone) => (\n <Badge key={tone} tone={tone} variant={variant}>\n {tone}\n </Badge>\n ))}\n </Stack>\n ))}\n </Stack>\n ),\n}\n"},{"name":"Box","category":"Layout","description":"The base layout primitive: a `<div>` with typed, responsive style props.\n\n```tsx\n<Box p={{ xs: 4, md: 6 }} maxW=\"40rem\" mx=\"auto\" />\n```\n\nStyle props resolve to classes and inline custom properties read by static\nCSS; nothing is generated at runtime. Server-component safe.","file":"packages/react/src/components/Box/Box.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Box","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Box } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Box',\n component: Box,\n args: {\n p: { xs: 3, md: 6 },\n maxW: '32rem',\n mx: 'auto',\n textAlign: { xs: 'start', md: 'center' },\n style: {\n background: 'var(--greese-color-surface)',\n borderRadius: 'var(--greese-radius-lg)',\n },\n children: 'Padding grows at md; text centres at md.',\n },\n} satisfies Meta<typeof Box>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Typed, responsive style props. Spacing takes tokens (0-8) or any length. */\nexport const Playground: Story = {}\n\n/** `display` per breakpoint: hidden on phones, a flex row from md. */\nexport const ResponsiveDisplay: Story = {\n args: {\n display: { xs: 'none', md: 'flex' },\n gap: 3,\n children: 'Visible from md, as a flex row.',\n },\n}\n\n/** `asChild` puts Box's styling on your own element. */\nexport const AsChild: Story = {\n render: () => (\n <Box asChild p={4} style={{ border: '1px dashed var(--greese-color-border-strong)' }}>\n <section aria-label=\"Example\">A real <section> with Box padding.</section>\n </Box>\n ),\n}\n"},{"name":"BreadcrumbItem","category":"Navigation","description":"One step in Breadcrumbs.\n\n```tsx\n<BreadcrumbItem href=\"/docs\">Docs</BreadcrumbItem>\n```","file":"packages/react/src/components/Breadcrumbs/BreadcrumbItem.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your router's link."},{"name":"current","type":"boolean","required":false,"description":"The current page: rendered as text with `aria-current=\"page\"`. Implied when there is no `href`."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-BreadcrumbItem","parts":["current","link"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { BreadcrumbItem, Breadcrumbs } from '@greese/react'\n\n/** One link in a Breadcrumbs trail; without `href`, the current page. */\nconst meta = {\n title: 'Navigation/BreadcrumbItem',\n component: BreadcrumbItem,\n args: { href: '#', children: 'Projects' },\n decorators: [\n (Story) => (\n <Breadcrumbs>\n <BreadcrumbItem href=\"#\">Home</BreadcrumbItem>\n <Story />\n <BreadcrumbItem>Settings</BreadcrumbItem>\n </Breadcrumbs>\n ),\n ],\n} satisfies Meta<typeof BreadcrumbItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The middle item. */\nexport const Playground: Story = {}\n"},{"name":"Breadcrumbs","category":"Navigation","description":"Where the current page sits in the hierarchy: a labelled `<nav>` with an\nordered list. Separators are CSS and silent to screen readers.\n\n```tsx\n<Breadcrumbs>\n <BreadcrumbItem href=\"/\">Home</BreadcrumbItem>\n <BreadcrumbItem href=\"/docs\">Docs</BreadcrumbItem>\n <BreadcrumbItem>Install</BreadcrumbItem>\n</Breadcrumbs>\n```","file":"packages/react/src/components/Breadcrumbs/Breadcrumbs.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"BreadcrumbItems, from the top level to the current page."},{"name":"expandLabel","type":"string","required":false,"default":"Show full path","description":"Name of the expand button."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"Breadcrumb","description":"Names the navigation landmark for screen readers."},{"name":"maxItems","type":"number","required":false,"description":"Collapse the middle into \"…\" beyond this many items; the button expands them."}],"styles":{"className":"greese-Breadcrumbs","parts":["expand","list"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { BreadcrumbItem, Breadcrumbs } from '@greese/react'\n\nconst meta = {\n title: 'Navigation/Breadcrumbs',\n component: Breadcrumbs,\n subcomponents: { BreadcrumbItem },\n args: {\n children: [\n <BreadcrumbItem key=\"home\" href=\"#\">\n Home\n </BreadcrumbItem>,\n <BreadcrumbItem key=\"projects\" href=\"#\">\n Projects\n </BreadcrumbItem>,\n <BreadcrumbItem key=\"greese\" href=\"#\">\n Greese UI\n </BreadcrumbItem>,\n <BreadcrumbItem key=\"settings\">Settings</BreadcrumbItem>,\n ],\n },\n} satisfies Meta<typeof Breadcrumbs>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The last item is the current page (`aria-current=\"page\"`). */\nexport const Playground: Story = {}\n\n/** `maxItems` collapses the middle behind an expand button. */\nexport const Collapsed: Story = { args: { maxItems: 3 } }\n"},{"name":"Break","category":"Content","description":"A line break that only applies within a viewport range, for headings and\nshort copy that should set differently on phones and desktops. CSS alone, so\nserver-component safe and free of layout shift.\n\n```tsx\n<Heading>\n Ship faster,<Break above=\"md\" />on every screen\n</Heading>\n```\n\nBoth the `<br>` and the fallback are always in the DOM; the one that doesn't\napply is `display: none`, so screen readers announce the text once.","file":"packages/react/src/components/Break/Break.tsx","props":[{"name":"above","type":"BreakpointBoundary","required":false,"description":"Break the line from this breakpoint upward (inclusive)."},{"name":"below","type":"BreakpointBoundary","required":false,"description":"Break the line below this breakpoint (exclusive)."},{"name":"fallback","type":"ReactNode","required":false,"default":"","description":"What renders between the siblings where the line doesn't break.\n\n- A non-breaking space (the default) separates the words and keeps them\n together: `Fast,<Break above=\"md\" />everywhere` never wraps between them.\n- `' '` separates them and lets the line wrap there as usual.\n- `null` joins the siblings with nothing in between.\n- Any text or element: a separator such as `' · '` or an icon."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Break, Heading, Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Break',\n component: Break,\n args: { above: 'md' },\n argTypes: {\n above: { control: 'select', options: [undefined, 'sm', 'md', 'lg', 'xl'] },\n below: { control: 'select', options: [undefined, 'sm', 'md', 'lg', 'xl'] },\n fallback: { control: 'text' },\n },\n render: (args) => (\n <Heading level={1}>\n Ship faster,\n <Break {...args} />\n on every screen\n </Heading>\n ),\n} satisfies Meta<typeof Break>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * Breaks from md up. Below it, a non-breaking space joins the lines and keeps\n * \"faster, on\" together. Resize the viewport to see both.\n */\nexport const Playground: Story = {}\n\n/** The opposite: a two-line heading on phones, one line from md. */\nexport const BelowBreakpoint: Story = { args: { above: undefined, below: 'md' } }\n\n/** What renders instead of the break: a separator, a plain space or nothing. */\nexport const Fallbacks: Story = {\n render: () => (\n <Stack gap={4}>\n <Text variant=\"s2\">\n Design\n <Break below=\"md\" fallback=\" · \" />\n Build\n <Break below=\"md\" fallback=\" · \" />\n Ship\n </Text>\n <Text variant=\"s2\">\n A plain space lets this line wrap where it likes,\n <Break above=\"lg\" fallback=\" \" />\n and breaks it from lg.\n </Text>\n <Text variant=\"s2\">\n Joined\n <Break above=\"md\" fallback={null} />\n Together (no space below md)\n </Text>\n </Stack>\n ),\n}\n"},{"name":"Button","category":"Forms","description":"A button. `type` defaults to `\"button\"`, so it never submits a form by\naccident; pass `type=\"submit\"` when it should. Server-component safe: it\nblocks a loading or disabled press without script of its own, so it adds a\nhandler only around an `onClick` you pass (which only a client component can).\n\n```tsx\n<Button startIcon={<PlusIcon />}>Add item</Button>\n<Button variant=\"outline\" tone=\"negative\" loading={deleting}>Delete</Button>\n<Button href=\"/docs\" variant=\"ghost\">Docs</Button>\n```","file":"packages/react/src/components/Button/Button.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element, e.g. a router `<Link>`, as the button.\nAn `href` renders the link itself; use `asChild` without one for your own."},{"name":"endIcon","type":"ReactNode","required":false,"description":"Decorative icon after the label."},{"name":"fullWidth","type":"Responsive<boolean>","required":false,"description":"Fill the container's width, e.g. `{ xs: true, md: false }` on phones only."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"href","type":"string","required":false,"description":"A button that goes somewhere takes `href` instead of `onClick`.\nWhere it goes: renders an `<a>` instead of a `<button>`."},{"name":"loading","type":"boolean","required":false,"description":"Shows a spinner and ignores clicks, but stays focusable (`aria-disabled`,\nnot `disabled`) so keyboard focus is not lost mid-action. A submit button\ndoesn't submit while it's loading."},{"name":"onClick","type":"MouseEventHandler<HTMLButtonElement>","required":false,"description":"Called when it's pressed; never while it's loading or disabled.\nA link goes to its `href`; it takes no `onClick`."},{"name":"ref","type":"((instance: HTMLButtonElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<HTMLButtonElement | null> | ((instance: HTMLAnchorElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<...> | null","required":false,"description":"The rendered `<button>` (or your element, with `asChild`).\nThe rendered `<a>`."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height, padding and text size: `xs`, `sm`, `md`, `lg` or `xl`. Touch targets stay at\nleast 44px."},{"name":"startIcon","type":"ReactNode","required":false,"description":"Decorative icon before the label."},{"name":"tone","type":"ButtonTone","required":false,"default":"primary","description":"Color role: `accent`, a brand color (primary, secondary, tertiary),\n`neutral`, or `negative` for destructive actions."},{"name":"variant","type":"ButtonVariant","required":false,"default":"solid","description":"Visual weight: `solid` for the main action, `soft`, `outline`, then `ghost`\nfor the least. `text` drops the box and takes the surrounding text's color,\nso the button reads as plain text."}],"styles":{"className":"greese-Button","parts":["icon"],"modifiers":["accent","ghost","negative","neutral","outline","primary","secondary","size-lg","size-md","size-sm","size-xl","size-xs","soft","solid","tertiary","text"],"attributes":["[aria-disabled=true]","[aria-pressed=true]","[data-loading]"],"variables":["--greese-button-bg","--greese-button-bg-active","--greese-button-bg-hover","--greese-button-border","--greese-button-fg","--greese-button-height","--greese-button-on-tone","--greese-button-padding","--greese-button-tone","--greese-type-button-font-family","--greese-type-button-font-style","--greese-type-button-text-transform"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, IconButton, Stack } from '@greese/react'\nimport { ArrowRightIcon, PlusIcon, TrashIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/Button',\n component: Button,\n args: { children: 'Save changes' },\n argTypes: {\n variant: {\n control: 'inline-radio',\n options: ['solid', 'soft', 'outline', 'ghost', 'text'],\n },\n tone: {\n control: 'inline-radio',\n options: ['primary', 'secondary', 'tertiary', 'accent', 'neutral', 'negative'],\n },\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },\n },\n} satisfies Meta<typeof Button>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const VariantsAndTones: Story = {\n render: () => (\n <Stack gap={3}>\n {(\n ['primary', 'secondary', 'tertiary', 'accent', 'neutral', 'negative'] as const\n ).map((tone) => (\n <Stack key={tone} direction=\"row\" gap={2} wrap=\"wrap\">\n {(['solid', 'soft', 'outline', 'ghost', 'text'] as const).map((variant) => (\n <Button key={variant} tone={tone} variant={variant}>\n {variant} {tone}\n </Button>\n ))}\n </Stack>\n ))}\n </Stack>\n ),\n}\n\nexport const IconsSizesAndStates: Story = {\n render: () => (\n <Stack gap={3}>\n <Stack direction=\"row\" gap={2} align=\"center\" wrap=\"wrap\">\n <Button size=\"sm\" startIcon={<PlusIcon />}>\n Small\n </Button>\n <Button startIcon={<PlusIcon />}>Medium</Button>\n <Button size=\"lg\" endIcon={<ArrowRightIcon />}>\n Large\n </Button>\n <IconButton label=\"Delete\" tone=\"negative\">\n <TrashIcon />\n </IconButton>\n </Stack>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n <Button loading>Saving</Button>\n <Button disabled>Disabled</Button>\n <Button asChild variant=\"outline\" endIcon={<ArrowRightIcon />}>\n <a href=\"#docs\">A link styled as a button</a>\n </Button>\n </Stack>\n </Stack>\n ),\n}\n\n/** Full width on phones, natural width from md. */\nexport const ResponsiveFullWidth: Story = {\n args: { fullWidth: { xs: true, md: false } },\n}\n"},{"name":"ButtonGroup","category":"Forms","description":"Groups related buttons (`role=\"group\"`). Give it an `aria-label` when the\ngrouping itself needs a name, e.g. \"Text formatting\".\n\n```tsx\n<ButtonGroup attached aria-label=\"Text formatting\">\n <ToggleButton>Bold</ToggleButton>\n <ToggleButton>Italic</ToggleButton>\n</ButtonGroup>\n```","file":"packages/react/src/components/ButtonGroup/ButtonGroup.tsx","props":[{"name":"attached","type":"boolean","required":false,"description":"Join the buttons into one segmented control."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"orientation","type":"\"horizontal\" | \"vertical\"","required":false,"default":"horizontal","description":"Lay the buttons out in a row (`horizontal`) or a column (`vertical`)."}],"styles":{"className":"greese-ButtonGroup","parts":[],"modifiers":["attached"],"attributes":["[data-orientation=horizontal]","[data-orientation=vertical]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, ButtonGroup } from '@greese/react'\n\nconst meta = {\n title: 'Forms/ButtonGroup',\n component: ButtonGroup,\n args: {\n 'aria-label': 'Actions',\n children: (\n <>\n <Button variant=\"outline\" tone=\"neutral\">\n Cancel\n </Button>\n <Button>Confirm</Button>\n </>\n ),\n },\n} satisfies Meta<typeof ButtonGroup>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** `attached` joins the buttons into one segmented control. */\nexport const Attached: Story = {\n args: {\n attached: true,\n children: (\n <>\n <Button variant=\"outline\" tone=\"neutral\">\n Day\n </Button>\n <Button variant=\"outline\" tone=\"neutral\">\n Week\n </Button>\n <Button variant=\"outline\" tone=\"neutral\">\n Month\n </Button>\n </>\n ),\n },\n}\n\nexport const Vertical: Story = { args: { orientation: 'vertical', attached: true } }\n"},{"name":"Card","category":"Content","description":"A surface that groups related content. Lay out its contents with Stack.\n\n```tsx\n<Card>\n <CardMedia><img src={cover} alt=\"\" /></CardMedia>\n <Stack gap={2}><Heading level={3}>Title</Heading><Text>…</Text></Stack>\n</Card>\n```","file":"packages/react/src/components/Card/Card.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"interactive","type":"boolean","required":false,"description":"Hover and press feedback, for cards that are one big link or button. Put\nthe link on the card with `asChild`."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"padding","type":"Responsive<SpaceValue>","required":false,"description":"Inner spacing; CardMedia bleeds through it. Default: 4, or 5 from `md`."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"variant","type":"\"outline\" | \"elevated\" | \"filled\"","required":false,"default":"outline","description":"`outline` (a border), `elevated` (a shadow) or `filled` (a surface color,\nno border)."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Card","parts":[],"modifiers":["elevated","filled","interactive","outline"],"attributes":[],"variables":["--greese-card-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Badge, Card, CardMedia, Grid, Heading, Image, Stack, Text } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Content/Card',\n component: Card,\n subcomponents: { CardMedia },\n args: { variant: 'outline' },\n argTypes: {\n variant: { control: 'inline-radio', options: ['outline', 'elevated', 'filled'] },\n },\n render: (args) => (\n <Card {...args} style={{ maxInlineSize: '20rem' }}>\n <CardMedia>\n <Image alt=\"\" src={art(200)} ratio={16 / 9} placeholder=\"#ccd\" />\n </CardMedia>\n <Stack gap={2}>\n <Heading level={3} variant=\"h5\">\n Card title\n </Heading>\n <Text tone=\"muted\" variant=\"p3\">\n CardMedia bleeds through the padding, which steps up at md.\n </Text>\n </Stack>\n </Card>\n ),\n} satisfies Meta<typeof Card>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Variants: Story = {\n render: () => (\n <Grid container minChildWidth=\"14rem\" gap={4}>\n {(['outline', 'elevated', 'filled'] as const).map((variant, i) => (\n <Card key={variant} variant={variant} interactive={i === 1}>\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Heading level={3} variant=\"h6\">\n {variant}\n </Heading>\n {i === 1 && <Badge tone=\"primary\">Interactive</Badge>}\n </Stack>\n <Text tone=\"muted\" variant=\"p3\">\n A surface for related content.\n </Text>\n </Card>\n ))}\n </Grid>\n ),\n}\n\n/** A whole-card link: put the anchor on the card with `asChild`. */\nexport const AsLink: Story = {\n render: () => (\n <Card asChild interactive style={{ maxInlineSize: '20rem' }}>\n <a href=\"#project\">\n <Heading level={3} variant=\"h6\">\n Open project\n </Heading>\n <Text tone=\"muted\" variant=\"p3\">\n The whole card is the link.\n </Text>\n </a>\n </Card>\n ),\n}\n"},{"name":"CardMedia","category":"Content","description":"Media that runs edge to edge in a Card, ignoring its padding. As the first\nchild it also takes the card's top corners.","file":"packages/react/src/components/Card/Card.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-CardMedia","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Card, CardMedia, Heading, Image, Stack, Text } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\n/** Media that bleeds through a Card's padding to its edges. */\nconst meta = {\n title: 'Content/CardMedia',\n component: CardMedia,\n args: {\n children: <Image alt=\"\" src={art(200)} ratio={16 / 9} placeholder=\"#ccd\" />,\n },\n decorators: [\n (Story) => (\n <Card style={{ maxInlineSize: '20rem' }}>\n <Story />\n <Stack gap={2}>\n <Heading level={3} variant=\"h5\">\n Card title\n </Heading>\n <Text tone=\"muted\" variant=\"p3\">\n The media above reaches the card's edges.\n </Text>\n </Stack>\n </Card>\n ),\n ],\n} satisfies Meta<typeof CardMedia>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Carousel","category":"Content","description":"Slides in a row that scroll with a swipe, the trackpad or the keyboard, on\nnative CSS scroll snapping. JavaScript only adds the buttons and dots and\ntracks which slide is in view. It never moves on its own.\n\n```tsx\n<Carousel label=\"Featured\" perView={{ xs: 1.15, md: 3 }}>\n <CarouselSlide><Card>…</Card></CarouselSlide>\n <CarouselSlide><Card>…</Card></CarouselSlide>\n</Carousel>\n```","file":"packages/react/src/components/Carousel/Carousel.tsx","props":[{"name":"label","type":"string","required":true,"description":"Names the carousel (\"Featured products\")."},{"name":"controls","type":"boolean","required":false,"default":"true","description":"Previous and next buttons."},{"name":"defaultIndex","type":"number","required":false,"default":"0","description":"The slide shown first, from 0, when the carousel keeps its own state."},{"name":"gap","type":"SpaceValue","required":false,"default":"3","description":"Space between slides: a scale token (`0`–`8`) or any CSS length."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"index","type":"number","required":false,"description":"The slide at the start of the view, from 0."},{"name":"indicators","type":"boolean","required":false,"default":"true","description":"A dot per slide, to jump to it."},{"name":"loop","type":"boolean","required":false,"default":"false","description":"Next on the last slide goes back to the first, and the reverse."},{"name":"nextLabel","type":"string","required":false,"default":"Next slide","description":"Accessible name of the next button."},{"name":"onIndexChange","type":"((index: number) => void)","required":false,"description":"Called with the leading slide's index whenever it changes: by scrolling, the\nbuttons or the dots."},{"name":"perView","type":"Responsive<number>","required":false,"default":"1","description":"Slides in view at once. A fraction (`1.2`) lets the next one peek in."},{"name":"previousLabel","type":"string","required":false,"default":"Previous slide","description":"Accessible name of the previous button."}],"styles":{"className":"greese-Carousel","parts":["control","indicator","indicators","viewport"],"modifiers":[],"attributes":["[aria-current=true]"],"variables":["--greese-carousel-dots","--greese-carousel-gap","--greese-carousel-gaps","--greese-carousel-per-view"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Card, Carousel, CarouselSlide, Heading, Image, Stack, Text } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst places = ['Harbour', 'Ridge', 'Meadow', 'Coast', 'Forest', 'Valley']\n\nconst slides = places.map((place, i) => (\n <CarouselSlide key={place}>\n <Card padding={0} style={{ overflow: 'hidden' }}>\n <Image alt=\"\" src={art(40 + i * 50)} ratio={16 / 9} placeholder=\"#ccd\" />\n <Stack gap={1} p={4}>\n <Heading level={3} variant=\"h6\">\n {place}\n </Heading>\n <Text variant=\"p3\" tone=\"muted\">\n Slide {i + 1} of {places.length}\n </Text>\n </Stack>\n </Card>\n </CarouselSlide>\n))\n\nconst meta = {\n title: 'Content/Carousel',\n component: Carousel,\n subcomponents: { CarouselSlide },\n args: { label: 'Places', children: slides },\n} satisfies Meta<typeof Carousel>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Swipe, scroll or use the buttons (where a pointer can hover) and dots. */\nexport const Playground: Story = {}\n\n/** One and a bit on phones, so the next slide peeks in; three from md. */\nexport const SeveralInView: Story = {\n args: { perView: { xs: 1.15, md: 3 }, gap: 4 },\n}\n\n/** Next on the last slide wraps to the first. */\nexport const Looping: Story = { args: { loop: true, indicators: false } }\n"},{"name":"CarouselSlide","category":"Content","description":"One slide of a Carousel.","file":"packages/react/src/components/Carousel/Carousel.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"'<n> of <count>'","description":"How the slide is announced."}],"styles":{"className":"greese-CarouselSlide","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Carousel, CarouselSlide, Tile } from '@greese/react'\n\n/** One slide: a group announced as \"n of count\", or by its own `label`. */\nconst meta = {\n title: 'Content/CarouselSlide',\n component: CarouselSlide,\n args: { children: <Tile>This slide</Tile> },\n decorators: [\n (Story) => (\n <Carousel label=\"Example\" perView={2}>\n <Story />\n <CarouselSlide>\n <Tile>Another slide</Tile>\n </CarouselSlide>\n <CarouselSlide>\n <Tile>A third</Tile>\n </CarouselSlide>\n </Carousel>\n ),\n ],\n} satisfies Meta<typeof CarouselSlide>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const CustomLabel: Story = { args: { label: 'Introduction' } }\n"},{"name":"Center","category":"Layout","description":"Centres its children on both axes. Accepts every Box style prop and `asChild`.\n\n```tsx\n<Center style={{ minBlockSize: '20rem' }}>\n <Spinner label=\"Loading\" />\n</Center>\n```","file":"packages/react/src/components/Center/Center.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"inline","type":"boolean","required":false,"description":"Shrink to fit content (`inline-flex`) instead of filling the line."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Center","parts":[],"modifiers":["inline"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Center, Tile } from '@greese/react'\nimport { StarIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Layout/Center',\n component: Center,\n args: {\n style: { minBlockSize: '12rem', background: 'var(--greese-color-surface)' },\n children: <Tile>Centred on both axes</Tile>,\n },\n} satisfies Meta<typeof Center>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** `inline` shrinks to its content: handy for icon badges. */\nexport const Inline: Story = {\n args: {\n inline: true,\n style: {\n inlineSize: '2.5rem',\n blockSize: '2.5rem',\n borderRadius: '50%',\n background: 'var(--greese-color-primary)',\n color: 'var(--greese-color-primary-content)',\n },\n children: <StarIcon size=\"1.25rem\" />,\n },\n}\n"},{"name":"ChatBubble","category":"Content","description":"One message in a conversation, with its author, time and status. Put the\nmessages in an element with `role=\"log\"` so new ones are announced.\n\n```tsx\n<Stack role=\"log\" aria-label=\"Messages\" gap={3}>\n <ChatBubble author=\"Ada\" time=\"09:12\" avatar={<Avatar name=\"Ada\" size=\"sm\" />}>Ready?</ChatBubble>\n <ChatBubble side=\"end\" footer=\"Seen\">On my way.</ChatBubble>\n</Stack>\n```","file":"packages/react/src/components/ChatBubble/ChatBubble.tsx","props":[{"name":"author","type":"ReactNode","required":false,"description":"Who wrote it, above the bubble."},{"name":"avatar","type":"ReactNode","required":false,"description":"Beside the bubble, usually an Avatar."},{"name":"footer","type":"ReactNode","required":false,"description":"Below the bubble: \"Delivered\", \"Seen\"."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"side","type":"\"start\" | \"end\"","required":false,"default":"start","description":"Which side it sits on: `end` for the reader's own messages."},{"name":"time","type":"ReactNode","required":false,"description":"When, beside the author."},{"name":"tone","type":"\"info\" | \"positive\" | \"warning\" | \"negative\" | \"neutral\" | BrandTone","required":false,"description":"The bubble's color: neutral, accent, a brand color (primary, secondary,\ntertiary), positive, negative, warning or info. Defaults to `neutral` on\nthe start side and `accent` on the end side."}],"styles":{"className":"greese-ChatBubble","parts":["author","avatar","bubble","footer","header","time"],"modifiers":["accent","end","info","muted","negative","neutral","positive","primary","secondary","tertiary","warning"],"attributes":[],"variables":["--greese-chat-tail","--greese-chat-tone","--greese-chat-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, ChatBubble, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/ChatBubble',\n component: ChatBubble,\n args: {\n author: 'Ada Lovelace',\n time: '09:12',\n avatar: <Avatar name=\"Ada Lovelace\" size=\"sm\" />,\n children: 'Did the build pass?',\n },\n argTypes: {\n side: { control: 'inline-radio', options: ['start', 'end'] },\n tone: {\n control: 'select',\n options: [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ],\n },\n },\n} satisfies Meta<typeof ChatBubble>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** A conversation in a `role=\"log\"`, so new messages are announced. */\nexport const Conversation: Story = {\n render: () => (\n <Stack role=\"log\" aria-label=\"Messages\" gap={3} style={{ maxInlineSize: '32rem' }}>\n <ChatBubble\n author=\"Ada\"\n time=\"09:12\"\n avatar={<Avatar name=\"Ada Lovelace\" size=\"sm\" />}\n >\n Did the build pass?\n </ChatBubble>\n <ChatBubble side=\"end\" time=\"09:13\" footer=\"Seen\">\n All green. Shipping it now.\n </ChatBubble>\n <ChatBubble\n author=\"Ada\"\n time=\"09:14\"\n avatar={<Avatar name=\"Ada Lovelace\" size=\"sm\" />}\n >\n Lovely, thank you!\n </ChatBubble>\n <ChatBubble side=\"end\" tone=\"negative\" footer=\"Failed to send\">\n One more thing…\n </ChatBubble>\n </Stack>\n ),\n}\n"},{"name":"Checkbox","category":"Forms","description":"A native checkbox, styled. Works uncontrolled (`defaultChecked`), controlled\n(`checked` + `onChange`/`onCheckedChange`), in native forms and in\nCheckboxGroup (pass `value`).","file":"packages/react/src/components/Checkbox/Checkbox.tsx","props":[{"name":"description","type":"ReactNode","required":false,"description":"Secondary text under the label, announced with the checkbox."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"indeterminate","type":"boolean","required":false,"description":"The \"some selected\" state, e.g. for a select-all checkbox."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid (`aria-invalid`) and colors it as an error. A surrounding\ngroup's `error` sets it too."},{"name":"label","type":"ReactNode","required":false,"description":"Text beside the box. Without it, give the checkbox an `aria-label`."},{"name":"onCheckedChange","type":"((checked: boolean) => void)","required":false,"description":"Convenience alongside `onChange`: receives the new checked state."}],"styles":{"className":"greese-Checkbox","parts":["box","description","icon","input","label","text"],"modifiers":[],"attributes":["[aria-invalid=true]","[data-disabled]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Checkbox, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Checkbox',\n component: Checkbox,\n args: { label: 'I accept the terms', description: 'You can withdraw at any time.' },\n} satisfies Meta<typeof Checkbox>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const States: Story = {\n render: () => (\n <Stack gap={3}>\n <Checkbox label=\"Checked\" defaultChecked />\n <Checkbox label=\"Select all (some selected)\" indeterminate />\n <Checkbox label=\"Invalid\" invalid />\n <Checkbox label=\"Disabled\" disabled />\n </Stack>\n ),\n}\n"},{"name":"CheckboxGroup","category":"Forms","description":"A labelled set of checkboxes (`<fieldset>` + `<legend>`) that tracks which\nvalues are checked.\n\n```tsx\n<CheckboxGroup label=\"Notify me by\" defaultValue={['email']} name=\"notify\">\n <Checkbox value=\"email\" label=\"Email\" />\n <Checkbox value=\"sms\" label=\"SMS\" />\n</CheckboxGroup>\n```","file":"packages/react/src/components/Checkbox/Checkbox.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The group's name, rendered as the `<legend>`."},{"name":"defaultValue","type":"string[]","required":false,"default":"[]","description":"The values checked at first, when the group keeps its own state."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the group."},{"name":"direction","type":"Responsive<StackDirection>","required":false,"default":"'column'","description":"Layout of the choices."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks every choice invalid."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"default":"3","description":"Space between the choices: a scale token (`0`–`8`) or any CSS length, per\nbreakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Marks every choice invalid without showing an error message."},{"name":"name","type":"string","required":false,"description":"Shared `name` for native form submission."},{"name":"onValueChange","type":"((value: string[]) => void)","required":false,"description":"Called with every checked value whenever one is checked or unchecked."},{"name":"required","type":"boolean","required":false,"description":"Shows the required marker."},{"name":"value","type":"string[]","required":false,"description":"Checked values (each Checkbox's `value`)."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Checkbox, CheckboxGroup } from '@greese/react'\n\nconst meta = {\n title: 'Forms/CheckboxGroup',\n component: CheckboxGroup,\n args: {\n label: 'Notify me by',\n name: 'notify',\n defaultValue: ['email'],\n direction: { xs: 'column', md: 'row' },\n children: (\n <>\n <Checkbox value=\"email\" label=\"Email\" />\n <Checkbox value=\"sms\" label=\"SMS\" />\n <Checkbox value=\"push\" label=\"Push notification\" />\n </>\n ),\n },\n} satisfies Meta<typeof CheckboxGroup>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** A labelled set that tracks checked values; stacks on phones. */\nexport const Playground: Story = {}\n\nexport const WithError: Story = {\n args: { error: 'Choose at least one channel.', defaultValue: [] },\n}\n"},{"name":"Chip","category":"Content","description":"A compact label that can be removed or toggled: filters, tags, recipients.\n\n```tsx\n<Chip onRemove={() => drop(tag)}>{tag}</Chip>\n<Chip selectable defaultSelected>In stock</Chip>\n<Chip tone=\"secondary\">Featured</Chip>\n```","file":"packages/react/src/components/Chip/Chip.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The chip's text."},{"name":"defaultSelected","type":"boolean","required":false,"default":"false","description":"Whether a `selectable` chip starts on, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"description":"Leading icon or avatar."},{"name":"onRemove","type":"(() => void)","required":false,"description":"Adds a remove button (e.g. a filter or a recipient)."},{"name":"onSelectedChange","type":"((selected: boolean) => void)","required":false,"description":"Called with the new state when a `selectable` chip is toggled."},{"name":"removeLabel","type":"string","required":false,"default":"`Remove ${children}`","description":"Accessible name for the remove button."},{"name":"selectable","type":"boolean","required":false,"description":"Makes the chip a toggle (`aria-pressed`), e.g. a filter choice."},{"name":"selected","type":"boolean","required":false,"description":"Whether a `selectable` chip is on, when you control it. Pair with\n`onSelectedChange`."},{"name":"tone","type":"ChipTone","required":false,"description":"The chip's color: neutral, accent, a brand color (primary, secondary,\ntertiary), positive, negative, warning or info. A plain chip is tinted\nin it; a `selectable` one shows it when selected. Without it, chips are\nplain and selected ones use `accent`."}],"styles":{"className":"greese-Chip","parts":["icon","remove","toggle"],"modifiers":["accent","info","negative","neutral","positive","primary","secondary","selected","tertiary","warning"],"attributes":[],"variables":["--greese-chip-tone","--greese-chip-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\nimport { Chip, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/Chip',\n component: Chip,\n args: { children: 'Design', onRemove: () => {} },\n} satisfies Meta<typeof Chip>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Removable: the remove button is named \"Remove Design\". */\nexport const Playground: Story = {}\n\nexport const Selectable: Story = {\n args: {\n selectable: true,\n defaultSelected: true,\n onRemove: undefined,\n children: 'In stock',\n },\n}\n\n/**\n * `tone` tints a plain chip, and colors a selectable one when it's selected.\n * Without a tone, chips are plain and select to primary.\n */\nexport const Tones: Story = {\n render: () => (\n <Stack gap={3}>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n {(\n [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ] as const\n ).map((tone) => (\n <Chip key={tone} tone={tone}>\n {tone}\n </Chip>\n ))}\n </Stack>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n <Chip selectable defaultSelected tone=\"secondary\">\n Selected secondary\n </Chip>\n <Chip selectable tone=\"secondary\">\n Not selected\n </Chip>\n </Stack>\n </Stack>\n ),\n}\n\nexport const Filters: Story = {\n render: function Render() {\n const [tags, setTags] = useState(['Design', 'Frontend', 'Accessibility'])\n return (\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n {tags.map((tag) => (\n <Chip key={tag} onRemove={() => setTags((t) => t.filter((x) => x !== tag))}>\n {tag}\n </Chip>\n ))}\n <Chip selectable>On sale</Chip>\n </Stack>\n )\n },\n}\n"},{"name":"Code","category":"Content","description":"Inline code, or a code block with `block`. Bring your own syntax highlighting.\n\n```tsx\nRun <Code>npm install","file":"packages/react/src/components/Code/Code.tsx","props":[{"name":"block","type":"boolean","required":false,"description":"A scrollable code block (`<pre><code>`) instead of inline code. Blocks are\nkeyboard-focusable so they can be scrolled without a mouse."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-Code","parts":[],"modifiers":["block"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Code, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Code',\n component: Code,\n args: { children: 'npm install @greese/react' },\n} satisfies Meta<typeof Code>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {\n render: (args) => (\n <Text>\n Run <Code {...args} /> to get started.\n </Text>\n ),\n}\n\n/** A keyboard-scrollable block. Bring your own syntax highlighting. */\nexport const Block: Story = {\n args: {\n block: true,\n children: `import { Stack } from '@greese/react'\\n\\nexport const App = () => <Stack gap={4}>…</Stack>`,\n },\n}\n"},{"name":"Collapsible","category":"Content","description":"Show/hide content behind a summary, on native `<details>`/`<summary>`:\nkeyboard, screen readers and find-in-page work without JavaScript, and the\ncontent animates open where the browser supports it. The icon is yours to\nchange: one that turns, or one per state that crossfades.\n\n```tsx\n<Collapsible title=\"Details\" icon={<PlusIcon />} openIcon={<MinusIcon />}>…</Collapsible>\n```","file":"packages/react/src/components/Collapsible/Collapsible.tsx","props":[{"name":"title","type":"ReactNode","required":true,"description":"The always-visible summary that toggles the content."},{"name":"defaultOpen","type":"boolean","required":false,"description":"Initial state when uncontrolled."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"default":"a downward chevron","description":"The icon beside the title: the closed state's, or both states' when there\nis no `openIcon`. `null` shows none."},{"name":"iconTransition","type":"CollapsibleIconTransition","required":false,"default":"'rotate' with one icon, 'fade' with an `openIcon`","description":"How the icon changes state: `rotate` turns it (by\n`--greese-collapsible-icon-turn`, 180deg), `fade` crossfades the closed\nand open icons, `none` switches at once. Under reduced motion every one\nswitches at once."},{"name":"name","type":"string","required":false,"description":"Exclusive group name: only one `<details>` with the same name is open at\na time (native, no JS). Accordion sets it for you."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes."},{"name":"open","type":"boolean","required":false,"description":"Controlled state; pair with `onOpenChange`."},{"name":"openIcon","type":"ReactNode","required":false,"description":"The open state's icon. With one, the two icons swap as it opens and closes."}],"styles":{"className":"greese-Collapsible","parts":["chevron","closedIcon","content","icon","openIcon","trigger"],"modifiers":[],"attributes":["[open]"],"variables":["--greese-collapsible-icon-turn"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Collapsible, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Collapsible',\n component: Collapsible,\n args: {\n title: 'Show advanced options',\n style: { maxInlineSize: '36rem' },\n children: <Text>Advanced options live here.</Text>,\n },\n} satisfies Meta<typeof Collapsible>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** A single native details/summary disclosure. */\nexport const Playground: Story = {}\n\nexport const OpenByDefault: Story = { args: { defaultOpen: true } }\n"},{"name":"ColorPicker","category":"Forms","description":"Picks a color: a saturation/brightness area, a hue slider, an optional\nopacity slider, a hex field and preset swatches. Drag works with mouse, pen\nand touch; every part works from the keyboard.\n\n```tsx\n<ColorPicker defaultValue=\"#e11d48\" swatches={brand} onValueChange={setColor} />\n```\n\nFor a compact field, put it in a Popover with a swatch button as trigger.","file":"packages/react/src/components/ColorPicker/ColorPicker.tsx","props":[{"name":"alpha","type":"boolean","required":false,"default":"false","description":"Show the opacity slider; values gain an alpha pair when below 100%."},{"name":"defaultValue","type":"string","required":false,"default":"#3b82f6","description":"Hex color, uncontrolled."},{"name":"disabled","type":"boolean","required":false,"description":"Disables every part of the picker."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"Color","description":"Name for the whole picker."},{"name":"onValueChange","type":"((hex: string, color: RgbColor) => void)","required":false,"description":"Called on every change with the hex color and its channels."},{"name":"swatches","type":"readonly string[]","required":false,"description":"Preset colors offered as one-tap swatches."},{"name":"value","type":"string","required":false,"description":"Hex color (`#rrggbb`, or `#rrggbbaa` with transparency), controlled."}],"styles":{"className":"greese-ColorPicker","parts":["alpha","area","controls","hex","hue","preview","sliders","swatch","swatches","thumb"],"modifiers":[],"attributes":["[aria-pressed=true]","[data-disabled]"],"variables":["--greese-colorpicker-color","--greese-colorpicker-current","--greese-colorpicker-hue","--greese-colorpicker-swatch","--greese-colorpicker-thumb","--greese-colorpicker-track","--greese-colorpicker-x","--greese-colorpicker-y"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\nimport { Button, ColorPicker, Popover, Stack, Text } from '@greese/react'\n\nconst brand = [\n '#e11d48',\n '#f97316',\n '#eab308',\n '#22c55e',\n '#06b6d4',\n '#3b82f6',\n '#8b5cf6',\n '#111827',\n]\n\nconst meta = {\n title: 'Forms/ColorPicker',\n component: ColorPicker,\n args: { defaultValue: '#3b82f6', swatches: brand },\n} satisfies Meta<typeof ColorPicker>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Drag with mouse, pen or finger; arrows (Shift for bigger steps) on the area. */\nexport const Playground: Story = {}\n\nexport const WithOpacity: Story = { args: { alpha: true, defaultValue: '#8b5cf6b3' } }\n\n/** A compact color field: a swatch button opening the picker in a Popover. */\nexport const InPopover: Story = {\n render: function Render() {\n const [color, setColor] = useState('#e11d48')\n return (\n <Popover\n label=\"Accent color\"\n trigger={\n <Button variant=\"outline\" tone=\"neutral\">\n <span\n aria-hidden=\"true\"\n style={{\n inlineSize: '1rem',\n blockSize: '1rem',\n borderRadius: '50%',\n background: color,\n boxShadow: 'inset 0 0 0 1px rgb(0 0 0 / 15%)',\n }}\n />\n Accent: {color}\n </Button>\n }\n >\n <ColorPicker value={color} onValueChange={setColor} swatches={brand} />\n </Popover>\n )\n },\n}\n\nexport const Controlled: Story = {\n render: function Render() {\n const [color, setColor] = useState('#22c55e')\n return (\n <Stack gap={3}>\n <ColorPicker value={color} onValueChange={setColor} />\n <Text variant=\"p3\" tone=\"muted\">\n Value: <code>{color}</code>\n </Text>\n </Stack>\n )\n },\n}\n"},{"name":"Combobox","category":"Forms","description":"A text input with a filtered list of suggestions: the WAI-ARIA combobox\npattern. Type to filter; arrows move through options; Enter or Tab picks;\nEscape closes (or clears when closed). Focus stays in the input\nthroughout, and with `name` a hidden input submits the selected *value*.\n\n```tsx\n<Combobox label=\"Country\" name=\"country\" options={countries} placeholder=\"Search…\" />\n```","file":"packages/react/src/components/Combobox/Combobox.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The visible label. Required: use `hideLabel` to hide it visually."},{"name":"options","type":"readonly (string | ComboboxOption)[]","required":true,"description":"Options: objects, or plain strings used as both value and label."},{"name":"allowCustomValue","type":"boolean","required":false,"description":"Accept typed text that matches no option as the value."},{"name":"defaultValue","type":"string | null","required":false,"default":"null","description":"The option chosen at first, when the combobox keeps its own state. `null` for none."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the input."},{"name":"emptyMessage","type":"ReactNode","required":false,"default":"No results","description":"Shown when nothing matches."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks the input invalid."},{"name":"filter","type":"((option: ComboboxOption, text: string) => boolean)","required":false,"default":"(option: ComboboxOption, text: string): boolean =>\n normalize(option.label).includes(normalize(text.trim()))","description":"Which options match the typed text. Default: label contains it, ignoring case and accents."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"onInputChange","type":"((text: string) => void)","required":false,"description":"Called as the user types: load options asynchronously from here."},{"name":"onValueChange","type":"((value: string | null) => void)","required":false,"description":"Called with the chosen option's value, or `null` when cleared."},{"name":"placement","type":"Placement","required":false,"default":"bottom-start","description":"Where the list opens relative to the input. It flips if there's no room."},{"name":"resultsLabel","type":"((count: number) => string)","required":false,"default":"(n) => (n === 1 ? '1 result' : `${n} results`)","description":"Announced with the result count, e.g. `(n) => \\`${n} results\\``."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."},{"name":"toggleLabel","type":"string","required":false,"default":"Show options","description":"Accessible name of the button that opens the full list."},{"name":"value","type":"string | null","required":false,"description":"Selected option value (or custom text with `allowCustomValue`)."}],"styles":{"className":"greese-Combobox","parts":["empty","list","option","popup","toggle"],"modifiers":[],"attributes":["[aria-disabled=true]","[aria-selected=true]","[data-active]","[data-open]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Combobox } from '@greese/react'\nimport { countries } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Forms/Combobox',\n component: Combobox,\n args: {\n label: 'Country',\n name: 'country',\n options: countries,\n placeholder: 'Start typing…',\n description: 'Try “cote” or “mexico”.',\n },\n decorators: [(Story) => <div style={{ maxInlineSize: '24rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Combobox>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Type to filter (accents optional); arrows, Enter, Escape; submits the value. */\nexport const Playground: Story = {}\n\nexport const CustomValues: Story = {\n args: {\n label: 'Tag',\n options: ['bug', 'feature', 'docs'],\n allowCustomValue: true,\n description: 'Free text allowed: type a new tag.',\n placeholder: undefined,\n },\n}\n\nexport const WithDisabledOptions: Story = {\n args: {\n label: 'Plan',\n options: [\n { value: 'free', label: 'Free' },\n { value: 'pro', label: 'Pro' },\n { value: 'enterprise', label: 'Enterprise (contact sales)', disabled: true },\n ],\n description: undefined,\n placeholder: undefined,\n },\n}\n"},{"name":"Container","category":"Layout","description":"Centres content at a readable maximum width, with gutters that grow at `md`\nand respect notches and rounded corners (safe-area insets).\n\nAccepts every Box style prop (`px` overrides the gutter) and `asChild`.\n\n```tsx\n<Container size=\"lg\">…</Container>\n```","file":"packages/react/src/components/Container/Container.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"size","type":"ContainerSize","required":false,"default":"lg","description":"Maximum width, matching the breakpoint of the same name."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Container","parts":[],"modifiers":["size-full","size-lg","size-md","size-sm","size-xl"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Container, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Container',\n component: Container,\n args: {\n size: 'md',\n children: <Tile>Centred at a readable width, gutters grow at md</Tile>,\n },\n argTypes: {\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg', 'xl', 'full'] },\n },\n} satisfies Meta<typeof Container>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Sizes: Story = {\n render: () => (\n <>\n {(['sm', 'md', 'lg'] as const).map((size) => (\n <Container key={size} size={size} my={2}>\n <Tile>Container size="{size}"</Tile>\n </Container>\n ))}\n </>\n ),\n}\n"},{"name":"Countdown","category":"Content","description":"A live countdown, as a `role=\"timer\"` (not announced every second; its\nspoken form is its label). Ticks against the clock, so it doesn't drift.\n\n```tsx\n<Countdown seconds={3725} onComplete={() => setDone(true)} />\n```","file":"packages/react/src/components/Countdown/Countdown.tsx","props":[{"name":"seconds","type":"number","required":true,"description":"Seconds left. Counting restarts from here whenever it changes."},{"name":"format","type":"\"clock\" | \"labels\"","required":false,"default":"clock","description":"`clock` (01:02:05) or `labels` (1h 2m 5s)."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onComplete","type":"(() => void)","required":false,"description":"Called once when it reaches zero."},{"name":"running","type":"boolean","required":false,"default":"true","description":"Count down; `false` freezes it."},{"name":"units","type":"CountdownUnit[]","required":false,"default":"['hours', 'minutes', 'seconds']","description":"Which units to show, largest first. The largest takes whatever the others\ncan't hold."}],"styles":{"className":"greese-Countdown","parts":["label","separator","unit"],"modifiers":["clock"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Countdown, Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Countdown',\n component: Countdown,\n // Paused here so the docs and screenshots don't change; press play in Controls.\n args: { seconds: 3725, running: false },\n argTypes: {\n format: { control: 'inline-radio', options: ['clock', 'labels'] },\n },\n} satisfies Meta<typeof Countdown>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Set `running` to watch it count. */\nexport const Playground: Story = {}\n\nexport const DaysWithLabels: Story = {\n args: {\n seconds: 3 * 86400 + 4 * 3600 + 5 * 60 + 6,\n units: ['days', 'hours', 'minutes', 'seconds'],\n format: 'labels',\n },\n}\n\nexport const Large: Story = {\n render: (args) => (\n <Stack gap={1}>\n <Text variant=\"p3\" tone=\"muted\">\n Sale ends in\n </Text>\n <Text variant=\"h1\" weight=\"bold\">\n <Countdown {...args} />\n </Text>\n </Stack>\n ),\n}\n"},{"name":"DateField","category":"Forms","description":"A labelled native date or time input: the platform's own picker (wheels on\niOS, a calendar on Android and desktop), keyboard entry, locale-aware\ndisplay, and an ISO value (`2026-10-18`) in forms. `min`, `max` and `step`\nwork natively. The picker follows the color scheme.\n\n```tsx\n<DateField label=\"Start date\" name=\"start\" min=\"2026-01-01\" required />\n```","file":"packages/react/src/components/DateField/DateField.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The visible label. Required: use `hideLabel` to hide it visually."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the input."},{"name":"endAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, after the text: a unit, a clear button."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks the input invalid."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."},{"name":"type","type":"DateFieldType","required":false,"default":"date","description":"Which native picker: a date, a time, both, a month or a week."}],"styles":{"className":"greese-DateField","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { DateField, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Forms/DateField',\n component: DateField,\n args: { label: 'Due date', min: '2026-01-01' },\n decorators: [(Story) => <div style={{ maxInlineSize: '20rem' }}>{Story()}</div>],\n} satisfies Meta<typeof DateField>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The platform's own picker; the value is ISO (2026-10-18). */\nexport const Playground: Story = {}\n\nexport const Types: Story = {\n render: () => (\n <Stack gap={4}>\n <DateField label=\"Date\" />\n <DateField label=\"Time\" type=\"time\" />\n <DateField label=\"Date and time\" type=\"datetime-local\" />\n <DateField label=\"Month\" type=\"month\" />\n </Stack>\n ),\n}\n"},{"name":"Dialog","category":"Overlays","description":"A modal dialog on native `<dialog>`: focus is trapped and returned, the page\nbehind is inert and stops scrolling (CSS only), Escape and backdrop clicks\ndismiss. Its body scrolls when content is tall.\n\n```tsx\n<Dialog\n trigger={<Button>Delete project</Button>}\n title=\"Delete project?\"\n description=\"This can't be undone.\"\n footer={<Button tone=\"negative\" onClick={remove}>Delete</Button>}\n/>\n```","file":"packages/react/src/components/Dialog/Dialog.tsx","props":[{"name":"title","type":"ReactNode","required":true,"description":"Required: names the dialog for assistive tech."},{"name":"closeLabel","type":"string","required":false,"default":"Close","description":"Accessible name of the close button."},{"name":"defaultOpen","type":"boolean","required":false,"default":"false","description":"Whether it starts open, when it keeps its own state."},{"name":"description","type":"ReactNode","required":false,"description":"A line under the title, announced when it opens."},{"name":"dismissible","type":"boolean","required":false,"default":"true","description":"Escape, a click on the backdrop and the close button dismiss it. Turn off\nfor flows that must end with an explicit choice."},{"name":"footer","type":"ReactNode","required":false,"description":"Actions row, e.g. Cancel / Confirm buttons."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideTitle","type":"boolean","required":false,"description":"Visually hide the title, keeping it as the accessible name."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes (Escape, the close button,\na backdrop click)."},{"name":"open","type":"boolean","required":false,"description":"Controlled open state."},{"name":"size","type":"ControlSize | \"full\"","required":false,"default":"md","description":"Maximum width. `full` fills the viewport on every screen."},{"name":"trigger","type":"ReactElement<unknown, string | JSXElementConstructor<any>>","required":false,"description":"An element (usually a Button) that opens it on click."}],"styles":{"className":"greese-Dialog","parts":["body","close","description","footer","header","title"],"modifiers":["size-full","size-lg","size-md","size-sm","size-xl"],"attributes":["[open]"],"variables":["--greese-dialog-width","--greese-motion-backdrop","--greese-motion-backdrop-duration","--greese-motion-dialog","--greese-motion-dialog-exit-mask-from","--greese-motion-dialog-exit-mask-image","--greese-motion-dialog-exit-mask-position","--greese-motion-dialog-exit-mask-repeat","--greese-motion-dialog-exit-mask-size","--greese-motion-dialog-exit-opacity","--greese-motion-dialog-exit-scale","--greese-motion-dialog-exit-transform","--greese-motion-dialog-exit-transform-origin","--greese-motion-dialog-exit-translate","--greese-motion-drawer","--greese-motion-drawer-exit-mask-from","--greese-motion-drawer-exit-mask-image","--greese-motion-drawer-exit-mask-position","--greese-motion-drawer-exit-mask-repeat","--greese-motion-drawer-exit-mask-size","--greese-motion-drawer-exit-opacity","--greese-motion-drawer-exit-scale","--greese-motion-drawer-exit-transform","--greese-motion-drawer-exit-transform-origin","--greese-motion-drawer-exit-translate","--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin","--greese-scrollbar-gap"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Dialog, Stack, TextField } from '@greese/react'\n\nconst meta = {\n title: 'Overlays/Dialog',\n component: Dialog,\n args: {\n trigger: <Button>Edit profile</Button>,\n title: 'Edit profile',\n description: 'Changes are visible to your team.',\n footer: (\n <>\n <Button variant=\"outline\" tone=\"neutral\">\n Cancel\n </Button>\n <Button>Save</Button>\n </>\n ),\n children: (\n <Stack gap={4}>\n <TextField label=\"Name\" defaultValue=\"Ada Lovelace\" />\n <TextField label=\"Role\" defaultValue=\"Analyst\" />\n </Stack>\n ),\n },\n argTypes: { size: { control: 'inline-radio', options: ['sm', 'md', 'lg', 'full'] } },\n} satisfies Meta<typeof Dialog>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native `<dialog>`: focus trapped and returned, page inert and scroll-locked, Escape closes. */\nexport const Playground: Story = {}\n\n/** `dismissible={false}`: no close button, Escape and outside clicks are ignored. */\nexport const Confirmation: Story = {\n args: {\n trigger: (\n <Button tone=\"negative\" variant=\"outline\">\n Delete project\n </Button>\n ),\n title: 'Delete project?',\n description: 'This permanently removes the project and its history.',\n size: 'sm',\n dismissible: false,\n children: undefined,\n footer: (\n <form method=\"dialog\">\n <Button type=\"submit\" tone=\"negative\">\n Delete\n </Button>\n </form>\n ),\n },\n}\n"},{"name":"Diff","category":"Content","description":"Two versions of something (images, layouts, code) overlaid with a\ndraggable divider between them. The divider is a native range input:\ndrag, tap or use the arrow keys, and screen readers hear a percentage.\n\n```tsx\n<Diff before={<img src={raw} alt=\"Before\" />} after={<img src={edited} alt=\"After\" />} />\n```","file":"packages/react/src/components/Diff/Diff.tsx","props":[{"name":"after","type":"ReactNode","required":true,"description":"Shown on the inline-end side."},{"name":"before","type":"ReactNode","required":true,"description":"Shown on the inline-start side of the divider."},{"name":"afterLabel","type":"ReactNode","required":false,"description":"A small tag in the top inline-end corner, over the `after` side."},{"name":"beforeLabel","type":"ReactNode","required":false,"description":"Small tags in the top corners (\"Before\", \"After\")."},{"name":"defaultValue","type":"number","required":false,"default":"50","description":"Where the divider starts, in percent, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"Comparison","description":"Names the divider's slider."},{"name":"onValueChange","type":"((value: number) => void)","required":false,"description":"Called with the divider's new position, in percent, as it moves."},{"name":"value","type":"number","required":false,"description":"Where the divider is, in percent from the inline start."}],"styles":{"className":"greese-Diff","parts":["handle","item","range","tag"],"modifiers":[],"attributes":[],"variables":["--greese-diff-position","--greese-diff-thumb"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Box, Diff, Text } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Content/Diff',\n component: Diff,\n args: {\n label: 'Before and after',\n before: <img src={art(200)} alt=\"The original\" />,\n after: <img src={art(20)} alt=\"The edit\" />,\n beforeLabel: 'Before',\n afterLabel: 'After',\n style: { maxInlineSize: '36rem', aspectRatio: '16 / 9' },\n },\n} satisfies Meta<typeof Diff>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Drag the grip, tap anywhere, or focus it and use the arrow keys. */\nexport const Playground: Story = {}\n\n/** Anything can be compared, text included. */\nexport const Text_: Story = {\n name: 'Text',\n args: {\n defaultValue: 35,\n before: (\n <Box p={6} style={{ background: 'var(--greese-color-surface)' }}>\n <Text variant=\"h3\" weight=\"bold\">\n The quick brown fox\n </Text>\n </Box>\n ),\n after: (\n <Box p={6} style={{ background: 'var(--greese-color-canvas)' }}>\n <Text variant=\"h3\" weight=\"bold\" tone=\"primary\">\n The quick brown fox\n </Text>\n </Box>\n ),\n beforeLabel: undefined,\n afterLabel: undefined,\n style: { maxInlineSize: '36rem' },\n },\n}\n"},{"name":"Divider","category":"Layout","description":"A thematic separator: an `<hr>`, so assistive tech announces it. In a Stack\nit stretches across the cross axis.\n\n```tsx\n<Divider orientation=\"vertical\" />\n```","file":"packages/react/src/components/Divider/Divider.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"orientation","type":"\"horizontal\" | \"vertical\"","required":false,"default":"horizontal","description":"`vertical` divides items in a row."}],"styles":{"className":"greese-Divider","parts":[],"modifiers":[],"attributes":["[data-orientation=vertical]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Divider, Stack, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Divider',\n component: Divider,\n args: { orientation: 'horizontal' },\n} satisfies Meta<typeof Divider>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Between two blocks: stacked when horizontal, side by side when vertical. */\nexport const Playground: Story = {\n render: (args) => (\n <Stack\n direction={args.orientation === 'vertical' ? 'row' : 'column'}\n gap={3}\n style={{ minBlockSize: '6rem' }}\n >\n <Tile>One</Tile>\n <Divider {...args} />\n <Tile>Two</Tile>\n </Stack>\n ),\n}\n\nexport const Horizontal: Story = {\n render: () => (\n <Stack gap={3}>\n <Tile>Above</Tile>\n <Divider />\n <Tile>Below</Tile>\n </Stack>\n ),\n}\n\n/** In a row, a vertical divider stretches to the row's height. */\nexport const Vertical: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} align=\"stretch\">\n <Tile>Left</Tile>\n <Divider orientation=\"vertical\" />\n <Tile>Right</Tile>\n </Stack>\n ),\n}\n"},{"name":"Dock","category":"Navigation","description":"A bottom navigation bar for phones: a `<nav>` of icon-and-label links.\nPair it with `hideFrom` and a sidebar or app bar for larger screens. Leave\nroom for it at the end of the page (`padding-block-end`).\n\n```tsx\n<Dock hideFrom=\"md\">\n <DockItem href=\"/\" icon={<HomeIcon />} current>Home</DockItem>\n <DockItem href=\"/search\" icon={<SearchIcon />}>Search</DockItem>\n</Dock>\n```","file":"packages/react/src/components/Dock/Dock.tsx","props":[{"name":"aria-label","type":"string","required":false,"default":"Main","description":"Names the navigation landmark."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideFrom","type":"\"sm\" | \"md\" | \"lg\" | \"xl\"","required":false,"description":"Hide it from this breakpoint up, where other navigation takes over."},{"name":"position","type":"\"fixed\" | \"static\"","required":false,"default":"fixed","description":"`fixed` pins it to the bottom of the viewport, clear of the home\nindicator; `static` leaves it in the flow."}],"styles":{"className":"greese-Dock","parts":["list"],"modifiers":["fixed","hide-from-lg","hide-from-md","hide-from-sm","hide-from-xl"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Dock, DockItem } from '@greese/react'\nimport { BellIcon, HomeIcon, SearchIcon, UserIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Navigation/Dock',\n component: Dock,\n subcomponents: { DockItem },\n // Static in the docs; `fixed` (the default) pins it to the viewport's bottom.\n args: {\n position: 'static',\n children: (\n <>\n <DockItem href=\"#home\" icon={<HomeIcon />} current>\n Home\n </DockItem>\n <DockItem href=\"#search\" icon={<SearchIcon />}>\n Search\n </DockItem>\n <DockItem href=\"#alerts\" icon={<BellIcon />}>\n Alerts\n </DockItem>\n <DockItem href=\"#profile\" icon={<UserIcon />}>\n Profile\n </DockItem>\n </>\n ),\n },\n argTypes: {\n position: { control: 'inline-radio', options: ['fixed', 'static'] },\n hideFrom: { control: 'inline-radio', options: [undefined, 'sm', 'md', 'lg', 'xl'] },\n },\n} satisfies Meta<typeof Dock>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"DockItem","category":"Navigation","description":"One destination in a Dock: an icon over a short label.","file":"packages/react/src/components/Dock/Dock.tsx","props":[{"name":"icon","type":"ReactNode","required":true,"description":"The icon above the label. Decorative: the label names the link."},{"name":"asChild","type":"boolean","required":false,"description":"Render your own link (a router's) or a button instead of `<a>`."},{"name":"current","type":"boolean","required":false,"description":"The page it links to is the current one (`aria-current=\"page\"`)."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-DockItem","parts":["icon","label","link"],"modifiers":[],"attributes":["[aria-current=page]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Dock, DockItem } from '@greese/react'\nimport { HomeIcon, SearchIcon, UserIcon } from '@greese/icons'\n\n/** One destination in a Dock. `asChild` renders your router's link. */\nconst meta = {\n title: 'Navigation/DockItem',\n component: DockItem,\n args: { href: '#search', icon: <SearchIcon />, children: 'Search', current: true },\n decorators: [\n (Story) => (\n <Dock position=\"static\">\n <DockItem href=\"#home\" icon={<HomeIcon />}>\n Home\n </DockItem>\n <Story />\n <DockItem href=\"#profile\" icon={<UserIcon />}>\n Profile\n </DockItem>\n </Dock>\n ),\n ],\n} satisfies Meta<typeof DockItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The middle item, current. */\nexport const Playground: Story = {}\n"},{"name":"Drawer","category":"Overlays","description":"A panel that slides in from an edge: the same native modal behaviour as\nDialog. Bottom placement is a mobile sheet, padded for the home indicator.","file":"packages/react/src/components/Dialog/Dialog.tsx","props":[{"name":"title","type":"ReactNode","required":true,"description":"Required: names the dialog for assistive tech."},{"name":"closeLabel","type":"string","required":false,"default":"Close","description":"Accessible name of the close button."},{"name":"defaultOpen","type":"boolean","required":false,"default":"false","description":"Whether it starts open, when it keeps its own state."},{"name":"description","type":"ReactNode","required":false,"description":"A line under the title, announced when it opens."},{"name":"dismissible","type":"boolean","required":false,"default":"true","description":"Escape, a click on the backdrop and the close button dismiss it. Turn off\nfor flows that must end with an explicit choice."},{"name":"footer","type":"ReactNode","required":false,"description":"Actions row, e.g. Cancel / Confirm buttons."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideTitle","type":"boolean","required":false,"description":"Visually hide the title, keeping it as the accessible name."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes (Escape, the close button,\na backdrop click)."},{"name":"open","type":"boolean","required":false,"description":"Controlled open state."},{"name":"placement","type":"Responsive<DrawerPlacement>","required":false,"default":"end","description":"The edge it slides from, per breakpoint if needed, e.g. a bottom sheet on\nphones and a side panel from `md`: `{ xs: 'bottom', md: 'end' }`."},{"name":"swipeToClose","type":"boolean","required":false,"default":"true","description":"Drag the header (or a bottom sheet's handle) toward the edge to dismiss.\nIgnored when `dismissible` is false."},{"name":"trigger","type":"ReactElement<unknown, string | JSXElementConstructor<any>>","required":false,"description":"An element (usually a Button) that opens it on click."}],"styles":{"className":"greese-Drawer","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-drawer-dir","--greese-drawer-edge"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Drawer, Text } from '@greese/react'\n\nconst meta = {\n title: 'Overlays/Drawer',\n component: Drawer,\n args: {\n trigger: <Button variant=\"outline\">Filters</Button>,\n title: 'Filters',\n placement: { xs: 'bottom', md: 'end' },\n footer: <Button fullWidth>Apply</Button>,\n children: <Text tone=\"muted\">Filter controls go here.</Text>,\n },\n} satisfies Meta<typeof Drawer>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * A bottom sheet on phones and a side panel from md. Resize the viewport.\n * Drag the header (or the sheet's handle) toward the edge to dismiss.\n */\nexport const Playground: Story = {}\n\nexport const Start: Story = { args: { placement: 'start', title: 'Navigation' } }\n"},{"name":"Embed","category":"Content","description":"A third-party embed (YouTube, maps, CodePen) in a ratio frame. Lazy-loaded\nby default, so off-screen embeds cost nothing at page load.\n\n```tsx\n<Embed src=\"https://www.youtube-nocookie.com/embed/ID\" title=\"Product tour\" />\n```","file":"packages/react/src/components/Media/Media.tsx","props":[{"name":"title","type":"string","required":true,"description":"Required: names the frame for screen readers, e.g. \"Product demo video\"."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"ratio","type":"Responsive<string | number>","required":false,"default":"16 / 9","description":"Width to height, as a number (`16 / 9`) or a string (`'4 / 3'`), per\nbreakpoint if you like."}],"styles":{"className":"greese-Embed","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Embed } from '@greese/react'\n\nconst doc = `data:text/html,${encodeURIComponent(\n '<body style=\"margin:0;display:grid;place-items:center;font:16px system-ui;background:#eef\">An embedded page</body>'\n)}`\n\nconst meta = {\n title: 'Content/Embed',\n component: Embed,\n args: { title: 'Example embed', src: doc },\n decorators: [(Story) => <div style={{ maxInlineSize: '32rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Embed>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Third-party frames (YouTube, maps), lazy-loaded; `title` is required. */\nexport const Playground: Story = {}\n"},{"name":"Field","category":"Forms","description":"Label, description and error around one control, all wired up for\nassistive tech. The control is the child:\n\n```tsx\n<Field label=\"Email\" description=\"We never share it.\" error={errors.email}>\n <Input type=\"email\" name=\"email\" />\n</Field>\n```","file":"packages/react/src/components/Field/Field.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The visible label. Always required: use `hideLabel` to hide it visually."},{"name":"controlId","type":"string","required":false,"description":"The control's id. Generated when omitted."},{"name":"description","type":"ReactNode","required":false,"description":"Hint text below the label, announced with the control."},{"name":"disabled","type":"boolean","required":false,"description":"Disables the control and dims the label."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks the control invalid."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid without (or before) an error message."},{"name":"required","type":"boolean","required":false,"description":"Marks the control required and shows an asterisk after the label."}],"styles":{"className":"greese-Field","parts":["description","error","label","required"],"modifiers":[],"attributes":["[data-disabled]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, Input, Select, Textarea } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Field',\n component: Field,\n args: {\n label: 'Email',\n description: \"We'll only use it for receipts.\",\n children: <Input type=\"email\" />,\n },\n} satisfies Meta<typeof Field>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Label, description and error wired to the control for assistive tech. */\nexport const Playground: Story = {}\n\nexport const WithError: Story = {\n args: { error: 'Enter an email address like name@example.com', required: true },\n}\n\n/** Field works with any control, including your own (see `useFieldControl`). */\nexport const AnyControl: Story = {\n args: {\n label: 'Notes',\n description: 'Field wraps Select, Textarea and custom controls alike.',\n children: <Textarea placeholder=\"A few words\" />,\n },\n}\n\nexport const HiddenLabel: Story = {\n args: {\n label: 'Sort by',\n hideLabel: true,\n description: undefined,\n children: (\n <Select defaultValue=\"new\">\n <option value=\"new\">Newest</option>\n <option value=\"old\">Oldest</option>\n </Select>\n ),\n },\n}\n"},{"name":"Fieldset","category":"Forms","description":"Groups related fields under a title: a native `<fieldset>` and `<legend>`,\nso each control is announced with the group's name, and `disabled`\ndisables every control inside.\n\n```tsx\n<Fieldset legend=\"Shipping address\" description=\"Where we deliver.\">\n <TextField label=\"Street\" />\n <TextField label=\"City\" />\n</Fieldset>\n```","file":"packages/react/src/components/Fieldset/Fieldset.tsx","props":[{"name":"legend","type":"ReactNode","required":true,"description":"The group's title, read before each control in it."},{"name":"description","type":"ReactNode","required":false,"description":"Help for the whole group, announced with it."},{"name":"error","type":"ReactNode","required":false,"description":"An error for the group as a whole (\"Choose a delivery slot\")."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"variant","type":"\"plain\" | \"card\"","required":false,"default":"plain","description":"`plain` (no frame) or `card` (a padded surface with a border)."}],"styles":{"className":"greese-Fieldset","parts":["content","description","error","legend"],"modifiers":["card"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Fieldset, Grid, TextField } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Fieldset',\n component: Fieldset,\n args: {\n legend: 'Shipping address',\n description: 'Where we deliver your order.',\n style: { maxInlineSize: '32rem' },\n children: (\n <>\n <TextField label=\"Street\" autoComplete=\"street-address\" />\n <Grid container columns={{ xs: 1, sm: 2 }} gap={4}>\n <TextField label=\"City\" autoComplete=\"address-level2\" />\n <TextField label=\"Postcode\" autoComplete=\"postal-code\" />\n </Grid>\n </>\n ),\n },\n argTypes: { variant: { control: 'inline-radio', options: ['plain', 'card'] } },\n} satisfies Meta<typeof Fieldset>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Card: Story = { args: { variant: 'card' } }\n\n/** `disabled` disables every control inside, natively. */\nexport const Disabled: Story = { args: { variant: 'card', disabled: true } }\n\nexport const WithError: Story = {\n args: { variant: 'card', error: 'We don’t deliver to that postcode yet.' },\n}\n"},{"name":"FileInput","category":"Forms","description":"A native file input with a greese ui Button: the platform file picker\n(camera and photo library on phones), files dropped on it, and the chosen\nfile names beside the button. The input itself stays in the page, visually\nhidden, for keyboards, forms and screen readers; the Button is its\n`<label>`, so it takes the theme's button shape and states. `className`\nand `style` go to the frame; every other prop (and `ref`) goes to the\ninput.\n\n```tsx\n<Field label=\"Receipt\">\n <FileInput name=\"receipt\" accept=\"image/*,.pdf\" />\n</Field>\n```","file":"packages/react/src/components/FileInput/FileInput.tsx","props":[{"name":"buttonLabel","type":"ReactNode","required":false,"default":"Choose file","description":"The button's text."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid (`aria-invalid`) and colors it as an error. A surrounding\nField's `error` sets it too."},{"name":"placeholder","type":"string","required":false,"default":"No file chosen","description":"Shown beside the button until a file is chosen."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height and text size: `sm`, `md` or `lg`."}],"styles":{"className":"greese-FileInput","parts":["button","control","files"],"modifiers":["size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":["[data-disabled]"],"variables":["--greese-file-font"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, FileInput } from '@greese/react'\n\nconst meta = {\n title: 'Forms/FileInput',\n component: FileInput,\n args: { accept: 'image/*' },\n render: (args) => (\n <Field label=\"Avatar\" description=\"PNG or JPG, up to 2 MB.\">\n <FileInput {...args} />\n </Field>\n ),\n} satisfies Meta<typeof FileInput>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The native picker (camera and photos on phones), its button styled. */\nexport const Playground: Story = {}\n\nexport const Multiple: Story = { args: { multiple: true, accept: undefined } }\n"},{"name":"Footer","category":"Navigation","description":"The page's footer: a `<footer>` with the brand beside columns of links\n(FooterSection), and a closing row under a rule. The columns fill the width\nand wrap on narrow screens, the brand above them.\n\n```tsx\n<Footer brand={<Text weight=\"bold\">Acme</Text>} legal=\"© 2026 Acme\">\n <FooterSection title=\"Product\"><Link href=\"/pricing\">Pricing</Link></FooterSection>\n <FooterSection title=\"Company\"><Link href=\"/about\">About</Link></FooterSection>\n</Footer>\n```","file":"packages/react/src/components/Footer/Footer.tsx","props":[{"name":"brand","type":"ReactNode","required":false,"description":"The wordmark, logo or a line about the site, beside the sections."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"legal","type":"ReactNode","required":false,"description":"The closing row under a rule: copyright, legal links."},{"name":"size","type":"ContainerSize","required":false,"default":"lg","description":"How wide its content grows, as a Container: `lg` is 1024px, `full` the page."}],"styles":{"className":"greese-Footer","parts":["brand","inner","legal","main","sections"],"modifiers":["size-lg","size-md","size-sm","size-xl"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Footer, FooterSection, Link, Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Navigation/Footer',\n component: Footer,\n subcomponents: { FooterSection },\n parameters: { layout: 'fullscreen' },\n args: {\n brand: (\n <Stack gap={2}>\n <Text weight=\"bold\">Acme</Text>\n <Text variant=\"p3\" tone=\"muted\">\n Light, native components for teams that ship every week.\n </Text>\n </Stack>\n ),\n legal: (\n <>\n <span>© 2026 Acme, Inc.</span>\n <Stack direction=\"row\" gap={4}>\n <Link href=\"#privacy\" tone=\"neutral\">\n Privacy\n </Link>\n <Link href=\"#terms\" tone=\"neutral\">\n Terms\n </Link>\n </Stack>\n </>\n ),\n children: (\n <>\n <FooterSection title=\"Product\">\n <Link href=\"#features\" tone=\"neutral\">\n Features\n </Link>\n <Link href=\"#pricing\" tone=\"neutral\">\n Pricing\n </Link>\n <Link href=\"#changelog\" tone=\"neutral\">\n Changelog\n </Link>\n </FooterSection>\n <FooterSection title=\"Developers\">\n <Link href=\"#docs\" tone=\"neutral\">\n Docs\n </Link>\n <Link href=\"#api\" tone=\"neutral\">\n API\n </Link>\n </FooterSection>\n <FooterSection title=\"Company\">\n <Link href=\"#about\" tone=\"neutral\">\n About\n </Link>\n <Link href=\"#careers\" tone=\"neutral\">\n Careers\n </Link>\n </FooterSection>\n </>\n ),\n },\n} satisfies Meta<typeof Footer>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Only the closing row, for a page that needs little more. */\nexport const LegalOnly: Story = { args: { brand: undefined, children: undefined } }\n"},{"name":"FooterSection","category":"Navigation","description":"One column of a Footer: a heading over its links, as a `<nav>` named by the\nheading. Each child is an item of its list.\n\n```tsx\n<FooterSection title=\"Docs\">\n <Link href=\"/start\">Getting started</Link>\n <Link href=\"/theming\">Theming</Link>\n</FooterSection>\n```","file":"packages/react/src/components/Footer/Footer.tsx","props":[{"name":"title","type":"ReactNode","required":true,"description":"The column's heading."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"`title`, when it is text","description":"The navigation's accessible name, when `title` isn't text."}],"styles":{"className":"greese-FooterSection","parts":["links","title"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Footer, FooterSection, Link } from '@greese/react'\n\nconst meta = {\n title: 'Navigation/FooterSection',\n component: FooterSection,\n parameters: { layout: 'fullscreen' },\n decorators: [\n (Story) => (\n <Footer>\n <Story />\n </Footer>\n ),\n ],\n args: {\n title: 'Docs',\n children: [\n <Link key=\"start\" href=\"#start\" tone=\"neutral\">\n Getting started\n </Link>,\n <Link key=\"theming\" href=\"#theming\" tone=\"neutral\">\n Theming\n </Link>,\n <Link key=\"motion\" href=\"#motion\" tone=\"neutral\">\n Motion\n </Link>,\n ],\n },\n} satisfies Meta<typeof FooterSection>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Grid","category":"Layout","description":"Two-dimensional CSS grid layout. `container` makes a grid; a Grid without\nit is a cell that spans `size` columns. The same element can be both.\n\n```tsx\n<Grid container columns={12} gap={4}>\n <Grid size={{ xs: 12, md: 8 }}>…</Grid>\n <Grid size={{ xs: 12, md: 4 }}>…</Grid>\n</Grid>\n<Grid container minChildWidth=\"14rem\" gap={4}>…</Grid>\n```\n\nAccepts every Box style prop and `asChild`. Server-component safe.","file":"packages/react/src/components/Grid/Grid.tsx","props":[{"name":"align","type":"Responsive<\"center\" | \"start\" | \"end\" | \"stretch\">","required":false,"description":"With `container`: how cells align in the block axis (`align-items`)."},{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"columns","type":"Responsive<(string & {}) | GridColumnCount>","required":false,"description":"With `container`: equal columns (`1`–`12`), or any `grid-template-columns`\nvalue such as `'200px 1fr'`, per breakpoint if you like."},{"name":"container","type":"boolean","required":false,"default":"false","description":"Makes this element a grid: its children are laid out in its columns.\nWithout it, a Grid is a cell of the grid around it. One element can be\nboth, to nest grids."},{"name":"containerQueries","type":"boolean","required":false,"description":"With `container`: the cells' `size`s respond to this grid's own width\ninstead of the viewport's, so the same grid adapts in a sidebar or a\nfull-width page."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"With `container`: space between cells, a scale token (`0`–`8`) or any CSS\nlength, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"justify","type":"Responsive<\"center\" | \"start\" | \"end\" | \"stretch\">","required":false,"description":"With `container`: how cells align in the inline axis (`justify-items`)."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"minChildWidth","type":"Responsive<string>","required":false,"description":"With `container`: fits as many columns as possible, each at least this\nwide, so the grid is responsive without breakpoints. Overrides `columns`\nwhere both apply."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"size","type":"Responsive<GridSize>","required":false,"description":"How many of the parent grid's columns this cell spans: `1`–`12`, or\n`'full'` for the whole row, per breakpoint if you like\n(`{ xs: 12, md: 6 }`)."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Grid","parts":[],"modifiers":["container","queries"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Grid, Tile } from '@greese/react'\n\nconst tiles = (n: number) =>\n Array.from({ length: n }, (_, i) => <Tile key={i}>{i + 1}</Tile>)\n\nconst meta = {\n title: 'Layout/Grid',\n component: Grid,\n args: { container: true, columns: { xs: 1, sm: 2, lg: 4 }, gap: 3, children: tiles(8) },\n} satisfies Meta<typeof Grid>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** `container` makes a grid: one column on phones, two from `sm`, four from `lg`. */\nexport const Playground: Story = {}\n\n/** Without `container`, a Grid is a cell: `size` is how many columns it spans. */\nexport const Cells: Story = {\n args: {\n columns: 12,\n children: (\n <>\n <Grid size={{ xs: 12, md: 8 }}>\n <Tile>size: xs 12, md 8</Tile>\n </Grid>\n <Grid size={{ xs: 12, md: 4 }}>\n <Tile>size: xs 12, md 4</Tile>\n </Grid>\n <Grid size=\"full\">\n <Tile>size: full</Tile>\n </Grid>\n </>\n ),\n },\n}\n\n/** As many columns as fit at 12rem each: responsive with no breakpoints at all. */\nexport const MinChildWidth: Story = {\n args: { columns: undefined, minChildWidth: '12rem', children: tiles(10) },\n}\n\n/**\n * With `containerQueries`, cells' sizes respond to the grid's own width. The\n * same markup is stacked in the narrow column and split in the wide one; a\n * cell that is also a `container` nests a grid.\n */\nexport const ContainerQueries: Story = {\n args: { columns: { xs: 1, md: '16rem 1fr' }, gap: 4 },\n render: (args) => (\n <Grid {...args}>\n {['narrow', 'wide'].map((label) => (\n <Grid container key={label} containerQueries columns={12} gap={2}>\n <Grid size={{ xs: 12, sm: 6 }}>\n <Tile>{label}: half from sm</Tile>\n </Grid>\n <Grid size={{ xs: 12, sm: 6 }}>\n <Tile>{label}: half from sm</Tile>\n </Grid>\n </Grid>\n ))}\n </Grid>\n ),\n}\n"},{"name":"Header","category":"Navigation","description":"The page's header: a `<header>` row of brand, navigation (its children) and\nactions, padded for notches and the status bar. Sticky by default, spanning\nthe page or `floating` inset from it; a sticky one keeps in-page links clear\nof itself, with no JavaScript.\n\n```tsx\n<Header floating brand={<Link href=\"/\">Acme</Link>} actions={<Button size=\"sm\">Sign in</Button>}>\n <nav aria-label=\"Main\">…</nav>\n</Header>\n```","file":"packages/react/src/components/Header/Header.tsx","props":[{"name":"actions","type":"ReactNode","required":false,"description":"What sits at the end of the row: actions, a menu button."},{"name":"brand","type":"ReactNode","required":false,"description":"The wordmark or logo, at the start of the row."},{"name":"floating","type":"boolean","required":false,"default":"false","description":"Detached from the page's edges: inset, rounded and raised, so the page\nscrolls under it with a gap all round. Without it, it spans the page with\na rule along its foot."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"size","type":"ContainerSize","required":false,"default":"lg","description":"How wide its row grows, as a Container: `lg` is 1024px, `full` the page."},{"name":"sticky","type":"boolean","required":false,"default":"true","description":"Stay at the top while scrolling. A sticky header also sets the page's\nscroll padding to its own height, so in-page links (`#section`) land with\ntheir target just below it."}],"styles":{"className":"greese-Header","parts":["actions","brand","inner","nav"],"modifiers":["floating","size-lg","size-md","size-sm","size-xl","sticky"],"attributes":[],"variables":["--greese-header-height","--greese-header-inset"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Header, Link, Stack, Text } from '@greese/react'\n\nconst nav = (\n <Stack asChild direction=\"row\" gap={4}>\n <nav aria-label=\"Main\">\n <Link href=\"#features\" tone=\"neutral\">\n Features\n </Link>\n <Link href=\"#pricing\" tone=\"neutral\">\n Pricing\n </Link>\n <Link href=\"#docs\" tone=\"neutral\">\n Docs\n </Link>\n </nav>\n </Stack>\n)\n\nconst meta = {\n title: 'Navigation/Header',\n component: Header,\n parameters: { layout: 'fullscreen' },\n args: {\n brand: <Text weight=\"bold\">Acme</Text>,\n actions: (\n <Button size=\"sm\" variant=\"soft\">\n Sign in\n </Button>\n ),\n children: nav,\n },\n render: (args) => (\n <div>\n <Header {...args} />\n <Stack p={5} gap={4}>\n <Text tone=\"muted\">\n Scroll: the header sticks, with a shadow once the page moves, and in-page links\n land just below it.\n </Text>\n <div style={{ blockSize: '120vh' }} />\n </Stack>\n </div>\n ),\n} satisfies Meta<typeof Header>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Inset from the page's edges, rounded and raised: the page scrolls under it with a gap all round. */\nexport const Floating: Story = { args: { floating: true } }\n\n/** Scrolls away with the page. */\nexport const Static: Story = { args: { sticky: false } }\n\n/** The full width of the page, for apps. */\nexport const FullWidth: Story = { args: { size: 'full' } }\n"},{"name":"Heading","category":"Content","description":"A heading whose `level` sets the document outline and whose `variant` sets\nthe look (the level's own style by default), so the two never have to fight.\n\n```tsx\n<Heading level={2} variant=\"h4\">Billing</Heading>\n```","file":"packages/react/src/components/Heading/Heading.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (e.g. a heading inside a `<summary>`) with heading styles."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"level","type":"HeadingLevel","required":false,"default":"2","description":"Document outline level: renders `<h1>`–`<h6>`."},{"name":"ref","type":"Ref<HTMLHeadingElement>","required":false,"description":"The rendered heading element (or your element, with `asChild`)."},{"name":"tone","type":"TextTone","required":false,"description":"Text color: neutral, muted, accent, positive, negative, warning or info."},{"name":"variant","type":"\"button\" | \"caption\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p1\" | \"p2\" | \"p3\" | \"s1\" | \"s2\"","required":false,"default":"`h${level}`","description":"A named text style from the theme's type system, independent of level:\n`<Heading level={2} variant=\"h4\">` is an `<h2>` that looks like an `h4`.\nIt sets size, weight, letter spacing and line height for every breakpoint."}],"styles":{"className":"greese-Heading","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Heading, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/Heading',\n component: Heading,\n args: { level: 2, children: 'A section heading' },\n argTypes: {\n level: { control: 'inline-radio', options: [1, 2, 3, 4, 5, 6] },\n variant: {\n control: 'select',\n options: [undefined, 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 's1', 's2', 'p1'],\n },\n },\n} satisfies Meta<typeof Heading>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Headings shrink on phones by default; resize to see them step up at md. */\nexport const Levels: Story = {\n render: () => (\n <Stack gap={3}>\n {([1, 2, 3, 4, 5, 6] as const).map((level) => (\n <Heading key={level} level={level}>\n Heading level {level}\n </Heading>\n ))}\n </Stack>\n ),\n}\n\n/** `level` sets the outline; `variant` sets the look. */\nexport const LookIndependentOfLevel: Story = {\n args: {\n level: 2,\n variant: 'h6',\n tone: 'muted',\n children: 'A level-2 heading styled small',\n },\n}\n\n/** A `variant` takes its look from the type system, so an `<h2>` can look like an `h4`. */\nexport const Variants: Story = {\n render: () => (\n <Stack gap={3}>\n {(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const).map((variant) => (\n <Heading key={variant} level={2} variant={variant}>\n A level-2 heading in the {variant} style\n </Heading>\n ))}\n </Stack>\n ),\n}\n"},{"name":"Hide","category":"Layout","description":"The inverse of Show: hides children from `above` upward and/or `below` a\nbreakpoint. With both, and `above` the smaller, it hides only between them.","file":"packages/react/src/components/Visibility/Visibility.tsx","props":[{"name":"above","type":"BreakpointBoundary","required":false,"description":"From this breakpoint upward (inclusive)."},{"name":"asChild","type":"boolean","required":false,"description":"Apply to your element instead of a layout-neutral wrapper."},{"name":"below","type":"BreakpointBoundary","required":false,"description":"Below this breakpoint (exclusive)."},{"name":"children","type":"ReactNode","required":false,"description":"What to show or hide."},{"name":"className","type":"string","required":false,"description":"Classes for the wrapper, or for your element with `asChild`."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Hide, Tile } from '@greese/react'\n\n/** Show's opposite: hides its children in a breakpoint range, in CSS only. */\nconst meta = {\n title: 'Layout/Hide',\n component: Hide,\n args: { above: 'md', children: <Tile>Hidden from md up</Tile> },\n} satisfies Meta<typeof Hide>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Resize the viewport past md. */\nexport const Playground: Story = {}\n\nexport const Between: Story = {\n args: { above: 'sm', below: 'lg', children: <Tile>Hidden between sm and lg</Tile> },\n}\n"},{"name":"Icon","category":"Content","description":"Sizes and colors any icon (SVG from any set) consistently: it inherits the\ntext color and scales with font size.\n\n```tsx\n<Icon><HeartSvg /></Icon>\n<Icon label=\"Verified account\"><BadgeCheck /></Icon>\n```","file":"packages/react/src/components/Icon/Icon.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"description":"Accessible name. Without it the icon is decorative (`aria-hidden`), which\nis right when text sits beside it."},{"name":"size","type":"string","required":false,"default":"'1.25em' (scales with surrounding text)","description":"Any CSS length."}],"styles":{"className":"greese-Icon","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-icon-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Icon, Stack, Text } from '@greese/react'\nimport { InfoIcon, StarIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Content/Icon',\n component: Icon,\n args: { children: <StarIcon /> },\n} satisfies Meta<typeof Icon>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Decorative by default (aria-hidden); inherits color and scales with text. */\nexport const Playground: Story = {}\n\nexport const Labelled: Story = {\n args: {\n label: 'Verified account',\n size: '1.5rem',\n style: { color: 'var(--greese-color-primary)' },\n },\n}\n\nexport const ScalesWithText: Story = {\n render: () => (\n <Stack gap={2}>\n {(['p3', 'p2', 's1', 'h2'] as const).map((variant) => (\n <Text key={variant} variant={variant}>\n <Icon>\n <InfoIcon />\n </Icon>{' '}\n Text at {variant}\n </Text>\n ))}\n </Stack>\n ),\n}\n"},{"name":"IconButton","category":"Forms","description":"A square, icon-only button. Bring any icon, from any set; `@greese/icons` has some.\n\n```tsx\n<IconButton label=\"Close dialog\" onClick={close}><XIcon /></IconButton>\n<IconButton label=\"GitHub\" href=\"https://github.com/…\"><GitHubIcon /></IconButton>\n```","file":"packages/react/src/components/IconButton/IconButton.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The icon: any element, from any icon set."},{"name":"label","type":"string","required":true,"description":"The accessible name, required: an icon alone says nothing to a screen\nreader. Applied as `aria-label`."},{"name":"asChild","type":"boolean","required":false,"description":"Render your own element, e.g. a router `<Link>`, as the button.\nAn `href` renders the link itself; use `asChild` without one for your own."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"href","type":"string","required":false,"description":"A button that goes somewhere takes `href` instead of `onClick`.\nWhere it goes: renders an `<a>` instead of a `<button>`."},{"name":"loading","type":"boolean","required":false,"description":"Shows a spinner and ignores clicks, but stays focusable (`aria-disabled`,\nnot `disabled`) so keyboard focus is not lost mid-action. A submit button\ndoesn't submit while it's loading."},{"name":"onClick","type":"MouseEventHandler<HTMLButtonElement>","required":false,"description":"Called when it's pressed; never while it's loading or disabled.\nA link goes to its `href`; it takes no `onClick`."},{"name":"ref","type":"((instance: HTMLButtonElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<HTMLButtonElement | null> | ((instance: HTMLAnchorElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<...> | null","required":false,"description":"The rendered `<button>` (or your element, with `asChild`).\nThe rendered `<a>`."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `xs`, `sm`, `md`, `lg` or `xl`. Touch targets stay at\nleast 44px."},{"name":"tone","type":"ButtonTone","required":false,"default":"neutral","description":"Color role: `accent`, a brand color (primary, secondary, tertiary),\n`neutral`, or `negative` for destructive actions."},{"name":"variant","type":"ButtonVariant","required":false,"default":"ghost","description":"Visual weight: `solid` for the main action, `soft`, `outline`, then `ghost`\nfor the least. `text` drops the box and takes the surrounding text's color,\nso the button reads as plain text."}],"styles":{"className":"greese-IconButton","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-button-height"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { IconButton, Stack } from '@greese/react'\nimport { PlusIcon, StarIcon, TrashIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/IconButton',\n component: IconButton,\n args: { label: 'Add to favourites', children: <StarIcon /> },\n argTypes: {\n variant: { control: 'inline-radio', options: ['solid', 'soft', 'outline', 'ghost'] },\n tone: {\n control: 'inline-radio',\n options: ['primary', 'secondary', 'tertiary', 'accent', 'neutral', 'negative'],\n },\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },\n },\n} satisfies Meta<typeof IconButton>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** `label` is required: it is the button's accessible name. */\nexport const Playground: Story = {}\n\nexport const Variants: Story = {\n render: () => (\n <Stack direction=\"row\" gap={2} align=\"center\">\n <IconButton label=\"Add\" variant=\"solid\" tone=\"primary\">\n <PlusIcon />\n </IconButton>\n <IconButton label=\"Favourite\" variant=\"soft\" tone=\"primary\">\n <StarIcon />\n </IconButton>\n <IconButton label=\"Favourite\" variant=\"outline\" tone=\"neutral\">\n <StarIcon />\n </IconButton>\n <IconButton label=\"Delete\" tone=\"negative\">\n <TrashIcon />\n </IconButton>\n <IconButton label=\"Delete\" size=\"sm\" tone=\"negative\" loading>\n <TrashIcon />\n </IconButton>\n </Stack>\n ),\n}\n"},{"name":"Image","category":"Content","description":"A responsive `<img>`: lazy by default, decoded off the main thread, with an\noptional ratio frame, placeholder and error fallback. `srcSet`/`sizes` pass\nthrough to the image.\n\n```tsx\n<Image src=\"/hero.jpg\" alt=\"The team at work\" ratio={16 / 9} priority />\n```","file":"packages/react/src/components/Image/Image.tsx","props":[{"name":"alt","type":"string","required":true,"description":"Required: describe the image, or `\"\"` if it is decorative."},{"name":"fallback","type":"ReactNode","required":false,"description":"Rendered instead of the image if it fails to load."},{"name":"fit","type":"\"cover\" | \"contain\"","required":false,"default":"cover","description":"How the image fills its ratio box: `cover` crops to fill, `contain` shows\nall of it."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"placeholder","type":"string","required":false,"description":"Shown behind the image until it paints: a color, or a tiny blurred\ndata URL for a blur-up effect. Pure CSS, so it works before hydration."},{"name":"priority","type":"boolean","required":false,"description":"For the largest image above the fold (your LCP element): loads eagerly at\nhigh priority instead of lazily."},{"name":"radius","type":"\"none\" | \"sm\" | \"md\" | \"lg\" | \"pill\"","required":false,"description":"Rounded corners."},{"name":"ratio","type":"Responsive<string | number>","required":false,"description":"Width / height. Reserves space before loading, so nothing shifts (no CLS)."}],"styles":{"className":"greese-Image","parts":[],"modifiers":["contain","fallback","framed","radius-lg","radius-md","radius-none","radius-pill","radius-sm"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Image, Stack } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Content/Image',\n component: Image,\n args: {\n alt: 'Abstract illustration',\n src: art(260),\n ratio: { xs: 1, md: 16 / 9 },\n radius: 'lg',\n },\n decorators: [(Story) => <div style={{ maxInlineSize: '28rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Image>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Lazy by default; the ratio reserves space so nothing shifts. */\nexport const Playground: Story = {}\n\nexport const PlaceholderAndFallback: Story = {\n render: () => (\n <Stack gap={4}>\n <Image alt=\"\" src={art(140)} ratio={2} placeholder=\"#cfd8dc\" radius=\"md\" />\n <Image\n alt=\"Missing\"\n src=\"/does-not-exist.png\"\n ratio={2}\n fallback=\"Image unavailable\"\n radius=\"md\"\n />\n </Stack>\n ),\n}\n"},{"name":"Indicator","category":"Layout","description":"Pins a small element (a Badge, a Status dot) to a corner or edge of its\nchild, centred on that corner.\n\n```tsx\n<Indicator content={<Badge tone=\"negative\" variant=\"solid\">3</Badge>}>\n <IconButton label=\"Inbox\"><InboxIcon /></IconButton>\n</Indicator>\n```","file":"packages/react/src/components/Indicator/Indicator.tsx","props":[{"name":"content","type":"ReactNode","required":true,"description":"What sits on the corner: a Badge, a Status, a count."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"placement","type":"IndicatorPlacement","required":false,"default":"top-end","description":"Logical: `start`/`end` follow the writing direction."}],"styles":{"className":"greese-Indicator","parts":["item"],"modifiers":[],"attributes":[],"variables":["--greese-indicator-x","--greese-indicator-y"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, Badge, Grid, IconButton, Indicator, Status, Tile } from '@greese/react'\nimport { BellIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Layout/Indicator',\n component: Indicator,\n args: {\n content: (\n <Badge tone=\"negative\" variant=\"solid\">\n 3\n </Badge>\n ),\n children: (\n <IconButton label=\"Notifications, 3 unread\" variant=\"soft\" tone=\"neutral\">\n <BellIcon />\n </IconButton>\n ),\n },\n argTypes: {\n placement: {\n control: 'select',\n options: [\n 'top-start',\n 'top',\n 'top-end',\n 'start',\n 'center',\n 'end',\n 'bottom-start',\n 'bottom',\n 'bottom-end',\n ],\n },\n },\n} satisfies Meta<typeof Indicator>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The count is in the button's name too: the badge itself is only visual. */\nexport const Playground: Story = {}\n\nexport const OnAnAvatar: Story = {\n args: {\n placement: 'bottom-end',\n content: <Status tone=\"positive\" label=\"Online\" size=\"lg\" />,\n children: <Avatar name=\"Ada Lovelace\" />,\n },\n}\n\nexport const Placements: Story = {\n render: () => (\n <Grid\n container\n columns={3}\n gap={6}\n style={{ maxInlineSize: '34rem', padding: '1.5rem 3rem' }}\n >\n {(\n [\n 'top-start',\n 'top',\n 'top-end',\n 'start',\n 'center',\n 'end',\n 'bottom-start',\n 'bottom',\n 'bottom-end',\n ] as const\n ).map((placement) => (\n <Indicator\n key={placement}\n placement={placement}\n content={<Badge tone=\"primary\">{placement}</Badge>}\n style={{ inlineSize: '100%' }}\n >\n <Tile style={{ inlineSize: '100%', blockSize: '4rem' }} />\n </Indicator>\n ))}\n </Grid>\n ),\n}\n"},{"name":"Input","category":"Forms","description":"A native text-like `<input>` in a styled frame. `className` and `style` go\nto the frame; every other prop (and `ref`) goes to the input itself, so it\nworks with native forms and form libraries as-is.\n\n```tsx\n<Field label=\"Amount\">\n <Input type=\"number\" name=\"amount\" startAdornment=\"$\" />\n</Field>\n```","file":"packages/react/src/components/Input/Input.tsx","props":[{"name":"endAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, after the text: a unit, a clear button."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."}],"styles":{"className":"greese-Input","parts":["adornment","control"],"modifiers":["size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":["[aria-invalid=true]","[data-disabled]","[data-invalid]"],"variables":["--greese-input-height","--greese-input-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Input, Stack } from '@greese/react'\nimport { SearchIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/Input',\n component: Input,\n args: {\n 'aria-label': 'Search',\n placeholder: 'Search…',\n startAdornment: <SearchIcon />,\n },\n argTypes: { size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] } },\n} satisfies Meta<typeof Input>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The bare control. Wrap it in Field (or use TextField) for a visible label. */\nexport const Playground: Story = {}\n\nexport const Adornments: Story = {\n render: () => (\n <Stack gap={3} maxW=\"20rem\">\n <Input\n aria-label=\"Price\"\n inputMode=\"decimal\"\n startAdornment=\"$\"\n endAdornment=\"NZD\"\n />\n <Input aria-label=\"Website\" startAdornment=\"https://\" placeholder=\"example.com\" />\n </Stack>\n ),\n}\n\nexport const Sizes: Story = {\n render: () => (\n <Stack gap={3} maxW=\"20rem\">\n <Input aria-label=\"Small\" size=\"sm\" placeholder=\"Small\" />\n <Input aria-label=\"Medium\" placeholder=\"Medium\" />\n <Input aria-label=\"Large\" size=\"lg\" placeholder=\"Large\" />\n </Stack>\n ),\n}\n\nexport const States: Story = {\n render: () => (\n <Stack gap={3} maxW=\"20rem\">\n <Input aria-label=\"Invalid\" invalid defaultValue=\"not-an-email\" />\n <Input aria-label=\"Disabled\" disabled defaultValue=\"Disabled\" />\n <Input aria-label=\"Read only\" readOnly defaultValue=\"Read only\" />\n </Stack>\n ),\n}\n"},{"name":"Key","category":"Content","description":"A key on the keyboard, as a native `<kbd>`. Nest them for a shortcut, so\nthe whole combination is one piece of keyboard input.\n\n```tsx\n<Key><Key>⌘</Key> + <Key>K</Key></Key>\n```","file":"packages/react/src/components/Key/Key.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Text size of the key: `sm`, `md` or `lg`."}],"styles":{"className":"greese-Key","parts":[],"modifiers":["lg","md","sm","xl","xs"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Key, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Key',\n component: Key,\n args: { children: 'K' },\n argTypes: { size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] } },\n} satisfies Meta<typeof Key>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Nested: the outer `<kbd>` is the whole shortcut. */\nexport const Shortcut: Story = {\n render: () => (\n <Text>\n Search with{' '}\n <Key>\n <Key>⌘</Key> + <Key>K</Key>\n </Key>\n , or{' '}\n <Key size=\"sm\">\n <Key size=\"sm\">Ctrl</Key> + <Key size=\"sm\">K</Key>\n </Key>{' '}\n on Windows.\n </Text>\n ),\n}\n"},{"name":"Link","category":"Content","description":"An inline text link. Underlined by default: color alone is not enough to spot a link.\n\n```tsx\n<Link href=\"/pricing\" underline=\"hover\">Pricing</Link>\n```","file":"packages/react/src/components/Link/Link.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Style your router's link component: `<Link asChild><RouterLink to=\"/\" /></Link>`."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"ref","type":"Ref<HTMLAnchorElement>","required":false,"description":"The rendered `<a>` (or your element, with `asChild`)."},{"name":"tone","type":"\"neutral\" | BrandTone","required":false,"default":"primary","description":"`accent` for links in text; `neutral` for links that shouldn't stand out\n(footers, lists); or a brand color (primary, secondary, tertiary)."},{"name":"underline","type":"\"always\" | \"hover\"","required":false,"default":"always","description":"`always` underlined, or only on `hover`. Inline links in text should stay\n`always`."}],"styles":{"className":"greese-Link","parts":[],"modifiers":["accent","neutral","primary","secondary","tertiary","underline-hover"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Link, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Link',\n component: Link,\n args: { href: '#docs', children: 'Read the docs' },\n argTypes: {\n tone: {\n control: 'inline-radio',\n options: ['primary', 'secondary', 'tertiary', 'accent', 'neutral'],\n },\n underline: { control: 'inline-radio', options: ['always', 'hover'] },\n },\n} satisfies Meta<typeof Link>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const InText: Story = {\n render: () => (\n <Text>\n Inline links are underlined by default: <Link href=\"#a\">primary</Link>,{' '}\n <Link href=\"#b\" tone=\"neutral\">\n neutral\n </Link>\n ,{' '}\n <Link href=\"#d\" tone=\"secondary\">\n secondary\n </Link>{' '}\n and{' '}\n <Link href=\"#c\" underline=\"hover\">\n underline on hover\n </Link>\n .\n </Text>\n ),\n}\n"},{"name":"List","category":"Content","description":"Rows of related things (people, files, settings), each with optional\nmedia, text and actions: a native `<ul>`.\n\n```tsx\n<List framed>\n <ListItem start={<Avatar name=\"Ada Lovelace\" />} title=\"Ada Lovelace\"\n description=\"Analyst\" end={<Button size=\"sm\">Message</Button>} />\n</List>\n```","file":"packages/react/src/components/List/List.tsx","props":[{"name":"divided","type":"boolean","required":false,"default":"true","description":"Lines between rows."},{"name":"framed","type":"boolean","required":false,"default":"false","description":"A bordered box around the rows."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-List","parts":[],"modifiers":["divided","framed"],"attributes":[],"variables":["--greese-list-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, Badge, Button, List, ListItem } from '@greese/react'\n\nconst people = [\n { name: 'Ada Lovelace', role: 'Analyst', status: 'Owner' },\n { name: 'Grace Hopper', role: 'Compiler', status: 'Admin' },\n { name: 'Alan Turing', role: 'Theory', status: 'Member' },\n]\n\nconst meta = {\n title: 'Content/List',\n component: List,\n subcomponents: { ListItem },\n args: {\n framed: true,\n style: { maxInlineSize: '32rem' },\n children: people.map((p) => (\n <ListItem\n key={p.name}\n start={<Avatar name={p.name} size=\"sm\" />}\n title={p.name}\n description={p.role}\n end={\n <Badge tone={p.status === 'Owner' ? 'primary' : 'neutral'}>{p.status}</Badge>\n }\n />\n )),\n },\n} satisfies Meta<typeof List>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Rows with actions, no frame. */\nexport const WithActions: Story = {\n args: {\n framed: false,\n children: people.map((p) => (\n <ListItem\n key={p.name}\n title={p.name}\n description={p.role}\n end={\n <Button size=\"sm\" variant=\"soft\">\n Message\n </Button>\n }\n />\n )),\n },\n}\n"},{"name":"ListItem","category":"Content","description":"One row of a List. Anything in `children` goes under the text.","file":"packages/react/src/components/List/List.tsx","props":[{"name":"description","type":"ReactNode","required":false,"description":"A second, muted line."},{"name":"end","type":"ReactNode","required":false,"description":"At the inline end: actions, a Badge, a time."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"start","type":"ReactNode","required":false,"description":"Media at the inline start: an Avatar, an icon, a thumbnail."},{"name":"title","type":"ReactNode","required":false,"description":"The main line."}],"styles":{"className":"greese-ListItem","parts":["body","description","end","start","title"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Avatar, Button, List, ListItem } from '@greese/react'\n\n/** One row of a List: media, a title and description, and actions. */\nconst meta = {\n title: 'Content/ListItem',\n component: ListItem,\n args: {\n start: <Avatar name=\"Grace Hopper\" size=\"sm\" />,\n title: 'Grace Hopper',\n description: 'Compiler',\n end: (\n <Button size=\"sm\" variant=\"soft\">\n Message\n </Button>\n ),\n },\n decorators: [\n (Story) => (\n <List framed style={{ maxInlineSize: '32rem' }}>\n <ListItem title=\"Ada Lovelace\" description=\"Analyst\" />\n <Story />\n </List>\n ),\n ],\n} satisfies Meta<typeof ListItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The second row. */\nexport const Playground: Story = {}\n"},{"name":"MaskedInput","category":"Forms","description":"A text input that formats as you type against a pattern: phone numbers,\ncard numbers, codes. Value in and out is the raw characters; the user sees\nand edits the formatted text, and the caret skips over literals.\n\n```tsx\n<Field label=\"Phone\">\n <MaskedInput mask=\"(999) 999-9999\" placeholder=\"(555) 123-4567\" />\n</Field>\n```\n\nThe phone keypad opens for digit-only masks. In a form, the field submits\nthe formatted text; read the raw value from `onValueChange` if you need it.","file":"packages/react/src/components/MaskedInput/MaskedInput.tsx","props":[{"name":"mask","type":"string","required":true,"description":"The pattern. Placeholders: `9` a digit, `a`/`A` a letter, `h`/`H` a hex\ndigit, `*` a letter or digit. Anything else is a literal the user never\ntypes: `(999) 999-9999`, `#hhhhhh`, `AA-9999`."},{"name":"defaultValue","type":"string","required":false,"default":"","description":"The raw value, uncontrolled."},{"name":"endAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, after the text: a unit, a clear button."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"maskChar","type":"string","required":false,"default":"_","description":"Shown in unfilled placeholders."},{"name":"onValueChange","type":"((raw: string, masked: string) => void)","required":false,"description":"Called with the raw value and the formatted text on every edit."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."},{"name":"value","type":"string","required":false,"description":"The raw value (placeholder characters only), controlled."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\nimport { Field, Grid, MaskedInput, Text } from '@greese/react'\n\nconst meta = {\n title: 'Forms/MaskedInput',\n component: MaskedInput,\n args: { mask: '(999) 999-9999', placeholder: '(555) 123-4567' },\n render: (args) => (\n <Field label=\"Phone\" description=\"Digits only; the formatting is added for you.\">\n <MaskedInput {...args} />\n </Field>\n ),\n decorators: [(Story) => <div style={{ maxInlineSize: '20rem' }}>{Story()}</div>],\n} satisfies Meta<typeof MaskedInput>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The phone keypad opens on touch devices for digit-only masks. */\nexport const Playground: Story = {}\n\n/** `9` digit, `a`/`A` letter, `h`/`H` hex digit, `*` letter or digit. */\nexport const Patterns: Story = {\n render: () => (\n <Grid container gap={4}>\n <Field label=\"Card number\">\n <MaskedInput mask=\"9999 9999 9999 9999\" placeholder=\"4242 4242 4242 4242\" />\n </Field>\n <Field label=\"Expiry\">\n <MaskedInput mask=\"99/99\" placeholder=\"MM/YY\" />\n </Field>\n <Field label=\"Licence plate\">\n <MaskedInput mask=\"AA-9999\" defaultValue=\"AB12\" />\n </Field>\n <Field label=\"Color\">\n <MaskedInput mask=\"#hhhhhh\" defaultValue=\"3b82f6\" />\n </Field>\n </Grid>\n ),\n}\n\n/** Controlled: the value is the raw characters, without literals. */\nexport const Controlled: Story = {\n render: function Render() {\n const [raw, setRaw] = useState('5551')\n return (\n <Grid container gap={2}>\n <Field label=\"Phone\">\n <MaskedInput mask=\"+1 (999) 999-9999\" value={raw} onValueChange={setRaw} />\n </Field>\n <Text variant=\"p3\" tone=\"muted\">\n Raw value: {raw || '(empty)'}\n </Text>\n </Grid>\n )\n },\n}\n"},{"name":"Menu","category":"Overlays","description":"A menu button, per the WAI-ARIA pattern: the trigger opens a list of\nactions; arrows, Home/End and type-ahead move between them; Enter selects;\nEscape or Tab closes and returns focus. Built on the Popover API.\n\n```tsx\n<Menu trigger={<Button variant=\"outline\">Actions</Button>}>\n <MenuItem onSelect={rename}>Rename</MenuItem>\n <MenuSeparator />\n <MenuItem tone=\"negative\" onSelect={remove}>Delete</MenuItem>\n</Menu>\n```","file":"packages/react/src/components/Menu/Menu.tsx","props":[{"name":"trigger","type":"ReactElement<unknown, string | JSXElementConstructor<any>>","required":true,"description":"The menu button: usually a Button."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when the menu opens or closes."},{"name":"placement","type":"Placement","required":false,"default":"bottom-start","description":"Where the menu opens relative to its trigger. It flips if there's no room."}],"styles":{"className":"greese-Menu","parts":["viewport"],"modifiers":[],"attributes":[],"variables":["--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-motion-popover","--greese-motion-popover-exit-mask-from","--greese-motion-popover-exit-mask-image","--greese-motion-popover-exit-mask-position","--greese-motion-popover-exit-mask-repeat","--greese-motion-popover-exit-mask-size","--greese-motion-popover-exit-opacity","--greese-motion-popover-exit-scale","--greese-motion-popover-exit-transform","--greese-motion-popover-exit-transform-origin","--greese-motion-popover-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Menu, MenuItem, MenuSeparator } from '@greese/react'\n\nconst meta = {\n title: 'Overlays/Menu',\n component: Menu,\n subcomponents: { MenuItem, MenuSeparator },\n args: {\n trigger: <Button variant=\"outline\">Actions</Button>,\n children: (\n <>\n <MenuItem>Rename</MenuItem>\n <MenuItem>Duplicate</MenuItem>\n <MenuItem disabled>Move (no permission)</MenuItem>\n <MenuSeparator />\n <MenuItem tone=\"negative\">Delete</MenuItem>\n </>\n ),\n },\n argTypes: {\n placement: {\n control: 'select',\n options: [\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'top',\n 'top-start',\n 'top-end',\n 'start',\n 'end',\n ],\n },\n },\n} satisfies Meta<typeof Menu>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Arrow keys, Home/End and type-ahead move focus; Escape returns it to the trigger. */\nexport const Playground: Story = {}\n\n/** `asChild` turns an item into a link. */\nexport const WithLinks: Story = {\n args: {\n trigger: <Button variant=\"outline\">Help</Button>,\n children: (\n <>\n <MenuItem asChild>\n <a href=\"#docs\">Documentation</a>\n </MenuItem>\n <MenuItem asChild>\n <a href=\"#support\">Contact support</a>\n </MenuItem>\n </>\n ),\n },\n}\n"},{"name":"MenuItem","category":"Overlays","description":"One action in a Menu. Disabled items stay visible but are skipped by the keyboard.","file":"packages/react/src/components/Menu/Menu.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render a link (`<a>`, a router Link) as the item."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onSelect","type":"(() => void)","required":false,"description":"Called when chosen by click, Enter or Space; the menu then closes."},{"name":"tone","type":"\"negative\" | \"neutral\" | BrandTone","required":false,"default":"neutral","description":"The item's color: `negative` for destructive actions, or a brand color\n(primary, secondary, tertiary) to set one apart."}],"styles":{"className":"greese-MenuItem","parts":[],"modifiers":["accent","negative","primary","secondary","tertiary"],"attributes":["[aria-disabled=true]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Menu, MenuItem } from '@greese/react'\n\n/** One action in a Menu. Open the menu to see it; `asChild` makes it a link. */\nconst meta = {\n title: 'Overlays/MenuItem',\n component: MenuItem,\n args: { children: 'Rename' },\n argTypes: {\n tone: {\n control: 'inline-radio',\n options: ['neutral', 'primary', 'secondary', 'tertiary', 'accent', 'negative'],\n },\n },\n decorators: [\n (Story) => (\n <Menu trigger={<Button variant=\"outline\">Actions</Button>}>\n <Story />\n <MenuItem>Duplicate</MenuItem>\n </Menu>\n ),\n ],\n} satisfies Meta<typeof MenuItem>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Negative: Story = { args: { tone: 'negative', children: 'Delete' } }\n"},{"name":"MenuSeparator","category":"Overlays","description":"A divider between groups of menu items.","file":"packages/react/src/components/Menu/Menu.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-MenuSeparator","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Menu, MenuItem, MenuSeparator } from '@greese/react'\n\n/** A divider between groups of menu items. Open the menu to see it. */\nconst meta = {\n title: 'Overlays/MenuSeparator',\n component: MenuSeparator,\n decorators: [\n (Story) => (\n <Menu trigger={<Button variant=\"outline\">Actions</Button>}>\n <MenuItem>Rename</MenuItem>\n <MenuItem>Duplicate</MenuItem>\n <Story />\n <MenuItem tone=\"negative\">Delete</MenuItem>\n </Menu>\n ),\n ],\n} satisfies Meta<typeof MenuSeparator>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Motion","category":"Motion","description":"The `greese` prop for any element: wrap it, or pass it as the child with\n`asChild`. Every greese ui component already accepts `greese` directly.\n\n```tsx\n<Motion greese=\"fadeUp\"><img src={hero} alt=\"\" /></Motion>\n<Motion asChild greese={{ hover: 'rise' }}><a href=\"/pricing\">Pricing</a></Motion>\n```","file":"packages/react/src/components/Motion/Motion.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Animate your own element instead of a wrapping `<div>`."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-Motion","parts":[],"modifiers":["enter","enter-blur-in","enter-depth","enter-depth-in","enter-fade-down","enter-fade-end","enter-fade-in","enter-fade-start","enter-fade-up","enter-flip-down","enter-flip-left","enter-flip-over-down","enter-flip-over-left","enter-flip-over-right","enter-flip-over-up","enter-flip-right","enter-flip-up","enter-hinge","enter-iris-down","enter-iris-down-left","enter-iris-down-right","enter-iris-in","enter-iris-left","enter-iris-right","enter-iris-up","enter-iris-up-left","enter-iris-up-right","enter-pocket-down","enter-pocket-down-left","enter-pocket-down-right","enter-pocket-left","enter-pocket-right","enter-pocket-up","enter-pocket-up-left","enter-pocket-up-right","enter-pop","enter-pop-in","enter-scale-in","enter-slide-down","enter-slide-left","enter-slide-right","enter-slide-up","enter-swing-in","enter-theme","enter-turn-x","enter-turn-y","enter-wipe-down","enter-wipe-down-left","enter-wipe-down-right","enter-wipe-left","enter-wipe-open-x","enter-wipe-open-y","enter-wipe-right","enter-wipe-up","enter-wipe-up-left","enter-wipe-up-right","exit-blur-out","exit-depth-out","exit-fade-out","exit-fade-out-down","exit-fade-out-up","exit-fall","exit-flip-out-down","exit-flip-out-left","exit-flip-out-right","exit-flip-out-up","exit-flip-over-out-down","exit-flip-over-out-left","exit-flip-over-out-right","exit-flip-over-out-up","exit-glow","exit-iris-out","exit-iris-out-down","exit-iris-out-down-left","exit-iris-out-down-right","exit-iris-out-left","exit-iris-out-right","exit-iris-out-up","exit-iris-out-up-left","exit-iris-out-up-right","exit-pocket-out-down","exit-pocket-out-down-left","exit-pocket-out-down-right","exit-pocket-out-left","exit-pocket-out-right","exit-pocket-out-up","exit-pocket-out-up-left","exit-pocket-out-up-right","exit-pop-out","exit-rise","exit-scale-out","exit-squish","exit-swing-out","exit-tilt","exit-wipe-close-x","exit-wipe-close-y","exit-wipe-out-down","exit-wipe-out-down-left","exit-wipe-out-down-right","exit-wipe-out-left","exit-wipe-out-right","exit-wipe-out-up","exit-wipe-out-up-left","exit-wipe-out-up-right","scope","stagger","view","view-blur-in","view-depth","view-depth-in","view-fade-down","view-fade-end","view-fade-in","view-fade-start","view-fade-up","view-flip-down","view-flip-left","view-flip-over-down","view-flip-over-left","view-flip-over-right","view-flip-over-up","view-flip-right","view-flip-up","view-hinge","view-iris-down","view-iris-down-left","view-iris-down-right","view-iris-in","view-iris-left","view-iris-right","view-iris-up","view-iris-up-left","view-iris-up-right","view-pocket-down","view-pocket-down-left","view-pocket-down-right","view-pocket-left","view-pocket-right","view-pocket-up","view-pocket-up-left","view-pocket-up-right","view-pop","view-pop-in","view-scale-in","view-slide-down","view-slide-left","view-slide-right","view-slide-up","view-swing-in","view-theme","view-turn-x","view-turn-y","view-wipe-down","view-wipe-down-left","view-wipe-down-right","view-wipe-left","view-wipe-open-x","view-wipe-open-y","view-wipe-right","view-wipe-up","view-wipe-up-left","view-wipe-up-right"],"attributes":["[data-greese-scope=pending]","[data-greese-view=in]","[data-greese-view=pending]"],"variables":["--greese-ease-ease","--greese-ease-ease-in","--greese-ease-ease-in-out","--greese-ease-ease-out","--greese-ease-in","--greese-ease-in-out","--greese-ease-linear","--greese-ease-out","--greese-motion-content","--greese-motion-content-duration","--greese-motion-delay","--greese-motion-dir","--greese-motion-distance","--greese-motion-duration","--greese-motion-ease","--greese-motion-enter-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-index","--greese-motion-name","--greese-motion-offset","--greese-motion-scope","--greese-motion-stagger","--greese-motion-theme","--greese-motion-wait"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState, type ReactNode } from 'react'\nimport {\n Badge,\n Button,\n Card,\n Dialog,\n Grid,\n Heading,\n Motion,\n Stack,\n Text,\n defineGreeseEffect,\n type GreeseProp,\n type GreeseEffectName,\n} from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\nimport { Replay } from '../_shared/Replay.tsx'\n\n/**\n * Mounts its child without motion, then with it on each click: for effects\n * that end hidden, so the story's resting state stays the same.\n */\nconst PlayOnClick = ({\n greese,\n children,\n}: {\n greese: GreeseProp\n children: (greese: GreeseProp | undefined) => ReactNode\n}) => {\n const [key, setKey] = useState(0)\n return (\n <Stack gap={4}>\n <div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n tone=\"neutral\"\n onClick={() => setKey((k) => k + 1)}\n >\n Play\n </Button>\n </div>\n <div key={key}>{children(key ? greese : undefined)}</div>\n </Stack>\n )\n}\n\n// Custom effects: define them once, in client code, then use them by name.\n// The augmentation makes the names type-check and autocomplete.\ndeclare module '@greese/react' {\n interface GreeseEffectRegistry {\n wobble: true\n drift: true\n spin: true\n }\n}\n\ndefineGreeseEffect('wobble', {\n keyframes: { rotate: [0, -6, 6, -3, 0] },\n duration: 0.6,\n})\ndefineGreeseEffect('drift', ({ distance }) => ({\n y: [`calc(${distance} * 3)`, '0rem'],\n opacity: [0, 1],\n}))\ndefineGreeseEffect('spin', {\n keyframes: { rotate: [0, 360] },\n duration: 0.8,\n ease: 'inOut',\n})\n\nconst meta = {\n title: 'Motion/greese prop',\n component: Motion,\n args: { greese: 'fadeUp', children: 'Any element, animated with the greese prop' },\n argTypes: {\n greese: {\n control: 'select',\n options: [\n 'fadeIn',\n 'fadeUp',\n 'fadeDown',\n 'fadeStart',\n 'fadeEnd',\n 'scaleIn',\n 'blurIn',\n 'slideUp',\n 'pop',\n 'fadeIn+scaleIn',\n 'fadeUp,wobble',\n 'drift,+0.3,spin',\n ],\n },\n },\n render: (args) => (\n <Replay>\n <Motion\n {...args}\n style={{ padding: '1rem', border: '1px solid var(--greese-color-border)' }}\n />\n </Replay>\n ),\n // The web app's Try it: the example's own helper, in scope.\n} satisfies Meta<typeof Motion>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** `<Motion>` gives any element the prop; every greese ui component has it already. */\nexport const Playground: Story = {}\n\nconst presets: GreeseEffectName[] = [\n 'fadeIn',\n 'fadeUp',\n 'fadeDown',\n 'fadeStart',\n 'fadeEnd',\n 'scaleIn',\n 'blurIn',\n 'slideUp',\n 'pop',\n]\n\n/** Entrance presets played alone are pure CSS: they render on the server and need no JavaScript. */\nexport const Presets: Story = {\n render: () => (\n <Replay>\n <Grid container minChildWidth=\"10rem\" gap={3}>\n {presets.map((preset, i) => (\n <Card key={preset} greese={{ enter: preset, delay: i * 0.05, duration: 0.6 }}>\n <Text weight=\"semibold\">{preset}</Text>\n </Card>\n ))}\n </Grid>\n </Replay>\n ),\n}\n\n/** `stagger` animates the children one after another. */\nexport const Stagger: Story = {\n render: () => (\n <Replay>\n <Stack gap={2} greese={{ enter: 'fadeStart', stagger: 0.06, distance: '2rem' }}>\n {['Design', 'Build', 'Test', 'Ship', 'Celebrate'].map((step) => (\n <Card key={step} variant=\"filled\">\n {step}\n </Card>\n ))}\n </Stack>\n </Replay>\n ),\n}\n\n/**\n * A `scope` orders the entrances inside it, at any depth: each member starts\n * `stagger` seconds after the one before it in the page, and a scope inside a\n * scope takes one place in the outer one.\n */\nexport const Scope: Story = {\n render: () => (\n <Replay>\n <Stack gap={3} greese={{ scope: { stagger: 0.12, delay: 0.1 } }}>\n <Heading level={2} greese={{ enter: 'fadeUp' }}>\n A section that plays in order\n </Heading>\n <Text greese={{ enter: 'fadeUp' }}>\n Each piece declares only its own entrance; the section decides when it starts.\n </Text>\n <Grid\n container\n columns={{ xs: 1, md: 3 }}\n gap={3}\n greese={{ scope: { stagger: 0.06 } }}\n >\n {['One', 'Two', 'Three'].map((n) => (\n <Card key={n} greese={{ enter: 'scaleIn' }}>\n <Stack gap={1}>\n <Heading level={3} variant=\"h6\" greese={{ enter: 'fadeIn' }}>\n Card {n}\n </Heading>\n <Text variant=\"p3\" tone=\"muted\" greese={{ enter: 'fadeIn' }}>\n Starts after the card above it.\n </Text>\n </Stack>\n </Card>\n ))}\n </Grid>\n <Button greese={{ enter: 'pop' }}>Get started</Button>\n </Stack>\n </Replay>\n ),\n}\n\n/**\n * `inView: true` holds a whole scope until it scrolls into view, then plays its\n * entrances in order. Scroll down.\n */\nexport const ScopeInView: Story = {\n render: () => (\n <Stack gap={4}>\n <Text tone=\"muted\">\n Scroll down: the section below plays as one sequence when it arrives.\n </Text>\n <div style={{ blockSize: '70vh' }} />\n <Card greese={{ scope: { stagger: 0.15, inView: true } }}>\n <Stack gap={2}>\n <Heading level={3} variant=\"h5\" greese={{ enter: 'fadeUp' }}>\n Held until in view\n </Heading>\n <Text greese={{ enter: 'fadeUp' }}>\n The scope waits; its members start in order.\n </Text>\n <Stack direction=\"row\" gap={2} greese={{ scope: { stagger: 0.08 } }}>\n {['A', 'B', 'C', 'D'].map((n) => (\n <Badge key={n} greese={{ enter: 'pop' }}>\n {n}\n </Badge>\n ))}\n </Stack>\n </Stack>\n </Card>\n <div style={{ blockSize: '40vh' }} />\n </Stack>\n ),\n}\n\n/** `inView` waits until each card scrolls into view. Scroll down. */\nexport const ScrollReveal: Story = {\n render: () => (\n <Stack gap={4}>\n <Text tone=\"muted\">Scroll down: cards out of view reveal as they arrive.</Text>\n <div style={{ blockSize: '70vh' }} />\n {[1, 2, 3, 4].map((n) => (\n <Card key={n} greese={{ inView: n % 2 ? 'fadeUp' : 'scaleIn' }}>\n <Heading level={3} variant=\"h6\">\n Card {n}\n </Heading>\n </Card>\n ))}\n </Stack>\n ),\n}\n\n/**\n * Compose effects in one string: `+` plays effects together, `,` starts the\n * next group when the previous one ends, and a number is a pause in seconds.\n * Sequences run in greese.js. Under reduced motion each effect is a cut, but\n * pauses still wait.\n */\nexport const Sequences: Story = {\n render: () => (\n <Grid container minChildWidth=\"14rem\" gap={3}>\n {(\n [\n ['fadeIn+scaleIn', 'Together'],\n ['fadeStart,pop', 'One after the other'],\n ['blurIn,+0.4,pop', 'With a pause'],\n ] as const\n ).map(([sequence, label]) => (\n <Replay key={sequence}>\n <Card greese={sequence}>\n <Text weight=\"semibold\">{label}</Text>\n <Text tone=\"muted\" variant=\"p3\">\n <code>{sequence}</code>\n </Text>\n </Card>\n </Replay>\n ))}\n </Grid>\n ),\n}\n\n/** `'fadeIn+scaleIn,+2,fadeOut'`: in together, wait two seconds, fade out (and stay out). */\nexport const InWaitOut: Story = {\n name: 'In, wait, out',\n render: () => (\n <PlayOnClick greese=\"fadeIn+scaleIn,+2,fadeOut\">\n {(greese) => (\n <Card greese={greese}>\n <Text weight=\"semibold\">Saved</Text>\n <Text tone=\"muted\" variant=\"p3\">\n <code>fadeIn+scaleIn,+2,fadeOut</code>\n </Text>\n </Card>\n )}\n </PlayOnClick>\n ),\n}\n\n/**\n * `defineGreeseEffect(name, effect)` adds your own effects: keyframes, a\n * function of `{ el, distance, rtl }` returning keyframes, or\n * `{ keyframes, duration, ease }` with defaults the prop's options override.\n * Names are strings, so Server Components can use them too; define them in\n * client code. This file defines `wobble`, `drift` and `spin`.\n */\nexport const CustomEffects: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} wrap=\"wrap\" align=\"center\">\n <Replay>\n <Card greese=\"fadeUp,wobble\">\n <code>fadeUp,wobble</code>\n </Card>\n </Replay>\n <Replay>\n <Card greese={{ enter: 'drift', distance: '1.5rem' }}>\n <code>drift</code>\n </Card>\n </Replay>\n <Replay>\n <Card greese=\"drift,+0.3,spin\">\n <code>drift,+0.3,spin</code>\n </Card>\n </Replay>\n <Button greese={{ hover: 'wobble', duration: 0.4 }}>Hover: wobble</Button>\n </Stack>\n ),\n}\n\n/** Hover (mouse and pen only), press and focus play and reverse; interrupt them mid-way. */\nexport const Interactions: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} wrap=\"wrap\" align=\"center\">\n <Button greese={{ hover: 'rise', press: 'squish' }}>Lift + squish</Button>\n <Button variant=\"outline\" greese={{ hover: 'tilt' }}>\n Tilt\n </Button>\n <Button variant=\"soft\" greese={{ hover: 'glow', focus: 'rise' }}>\n Glow (focus lifts)\n </Button>\n <Card\n interactive\n greese={{\n hover: {\n y: [0, -6],\n boxShadow: ['0 0 0 transparent', '0 12px 24px rgb(0 0 0 / 0.18)'],\n },\n }}\n >\n Custom keyframes\n </Card>\n </Stack>\n ),\n}\n\n/** Text effects animate a hidden copy; screen readers read the real text once. */\nexport const TextEffects: Story = {\n render: () => (\n <Replay>\n <Stack gap={3}>\n <Heading level={2} greese={{ text: 'split' }}>\n Served fast, everywhere\n </Heading>\n <Text variant=\"s2\" greese={{ text: 'type' }}>\n Typed on, one letter at a time.\n </Text>\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Text variant=\"h3\" weight=\"bold\" greese={{ text: 'count', duration: 1.5 }}>\n 12480\n </Text>\n <Badge tone=\"positive\">orders</Badge>\n </Stack>\n </Stack>\n </Replay>\n ),\n}\n\n/** Overlays play `enter` each time they open and restyle their exit with `exit`. */\nexport const Overlays: Story = {\n render: () => (\n <Dialog\n trigger={<Button>Open</Button>}\n title=\"Pop in, scale out\"\n greese={{ enter: 'pop', exit: 'scaleOut' }}\n >\n <Text>Close it to see the exit.</Text>\n </Dialog>\n ),\n}\n\n/** Full control: fill a greese.js timeline for the element. */\nexport const CustomTimeline: Story = {\n render: () => (\n <Replay>\n <Motion\n asChild\n greese={{\n timeline: (tl, el) =>\n tl\n .from(el, { scale: 0.6, opacity: 0, duration: 0.4, ease: 'back.out(2)' })\n .to(el, { rotate: 8, duration: 0.15 })\n .to(el, { rotate: 0, duration: 0.4, ease: 'elastic.out(1.2, 0.4)' }),\n }}\n >\n <img\n src={art(18, '1 1')}\n alt=\"\"\n width={160}\n height={160}\n style={{ borderRadius: 'var(--greese-radius-lg)' }}\n />\n </Motion>\n </Replay>\n ),\n}\n"},{"name":"NumberField","category":"Forms","description":"A number input with steppers, per the WAI-ARIA spinbutton pattern: a text\ninput (`inputMode=\"decimal\"`, so phones show a number pad) rather than\n`type=\"number\"`, which scrolls values on wheel and mishandles locales.\n\nArrow keys step, Page Up/Down step by `largeStep`, Home/End jump to\n`min`/`max`. Typed values are clamped on blur or Enter; anything that isn't\na number reverts to the last valid value.\n\n```tsx\n<NumberField label=\"Guests\" name=\"guests\" min={1} max={12} defaultValue={2} />\n```","file":"packages/react/src/components/NumberField/NumberField.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The visible label. Required: use `hideLabel` to hide it visually."},{"name":"decrementLabel","type":"string","required":false,"default":"Decrease","description":"Accessible name of the minus button."},{"name":"defaultValue","type":"number | null","required":false,"default":"null","description":"The starting number, when it keeps its own state; `null` for empty."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the input."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks the input invalid."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"incrementLabel","type":"string","required":false,"default":"Increase","description":"Accessible name of the plus button."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"largeStep","type":"number","required":false,"default":"step * 10","description":"Page Up / Page Down move by this."},{"name":"max","type":"number","required":false,"description":"The highest allowed value. Typed values are clamped to it on blur or Enter."},{"name":"min","type":"number","required":false,"description":"The lowest allowed value. Typed values are clamped to it on blur or Enter."},{"name":"onValueChange","type":"((value: number | null) => void)","required":false,"description":"Called with the committed number, or `null` when cleared."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."},{"name":"step","type":"number","required":false,"default":"1","description":"Arrow keys and buttons move by this; values snap to it from `min`."},{"name":"value","type":"number | null","required":false,"description":"The number, when you control it; `null` when empty. Pair with `onValueChange`."}],"styles":{"className":"greese-NumberField","parts":["step","steppers"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { NumberField } from '@greese/react'\n\nconst meta = {\n title: 'Forms/NumberField',\n component: NumberField,\n args: { label: 'Quantity', defaultValue: 1, min: 1, max: 99 },\n decorators: [(Story) => <div style={{ maxInlineSize: '20rem' }}>{Story()}</div>],\n} satisfies Meta<typeof NumberField>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Spinbutton: arrows, Page Up/Down, Home/End. A number pad on phones. */\nexport const Playground: Story = {}\n\nexport const Decimal: Story = {\n args: {\n label: 'Discount',\n description: '0–1 in steps of 0.05',\n defaultValue: 0.1,\n min: 0,\n max: 1,\n step: 0.05,\n },\n}\n"},{"name":"OtpField","category":"Forms","description":"A one-time code, drawn as a box per character. It's one native input\nunderneath (`autocomplete=\"one-time-code\"`), so SMS autofill, paste and\npassword managers work, and screen readers hear a single field. Label it\nwith a Field.\n\n```tsx\n<Field label=\"Verification code\" description=\"We sent it to your phone.\">\n <OtpField onComplete={verify} />\n</Field>\n```","file":"packages/react/src/components/OtpField/OtpField.tsx","props":[{"name":"defaultValue","type":"string","required":false,"default":"","description":"The starting code, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid and outlines the boxes as an error. A surrounding Field's\n`error` sets it too."},{"name":"length","type":"number","required":false,"default":"6","description":"How many characters the code has."},{"name":"mask","type":"boolean","required":false,"description":"Show dots instead of the characters."},{"name":"mode","type":"\"numeric\" | \"alphanumeric\"","required":false,"default":"numeric","description":"Which characters it accepts."},{"name":"onComplete","type":"((value: string) => void)","required":false,"description":"Called once the code is complete, with it."},{"name":"onValueChange","type":"((value: string) => void)","required":false,"description":"Called with the code as it changes, already filtered to the allowed characters."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Size of the boxes: `sm`, `md` or `lg`."},{"name":"value","type":"string","required":false,"description":"The code typed so far, when you control it. Pair with `onValueChange`."}],"styles":{"className":"greese-OtpField","parts":["input","slot"],"modifiers":["size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":["[data-disabled]","[data-invalid]"],"variables":["--greese-otp-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, OtpField } from '@greese/react'\n\nconst meta = {\n title: 'Forms/OtpField',\n component: OtpField,\n args: { length: 6 },\n argTypes: {\n mode: { control: 'inline-radio', options: ['numeric', 'alphanumeric'] },\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },\n },\n render: (args) => (\n <Field label=\"Verification code\" description=\"We sent a 6-digit code to your phone.\">\n <OtpField {...args} />\n </Field>\n ),\n} satisfies Meta<typeof OtpField>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Type, paste, or let the phone fill it in from the SMS. */\nexport const Playground: Story = {}\n\nexport const PartlyFilled: Story = { args: { defaultValue: '204' } }\n\nexport const Masked: Story = { args: { length: 4, mask: true, defaultValue: '12' } }\n\nexport const Invalid: Story = {\n render: (args) => (\n <Field label=\"Verification code\" error=\"That code has expired. We sent a new one.\">\n <OtpField {...args} defaultValue=\"482913\" />\n </Field>\n ),\n}\n\nexport const Alphanumeric: Story = {\n args: { mode: 'alphanumeric', length: 8, size: 'sm', defaultValue: 'K7Q2' },\n}\n"},{"name":"PageShare","category":"Motion","description":"An element that morphs into its twin on the next page in a page transition\n(ADR 0029): the same `id` on both pages, a template's card and its page's\nhero, say. Its group's view-transition class (`greese-share-<group>`) lets a\ntheme or a rule style every template's morph at once. It's named only to\npair: in any other change it moves with the page. With `link` instead of an\n`id`, the link followed decides the pair. A Server Component; it needs\nReact 19.3, and renders its child as it is before that.\n\n```tsx\n<PageShare id={['template', template.id]}>\n <Card>…</Card>\n</PageShare>\n```","file":"packages/react/src/components/PageTransition/PageShare.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The element that morphs: one element, whose box is the one that moves."},{"name":"id","type":"ShareKey","required":false,"description":"What pairs it with its twin on the other page: a key that means the same\nthing on both, `'hero'` or `['template', id]`. Unique on each page. Give\nthis or `link`."},{"name":"link","type":"boolean","required":false,"default":"false","description":"Pairs it by the link followed, with no key: on a list, the item around\nthe link that was clicked; on the page it leads to, the page's hero (its\none `link` element with no link inside). Going back, the hero pairs with\nthe item linking to the page left. Needs `usePageNavigate` for the\nnavigation."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState, type JSX } from 'react'\nimport {\n Button,\n Card,\n Heading,\n PageShare,\n PageTransition,\n Stack,\n Text,\n usePageNavigate,\n} from '@greese/react'\n\nconst TEMPLATES = ['Finance', 'Travel', 'Health'] as const\n\n/**\n * A gallery and a page, with a router of the story's own: the open template\n * is state. Each card and its page's hero share an id, so one morphs into\n * the other.\n */\nconst Gallery = (): JSX.Element => {\n const [open, setOpen] = useState<string>()\n const page = usePageNavigate((to) => {\n if (typeof to === 'string') setOpen(to.slice(1) || undefined)\n })\n // One URL: a navigation here is its own type, `story`, played as a page change.\n const go = (id = '') => page.navigate(`#${id}`, { types: ['story'] })\n return (\n <PageTransition types={{ story: {} }}>\n {open ? (\n <Stack gap={4}>\n <PageShare id={['template', open]}>\n <Card p={6}>\n <Heading level={2} variant=\"h2\">\n {open}\n </Heading>\n </Card>\n </PageShare>\n <Text>The {open} template, opened.</Text>\n <Button variant=\"soft\" onClick={() => go()}>\n All templates\n </Button>\n </Stack>\n ) : (\n <Stack direction=\"row\" gap={3}>\n {TEMPLATES.map((name) => (\n <PageShare key={name} id={['template', name]}>\n <Card p={4} interactive asChild>\n <button type=\"button\" onClick={() => go(name)}>\n {name}\n </button>\n </Card>\n </PageShare>\n ))}\n </Stack>\n )}\n </PageTransition>\n )\n}\n\nconst meta = {\n title: 'Motion/PageShare',\n component: PageShare,\n args: { id: ['template', 'Finance'], children: null },\n parameters: { layout: 'padded' },\n render: () => <Gallery />,\n} satisfies Meta<typeof PageShare>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * Open a template: its card morphs into the page's hero, and back. Where the\n * browser has no view transitions, and under reduced motion, the page simply\n * changes.\n */\nexport const Playground: Story = {}\n"},{"name":"PageTransition","category":"Motion","description":"Animates page changes (ADR 0029): the old page leaves and the new one\narrives, played by the browser on snapshots of both, with greese's effects.\nPut it around a router's outlet, and navigate with `usePageNavigate`, which\nsays which way a navigation goes. Anything else that updates the page (a\ntab kept in the URL) changes it in place. Without a motion theme it's a\ncross-fade; under reduced motion, and where the browser has no view\ntransitions (or React is older than 19.3), the page simply changes.\n\nA Server Component: everything it takes is data.\n\n```tsx\n<PageTransition back={{ enter: 'slideRight', exit: 'fadeOut' }} rules={{ 'header, footer': 'still' }}>\n <Outlet />\n</PageTransition>\n```","file":"packages/react/src/components/PageTransition/PageTransition.tsx","props":[{"name":"back","type":"{ enter?: PageEffect; exit?: PageEffect | PageTimeline; } | undefined","required":false,"description":"Going back (in the history, or up the URL): what changes from `enter` and\n`exit`. Where a side follows the theme, it plays the theme's back roles."},{"name":"children","type":"ReactNode","required":false,"description":"The page: a router's outlet, or the routes themselves."},{"name":"enter","type":"PageEffect","required":false,"default":"'theme'","description":"How the new page arrives."},{"name":"exit","type":"PageEffect | PageTimeline","required":false,"default":"'theme'","description":"How the old page leaves: an effect (played on its snapshot, or on its\nmembers when it leaves live), or a timeline, a sequence or a map of\nselector → sequence, which greese.js plays on the live page."},{"name":"mode","type":"\"auto\" | \"snapshot\" | \"live\"","required":false,"default":"'auto'","description":"`snapshot`: the browser animates images of both pages. `live`: the old\npage's members (its elements with greese entrances) play their exits on\nthe real page, one after another, while the next page loads; then the new\npage arrives as in a snapshot, over what the exit left of the old one. `auto` leaves live when the page has members on\nscreen or a timeline, and as a snapshot otherwise. The theme's\n`page-mode` decides when this doesn't."},{"name":"name","type":"string","required":false,"default":"'auto'","description":"The boundary's view-transition name, for one `PageTransition` inside\nanother (a layout's and a page's)."},{"name":"order","type":"\"document\" | \"reverse\" | \"together\"","required":false,"default":"'reverse'","description":"The order a live page's members leave in: `reverse` (the last first, so\nthe page empties back towards its top), `document` or `together`."},{"name":"rules","type":"Record<string, PageRule>","required":false,"description":"Parts of the page with motion of their own, by selector: `'still'` keeps\nthem in place (a header the change leaves alone), or their own `enter`,\n`exit`, `duration`, `delay` and `ease`. Each match is a snapshot of its\nown, so name sections, not every item of a long list."},{"name":"stagger","type":"number","required":false,"description":"Seconds between a live page's members (the theme's `page-stagger`)."},{"name":"types","type":"Record<string, \"none\" | PageMotion>","required":false,"description":"Transition types of your own (added with `usePageNavigate`'s `types`, or\nReact's `addTransitionType`): how each plays, or `'none'`."}],"styles":{"className":"greese-PageTransition","parts":[],"modifiers":["enter-blur-in","enter-depth","enter-depth-in","enter-fade-down","enter-fade-end","enter-fade-in","enter-fade-start","enter-fade-up","enter-flip-down","enter-flip-left","enter-flip-over-down","enter-flip-over-left","enter-flip-over-right","enter-flip-over-up","enter-flip-right","enter-flip-up","enter-hinge","enter-iris-down","enter-iris-down-left","enter-iris-down-right","enter-iris-in","enter-iris-left","enter-iris-right","enter-iris-up","enter-iris-up-left","enter-iris-up-right","enter-none","enter-pocket-down","enter-pocket-down-left","enter-pocket-down-right","enter-pocket-left","enter-pocket-right","enter-pocket-up","enter-pocket-up-left","enter-pocket-up-right","enter-pop","enter-pop-in","enter-scale-in","enter-slide-down","enter-slide-left","enter-slide-right","enter-slide-up","enter-swing-in","enter-turn-x","enter-turn-y","enter-wipe-down","enter-wipe-down-left","enter-wipe-down-right","enter-wipe-left","enter-wipe-open-x","enter-wipe-open-y","enter-wipe-right","enter-wipe-up","enter-wipe-up-left","enter-wipe-up-right","exit-blur-out","exit-depth-out","exit-fade-out","exit-fade-out-down","exit-fade-out-up","exit-fall","exit-flip-out-down","exit-flip-out-left","exit-flip-out-right","exit-flip-out-up","exit-flip-over-out-down","exit-flip-over-out-left","exit-flip-over-out-right","exit-flip-over-out-up","exit-glow","exit-iris-out","exit-iris-out-down","exit-iris-out-down-left","exit-iris-out-down-right","exit-iris-out-left","exit-iris-out-right","exit-iris-out-up","exit-iris-out-up-left","exit-iris-out-up-right","exit-none","exit-pocket-out-down","exit-pocket-out-down-left","exit-pocket-out-down-right","exit-pocket-out-left","exit-pocket-out-right","exit-pocket-out-up","exit-pocket-out-up-left","exit-pocket-out-up-right","exit-pop-out","exit-rise","exit-scale-out","exit-squish","exit-swing-out","exit-tilt","exit-wipe-close-x","exit-wipe-close-y","exit-wipe-out-down","exit-wipe-out-down-left","exit-wipe-out-down-right","exit-wipe-out-left","exit-wipe-out-right","exit-wipe-out-up","exit-wipe-out-up-left","exit-wipe-out-up-right","left","page","route-enter","route-exit","route-pace","share","still","theme","theme-back"],"attributes":[],"variables":["--greese-ease-out","--greese-motion-distance","--greese-motion-page","--greese-motion-page-back","--greese-motion-page-back-exit","--greese-motion-page-duration","--greese-motion-page-ease","--greese-motion-page-exit","--greese-motion-share-duration","--greese-motion-share-ease","--greese-page-duration","--greese-page-ease","--greese-page-enter","--greese-page-exit","--greese-page-scrolled"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState, type JSX } from 'react'\nimport {\n Button,\n Card,\n Heading,\n PageTransition,\n Stack,\n Text,\n usePageNavigate,\n type PageEffect,\n type PageTransitionProps,\n} from '@greese/react'\n\nconst PAGES = ['Overview', 'Pricing', 'Contact'] as const\n\n/**\n * A router of the story's own: the page is state. In an app, hand\n * `usePageNavigate` your router's navigate (React Router's `useNavigate()`).\n */\nconst Pages = (props: Omit<PageTransitionProps, 'children'>): JSX.Element => {\n const [index, setIndex] = useState(0)\n const page = usePageNavigate((to) => {\n if (typeof to === 'string') setIndex(Number(to.slice(1)))\n })\n // The story stays on one URL, so a navigation here is its own type,\n // `story`, which the PageTransition below plays like a page change, and\n // says it's a page change (`greese-page`), so a live page leaves live.\n const go = (i: number) => page.navigate(`#${i}`, { types: ['greese-page', 'story'] })\n return (\n <Stack gap={4}>\n <Stack direction=\"row\" gap={2}>\n {PAGES.map((name, i) => (\n <Button\n key={name}\n size=\"sm\"\n variant={i === index ? 'solid' : 'soft'}\n aria-current={i === index ? 'page' : undefined}\n onClick={() => go(i)}\n >\n {name}\n </Button>\n ))}\n </Stack>\n <PageTransition\n {...props}\n types={{ story: { enter: props.enter, exit: props.exit as PageEffect } }}\n >\n {props.mode === 'live' ? (\n // Live: each card has a greese entrance, which makes it a member;\n // members leave one after another (the last first), then the next\n // page's play their entrances.\n <Stack gap={3}>\n {[1, 2, 3].map((n) => (\n <Card key={`${index}-${n}`} p={4} greese=\"fadeUp\">\n <Text>\n {PAGES[index]}, part {n}\n </Text>\n </Card>\n ))}\n </Stack>\n ) : (\n <Card p={5}>\n <Heading level={2} variant=\"h3\">\n {PAGES[index]}\n </Heading>\n <Text tone=\"muted\">\n Page {index + 1} of {PAGES.length}. Pick another to see this one leave and\n the next arrive.\n </Text>\n </Card>\n )}\n </PageTransition>\n </Stack>\n )\n}\n\nconst meta = {\n title: 'Motion/PageTransition',\n component: PageTransition,\n args: { enter: 'theme', exit: 'theme' },\n argTypes: {\n enter: {\n control: 'select',\n options: ['theme', 'none', 'fadeUp', 'popIn', 'slideLeft', 'wipeRight', 'pocketUp'],\n },\n exit: {\n control: 'select',\n options: [\n 'theme',\n 'none',\n 'fadeOut',\n 'scaleOut',\n 'fadeOutUp',\n 'wipeOutLeft',\n 'pocketOutDown',\n ],\n },\n },\n parameters: { layout: 'padded' },\n render: (args) => <Pages {...args} />,\n} satisfies Meta<typeof PageTransition>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * Pick a page: the old one leaves and the new one arrives, as the motion\n * theme says unless you name effects. Where the browser has no view\n * transitions, and under reduced motion, the page simply changes.\n */\nexport const Playground: Story = {}\n\n/** The old page scales out and the new one pops in. */\nexport const NamedEffects: Story = {\n args: { enter: 'popIn', exit: 'scaleOut' },\n}\n\n/** Pockets: the old page sinks into a slot and the new one rises out of it. */\nexport const Pockets: Story = {\n args: { enter: 'pocketUp', exit: 'pocketOutDown' },\n}\n\n/**\n * Live: the page's cards leave on the real page, the last first, while the\n * next page loads; then the next page's cards play their entrances.\n */\nexport const Live: Story = {\n args: { mode: 'live', stagger: 0.08 },\n}\n"},{"name":"Pagination","category":"Navigation","description":"Page navigation. On phones it condenses to previous / current / next; from\n`sm` it shows the full range.\n\n```tsx\n<Pagination count={20} page={page} getHref={(page) => `?page=${page}`} />\n```\n\nLinks with a controlled `page` render from a Server Component; buttons,\nor links that track their own page, are a client component.","file":"packages/react/src/components/Pagination/Pagination.tsx","props":[{"name":"count","type":"number","required":true,"description":"Total pages."},{"name":"boundaries","type":"number","required":false,"default":"1","description":"How many page numbers to always show at the start and the end."},{"name":"defaultPage","type":"number","required":false,"default":"1","description":"The page shown first, when it keeps its own state."},{"name":"getHref","type":"((page: number) => string)","required":false,"description":"Render real links, e.g. `(page) => \\`?page=${page}\\``: crawlable, and they\nwork without JS. Without it, pages are buttons. With `page` as well (read\nfrom the URL, say), it's a Server Component and ships no JavaScript."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"'Pagination'","description":"Names the navigation landmark for screen readers."},{"name":"labels","type":"{ previous?: string; next?: string; page?: ((page: number) => string) | undefined; } | undefined","required":false,"default":"{ previous: 'Previous page', next: 'Next page', page: (n) => `Page ${n}` }","description":"Accessible names for the previous and next buttons and each page, for\ntranslation."},{"name":"onPageChange","type":"((page: number) => void)","required":false,"description":"Called with the new page number when the user picks one."},{"name":"page","type":"number","required":false,"description":"The current page, from 1, when you control it. Pair with `onPageChange`."},{"name":"siblings","type":"number","required":false,"default":"1","description":"How many page numbers to show on each side of the current one."}],"styles":{"className":"greese-Pagination","parts":["ellipsis","list","page","step"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Pagination } from '@greese/react'\n\nconst meta = {\n title: 'Navigation/Pagination',\n component: Pagination,\n args: { count: 20, defaultPage: 8 },\n} satisfies Meta<typeof Pagination>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Condenses to previous / current / next on phones. */\nexport const Playground: Story = {}\n\n/** `getHref` renders real, crawlable links that work without JavaScript. */\nexport const Links: Story = { args: { getHref: (page) => `#page-${page}` } }\n\nexport const FewPages: Story = { args: { count: 5, defaultPage: 1 } }\n"},{"name":"Popover","category":"Overlays","description":"Non-modal floating content anchored to a trigger, on the native Popover\nAPI: top layer, click-outside and Escape to close, and Tab order that flows\nfrom the trigger into the content. Positioned by CSS anchor positioning.\n\n```tsx\n<Popover trigger={<Button variant=\"outline\">Filters</Button>} label=\"Filters\">\n …\n</Popover>\n```","file":"packages/react/src/components/Popover/Popover.tsx","props":[{"name":"trigger","type":"ReactElement<unknown, string | JSXElementConstructor<any>>","required":true,"description":"The element that toggles it: usually a Button."},{"name":"defaultOpen","type":"boolean","required":false,"default":"false","description":"Whether it starts open, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"description":"Accessible name for the popover, if its content has no heading."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes (the trigger, Escape, a\nclick outside)."},{"name":"open","type":"boolean","required":false,"description":"Whether it's open, when you control it. Pair with `onOpenChange`."},{"name":"placement","type":"Placement","required":false,"default":"bottom-start","description":"Where it opens relative to its trigger. It flips if there's no room."}],"styles":{"className":"greese-Popover","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-motion-popover","--greese-motion-popover-exit-mask-from","--greese-motion-popover-exit-mask-image","--greese-motion-popover-exit-mask-position","--greese-motion-popover-exit-mask-repeat","--greese-motion-popover-exit-mask-size","--greese-motion-popover-exit-opacity","--greese-motion-popover-exit-scale","--greese-motion-popover-exit-transform","--greese-motion-popover-exit-transform-origin","--greese-motion-popover-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Popover, Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Overlays/Popover',\n component: Popover,\n args: {\n trigger: <Button variant=\"outline\">Details</Button>,\n label: 'Project details',\n placement: 'bottom-start',\n children: (\n <Stack gap={2}>\n <Text weight=\"semibold\">Greese UI</Text>\n <Text variant=\"p3\" tone=\"muted\">\n Created 17 October 2026. Popovers close on Escape or a click outside.\n </Text>\n </Stack>\n ),\n },\n argTypes: {\n placement: {\n control: 'select',\n options: [\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'top',\n 'top-start',\n 'top-end',\n 'start',\n 'end',\n ],\n },\n },\n} satisfies Meta<typeof Popover>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Popover API + CSS anchor positioning: flips when there is no room. */\nexport const Playground: Story = {}\n"},{"name":"Progress","category":"Content","description":"A native `<progress>` bar: announced with its percentage. Label it with\na Field, `aria-label` or `aria-labelledby`.\n\n```tsx\n<Progress value={40} aria-label=\"Uploading\" />\n<Progress value={40} loading aria-label=\"Uploading\" />\n```","file":"packages/react/src/components/Progress/Progress.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"loading","type":"boolean","required":false,"description":"Still working on it: the filled part runs with diagonal stripes in the\nbar's two colors (still under reduced motion), and the bar is\n`aria-busy`. For a known value that's being updated; leave `value` out\nwhen there's no value at all."},{"name":"max","type":"number","required":false,"default":"100","description":"The value that means complete."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Bar thickness, from the shared control sizes."},{"name":"value","type":"number","required":false,"description":"Omit for an indeterminate (unknown duration) bar."}],"styles":{"className":"greese-Progress","parts":[],"modifiers":["lg","loading","md","sm","xl","xs"],"attributes":[],"variables":["--greese-progress-height","--greese-progress-stripes","--greese-progress-tile"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Progress } from '@greese/react'\n\nconst meta = {\n title: 'Content/Progress',\n component: Progress,\n args: { 'aria-label': 'Upload', value: 64 },\n decorators: [(Story) => <div style={{ maxInlineSize: '24rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Progress>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** A native progress bar, announced with its percentage. */\nexport const Playground: Story = {}\n\n/** No `value`: an indeterminate sweep. */\nexport const Indeterminate: Story = {\n args: { value: undefined, 'aria-label': 'Processing' },\n}\n\n/**\n * `loading`: a value that's still being worked on. The filled part runs with\n * stripes in the bar's two colors (they hold still under reduced motion), and\n * the bar is `aria-busy`.\n */\nexport const Loading: Story = { args: { loading: true, size: 'lg' } }\n\nexport const Small: Story = { args: { size: 'sm' } }\n"},{"name":"RadialProgress","category":"Content","description":"Progress as a ring, with the percentage in the middle. A\n`role=\"progressbar\"`: name it with `aria-label` or `aria-labelledby`.\n\n```tsx\n<RadialProgress value={72} aria-label=\"Storage used\" />\n```","file":"packages/react/src/components/RadialProgress/RadialProgress.tsx","props":[{"name":"children","type":"ReactNode","required":false,"description":"In the centre. Defaults to the percentage; `null` shows nothing."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"max","type":"number","required":false,"default":"100","description":"The value that means complete."},{"name":"size","type":"string","required":false,"default":"'4rem'","description":"Diameter, any CSS length."},{"name":"thickness","type":"string","required":false,"default":"'10%' of the size","description":"Ring width, any CSS length."},{"name":"value","type":"number","required":false,"description":"Omit for an indeterminate (unknown duration) spinner-like ring."}],"styles":{"className":"greese-RadialProgress","parts":["label"],"modifiers":["indeterminate"],"attributes":[],"variables":["--greese-radialprogress-angle","--greese-radialprogress-size","--greese-radialprogress-thickness","--greese-radialprogress-value"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { RadialProgress, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/RadialProgress',\n component: RadialProgress,\n args: { value: 72, 'aria-label': 'Storage used' },\n argTypes: { value: { control: { type: 'range', min: 0, max: 100 } } },\n} satisfies Meta<typeof RadialProgress>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const Sizes: Story = {\n render: () => (\n <Stack direction=\"row\" gap={4} align=\"center\" wrap=\"wrap\">\n <RadialProgress value={25} size=\"2.5rem\" aria-label=\"Small\" />\n <RadialProgress value={50} aria-label=\"Default\" />\n <RadialProgress value={90} size=\"6rem\" thickness=\"6%\" aria-label=\"Large, thin\" />\n <RadialProgress value={3} max={4} size=\"5rem\" aria-label=\"Steps done\">\n 3 / 4\n </RadialProgress>\n </Stack>\n ),\n}\n\n/** No value: an indeterminate ring (still under reduced motion). */\nexport const Indeterminate: Story = {\n args: { value: undefined, 'aria-label': 'Loading' },\n}\n"},{"name":"Radio","category":"Forms","description":"A native radio, styled. Use inside RadioGroup, which supplies the shared\n`name`, so arrow keys move the selection as the platform expects.","file":"packages/react/src/components/Radio/Radio.tsx","props":[{"name":"value","type":"string","required":true,"description":"Submitted with the form and reported by the group when chosen."},{"name":"description","type":"ReactNode","required":false,"description":"A muted line under the label, announced with it."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid and colors it as an error. The group's `error` sets it too."},{"name":"label","type":"ReactNode","required":false,"description":"The visible label, beside the radio."}],"styles":{"className":"greese-Radio","parts":["input"],"modifiers":[],"attributes":["[aria-invalid=true]","[data-disabled]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Radio, RadioGroup } from '@greese/react'\n\n/** One choice of a RadioGroup: a native radio with its label and description. */\nconst meta = {\n title: 'Forms/Radio',\n component: Radio,\n args: { value: 'pro', label: 'Pro', description: 'For individuals' },\n decorators: [\n (Story) => (\n <RadioGroup label=\"Plan\" defaultValue=\"pro\">\n <Radio value=\"free\" label=\"Free\" description=\"For trying things out\" />\n <Story />\n </RadioGroup>\n ),\n ],\n} satisfies Meta<typeof Radio>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The second radio, selected. */\nexport const Playground: Story = {}\n\nexport const Disabled: Story = {\n args: {\n value: 'team',\n label: 'Team',\n description: 'Not on this account',\n disabled: true,\n },\n}\n"},{"name":"RadioGroup","category":"Forms","description":"A labelled set of radios (`<fieldset>` + `<legend>`), one selectable.\n\n```tsx\n<RadioGroup label=\"Plan\" defaultValue=\"pro\" direction={{ xs: 'column', md: 'row' }}>\n <Radio value=\"free\" label=\"Free\" />\n <Radio value=\"pro\" label=\"Pro\" />\n</RadioGroup>\n```","file":"packages/react/src/components/Radio/Radio.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The group's name, rendered as the `<legend>`."},{"name":"defaultValue","type":"string","required":false,"description":"The value chosen at first, when the group keeps its own state."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the group."},{"name":"direction","type":"Responsive<StackDirection>","required":false,"default":"'column'","description":"Layout of the choices."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks every choice invalid."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"default":"3","description":"Space between the choices: a scale token (`0`–`8`) or any CSS length, per\nbreakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Marks every choice invalid without showing an error message."},{"name":"name","type":"string","required":false,"description":"Shared `name`; generated when omitted."},{"name":"onValueChange","type":"((value: string) => void)","required":false,"description":"Called with the newly chosen value."},{"name":"required","type":"boolean","required":false,"description":"Shows the required marker."},{"name":"value","type":"string","required":false,"description":"The chosen value, when you control it. Pair with `onValueChange`."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Radio, RadioGroup } from '@greese/react'\n\nconst meta = {\n title: 'Forms/RadioGroup',\n component: RadioGroup,\n subcomponents: { Radio },\n args: {\n label: 'Plan',\n defaultValue: 'pro',\n children: (\n <>\n <Radio value=\"free\" label=\"Free\" description=\"For trying things out\" />\n <Radio value=\"pro\" label=\"Pro\" description=\"For individuals\" />\n <Radio value=\"team\" label=\"Team\" description=\"Billed per seat\" />\n </>\n ),\n },\n} satisfies Meta<typeof RadioGroup>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native radios: arrow keys move the selection. */\nexport const Playground: Story = {}\n\nexport const Horizontal: Story = { args: { direction: { xs: 'column', md: 'row' } } }\n\nexport const WithError: Story = {\n args: { error: 'The Team plan needs 3 or more seats.' },\n}\n"},{"name":"Rating","category":"Forms","description":"A star rating on native radios: arrow keys change it and it submits with\nforms. Whole, half or quarter stars (`step`); pointing previews a choice\nand dragging scrubs, on touch too. `readOnly` displays any value exactly.\n\n```tsx\n<Rating label=\"Your rating\" step={0.5} defaultValue={3.5} onValueChange={save} />\n<Rating label=\"Average\" readOnly value={4.3} />\n```","file":"packages/react/src/components/Rating/Rating.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"Names the rating (\"Your rating\"). Hidden visually unless `hideLabel={false}`."},{"name":"allowClear","type":"boolean","required":false,"default":"false","description":"Choosing the current rating again clears it to 0."},{"name":"defaultValue","type":"number","required":false,"default":"0","description":"The rating at first, when it keeps its own state. 0 is none."},{"name":"getItemLabel","type":"((value: number, max: number) => string)","required":false,"default":"(n: number) => `${n} star${n === 1 ? '' : 's'}`","description":"How each choice is read: `(n, max) => \"3.5 stars\"`."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"default":"true","description":"Keep the label for screen readers but hide it on screen."},{"name":"icon","type":"ReactNode","required":false,"default":"<StarFilledIcon />","description":"Replaces the star. Filled with `currentColor`."},{"name":"max","type":"number","required":false,"default":"5","description":"How many stars."},{"name":"name","type":"string","required":false,"description":"Shared `name` for form submission; generated when omitted."},{"name":"onValueChange","type":"((value: number) => void)","required":false,"description":"Called with the new rating when the user chooses one (0 when cleared)."},{"name":"readOnly","type":"boolean","required":false,"description":"Show a value, not ask for one: an image named \"3.5 out of 5\"."},{"name":"required","type":"boolean","required":false,"description":"A rating must be chosen before the form submits."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Star size: `sm`, `md` or `lg`. On touch screens the row is at least 44px tall."},{"name":"step","type":"1 | 0.5 | 0.25","required":false,"default":"1","description":"The smallest choice: whole stars, halves or quarters. Arrow keys move by\nit, and pointing or dragging snaps to it."},{"name":"value","type":"number","required":false,"description":"The rating, when you control it: 0 is none. Read-only ratings take any fraction (4.3)."}],"styles":{"className":"greese-Rating","parts":["choice","choices","empty","filled","icon","input","items","stars"],"modifiers":["lg","md","sm","xl","xs"],"attributes":[],"variables":["--greese-rating-fill","--greese-rating-off","--greese-rating-on","--greese-rating-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Rating, Stack, Text } from '@greese/react'\nimport { HeartIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/Rating',\n component: Rating,\n args: { label: 'Your rating', defaultValue: 3 },\n argTypes: {\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },\n step: { control: 'inline-radio', options: [1, 0.5, 0.25] },\n },\n} satisfies Meta<typeof Rating>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native radios: hover to preview, click or arrow keys to choose. */\nexport const Playground: Story = {}\n\n/** Half stars: point or drag to choose; arrow keys move by a half. */\nexport const Halves: Story = { args: { step: 0.5, defaultValue: 3.5 } }\n\n/** Quarter stars. On touch, drag across the stars and lift to choose. */\nexport const Quarters: Story = { args: { step: 0.25, defaultValue: 3.75, size: 'lg' } }\n\n/** Choosing the current rating again clears it. */\nexport const Clearable: Story = { args: { allowClear: true, hideLabel: false } }\n\n/** A value to show, not ask for: fractions are drawn exactly. */\nexport const ReadOnly: Story = {\n render: () => (\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Rating label=\"Average rating\" readOnly value={4.3} size=\"sm\" />\n <Text variant=\"p3\" tone=\"muted\">\n 4.3 (1,204 reviews)\n </Text>\n </Stack>\n ),\n}\n\nexport const TenHearts: Story = {\n args: {\n max: 10,\n defaultValue: 7,\n size: 'sm',\n icon: <HeartIcon fill=\"currentColor\" strokeWidth={0} />,\n getItemLabel: (n: number, max: number) => `${n} out of ${max}`,\n },\n}\n"},{"name":"ScrollSpy","category":"Navigation","description":"Marks the link to the section the page is scrolled to: every same-page\n`#id` link inside gets `aria-current=\"location\"` while its section is\ncurrent, so a table of contents or a header's links follow the reader.\nThe links can be anywhere inside, from any router. Sections that scroll\nin a panel of their own are measured from the panel's top.\n\n```tsx\n<ScrollSpy asChild offset={80}>\n <nav aria-label=\"Sections\">\n <a href=\"#install\">Install</a>\n <a href=\"#usage\">Usage</a>\n </nav>\n</ScrollSpy>\n```","file":"packages/react/src/components/ScrollSpy/ScrollSpy.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your element (a `nav`, a list) instead of a div."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"offset","type":"number","required":false,"description":"How far below the top of the viewport (or of the box the sections scroll\nin), in pixels, a section has to start to be the current one: a sticky\nheader's height, plus a little. Defaults to a third of that height."},{"name":"onActiveChange","type":"((id: string) => void)","required":false,"description":"Called with the id of the section the page is on, or undefined above the first."}],"styles":{"className":"greese-ScrollSpy","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Link, ScrollSpy, Stack, Text } from '@greese/react'\n\nconst sections = [\n ['spy-install', 'Install'],\n ['spy-usage', 'Usage'],\n ['spy-theming', 'Theming'],\n] as const\n\nconst PANEL = {\n blockSize: '24rem',\n overflowY: 'auto',\n // Links scroll their section to just under the sticky links.\n scrollPaddingBlockStart: '3.5rem',\n border: '1px solid var(--greese-color-border)',\n borderRadius: 'var(--greese-corner-surface)',\n} as const\n\nconst STICKY_NAV = {\n position: 'sticky',\n insetBlockStart: 0,\n zIndex: 1,\n padding: 'var(--greese-space-3) var(--greese-space-4)',\n backgroundColor: 'var(--greese-color-surface-overlay)',\n borderBlockEnd: '1px solid var(--greese-color-border)',\n} as const\n\nconst meta = {\n title: 'Navigation/ScrollSpy',\n component: ScrollSpy,\n args: {\n asChild: true,\n offset: 80,\n children: (\n <nav aria-label=\"On this page\" style={STICKY_NAV}>\n <Stack direction=\"row\" gap={4}>\n {sections.map(([id, label]) => (\n <Link key={id} href={`#${id}`} tone=\"neutral\">\n {label}\n </Link>\n ))}\n </Stack>\n </nav>\n ),\n },\n // A panel that scrolls on its own, so the links stay in view while the\n // sections go by, wherever the story is shown.\n decorators: [\n (Story) => (\n <div style={PANEL}>\n <Story />\n <Stack gap={4} p={4}>\n {sections.map(([id, label]) => (\n <section key={id} id={id} style={{ minBlockSize: '18rem' }}>\n <Text variant=\"s2\" weight=\"semibold\">\n {label}\n </Text>\n <Text tone=\"muted\">\n Scroll the panel: the link to this section lights up.\n </Text>\n </section>\n ))}\n </Stack>\n </div>\n ),\n ],\n} satisfies Meta<typeof ScrollSpy>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/**\n * Same-page `#id` links inside get `aria-current=\"location\"` while their\n * section is current: the last one whose top is above `offset`, measured from\n * the top of the page, or of the panel the sections scroll in, as here.\n */\nexport const Playground: Story = {}\n"},{"name":"Segment","category":"Forms","description":"One option of a SegmentedControl.","file":"packages/react/src/components/SegmentedControl/SegmentedControl.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The segment's label: text, an icon, or both."},{"name":"value","type":"string","required":true,"description":"Submitted with the form and reported by the control when chosen."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-Segment","parts":["input","label"],"modifiers":[],"attributes":[],"variables":["--greese-segment-current-bg","--greese-segment-current-edge","--greese-segment-height"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Segment, SegmentedControl } from '@greese/react'\n\n/** One option of a SegmentedControl: a native radio underneath. */\nconst meta = {\n title: 'Forms/Segment',\n component: Segment,\n args: { value: 'grid', children: 'Grid' },\n decorators: [\n (Story) => (\n <SegmentedControl label=\"View\" defaultValue=\"list\">\n <Segment value=\"list\">List</Segment>\n <Story />\n <Segment value=\"board\">Board</Segment>\n </SegmentedControl>\n ),\n ],\n} satisfies Meta<typeof Segment>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The middle segment; List is selected. */\nexport const Playground: Story = {}\n\nexport const Disabled: Story = {\n args: { value: 'table', children: 'Table', disabled: true },\n}\n"},{"name":"SegmentedControl","category":"Forms","description":"A compact single choice between a few options, e.g. List / Grid. Built on\nnative radios, so arrow keys move the selection and it submits with forms.\n\n```tsx\n<SegmentedControl label=\"View\" defaultValue=\"list\">\n <Segment value=\"list\">List</Segment>\n <Segment value=\"grid\">Grid</Segment>\n</SegmentedControl>\n```","file":"packages/react/src/components/SegmentedControl/SegmentedControl.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"Names the group for assistive tech. Hidden visually unless `hideLabel={false}`."},{"name":"defaultValue","type":"string","required":false,"description":"The segment chosen at first, when it keeps its own state."},{"name":"fullWidth","type":"boolean","required":false,"description":"Stretch to the container's width, segments sharing it equally."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"default":"true","description":"Keep the label for screen readers but hide it on screen."},{"name":"name","type":"string","required":false,"description":"Shared `name` for form submission; generated when omitted."},{"name":"onValueChange","type":"((value: string) => void)","required":false,"description":"Called with the newly chosen segment's value."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height and text size: `sm` or `md`."},{"name":"value","type":"string","required":false,"description":"The chosen segment's value, when you control it. Pair with `onValueChange`."}],"styles":{"className":"greese-SegmentedControl","parts":["track"],"modifiers":["full","size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":[],"variables":["--greese-button-height","--greese-button-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Segment, SegmentedControl } from '@greese/react'\n\nconst meta = {\n title: 'Forms/SegmentedControl',\n component: SegmentedControl,\n subcomponents: { Segment },\n args: {\n label: 'View',\n defaultValue: 'list',\n children: (\n <>\n <Segment value=\"list\">List</Segment>\n <Segment value=\"grid\">Grid</Segment>\n <Segment value=\"board\">Board</Segment>\n </>\n ),\n },\n} satisfies Meta<typeof SegmentedControl>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native radios underneath: arrow keys move the selection. */\nexport const Playground: Story = {}\n\nexport const VisibleLabelSmall: Story = {\n args: {\n label: 'Range',\n hideLabel: false,\n size: 'sm',\n defaultValue: '7d',\n children: (\n <>\n <Segment value=\"24h\">24h</Segment>\n <Segment value=\"7d\">7 days</Segment>\n <Segment value=\"30d\">30 days</Segment>\n <Segment value=\"all\" disabled>\n All time\n </Segment>\n </>\n ),\n },\n}\n\nexport const FullWidth: Story = { args: { fullWidth: true } }\n"},{"name":"Select","category":"Forms","description":"A native `<select>`: the platform picker on phones, full keyboard support,\nautofill. Options are plain `<option>` / `<optgroup>` children. `className`\nand `style` go to the frame; the rest to the select.\n\n```tsx\n<Field label=\"Country\">\n <Select name=\"country\" placeholder=\"Choose…\">\n <option value=\"fr\">France</option>\n </Select>\n</Field>\n```","file":"packages/react/src/components/Select/Select.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid (`aria-invalid`) and colors it as an error. A surrounding\nField's `error` sets it too."},{"name":"placeholder","type":"string","required":false,"description":"Shown until a choice is made; not itself selectable."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."}],"styles":{"className":"greese-Select","parts":["chevron","control"],"modifiers":["size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":["[aria-invalid=true]","[data-disabled]","[data-invalid]"],"variables":["--greese-select-height","--greese-select-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, Select } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Select',\n component: Select,\n args: { placeholder: 'Choose a country', required: true },\n render: (args) => (\n <Field label=\"Country\" style={{ maxInlineSize: '24rem' }}>\n <Select {...args}>\n <option value=\"nz\">New Zealand</option>\n <option value=\"au\">Australia</option>\n <optgroup label=\"Americas\">\n <option value=\"ca\">Canada</option>\n <option value=\"us\">United States</option>\n </optgroup>\n </Select>\n </Field>\n ),\n} satisfies Meta<typeof Select>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native select: the platform picker on phones. For search, use Combobox. */\nexport const Playground: Story = {}\n\nexport const Preselected: Story = { args: { placeholder: undefined, defaultValue: 'au' } }\n"},{"name":"Show","category":"Layout","description":"Renders children only within a viewport range, using CSS alone: no\nmatchMedia, no hydration mismatch, server-component safe.\n\n```tsx\n<Show above=\"md\"><DesktopNav /></Show>\n<Show below=\"md\"><MobileNav /></Show>\n```\n\nHidden content stays in the DOM (as `display: none`), so it is not rendered\nvisually or announced. To skip rendering entirely, use `useBreakpoint()`.","file":"packages/react/src/components/Visibility/Visibility.tsx","props":[{"name":"above","type":"BreakpointBoundary","required":false,"description":"From this breakpoint upward (inclusive)."},{"name":"asChild","type":"boolean","required":false,"description":"Apply to your element instead of a layout-neutral wrapper."},{"name":"below","type":"BreakpointBoundary","required":false,"description":"Below this breakpoint (exclusive)."},{"name":"children","type":"ReactNode","required":false,"description":"What to show or hide."},{"name":"className","type":"string","required":false,"description":"Classes for the wrapper, or for your element with `asChild`."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Hide, Show, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Show and Hide',\n component: Show,\n subcomponents: { Hide },\n args: { above: 'md', children: <Tile>Visible from md up</Tile> },\n} satisfies Meta<typeof Show>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** CSS-only: no matchMedia, no hydration mismatch. Resize the viewport. */\nexport const Playground: Story = {}\n\nexport const Ranges: Story = {\n render: () => (\n <>\n <Show below=\"md\">\n <Tile>Visible below md</Tile>\n </Show>\n <Show above=\"sm\" below=\"lg\">\n <Tile>Visible between sm and lg</Tile>\n </Show>\n <Hide above=\"sm\" below=\"lg\">\n <Tile>Hidden between sm and lg</Tile>\n </Hide>\n </>\n ),\n}\n"},{"name":"Sidebar","category":"Navigation","description":"The sidebar. Off-canvas below the layout's breakpoint (a native popover:\nclick-outside and Escape close it, and following a link inside does too);\na sticky column from the breakpoint up.\n\n```tsx\n<Sidebar label=\"Main\">\n <nav aria-label=\"Main\">…</nav>\n</Sidebar>\n```","file":"packages/react/src/components/Sidebar/Sidebar.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The navigation: links, a Stack of Buttons, anything."},{"name":"collapsed","type":"boolean","required":false,"description":"Narrow rail mode on wide screens (content decides what to show)."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"Open navigation","description":"Names the landmark, e.g. \"Main navigation\"."}],"styles":{"className":"greese-Sidebar","parts":[],"modifiers":[],"attributes":["[data-collapsed]"],"variables":["--greese-motion-drawer","--greese-motion-drawer-exit-mask-from","--greese-motion-drawer-exit-mask-image","--greese-motion-drawer-exit-mask-position","--greese-motion-drawer-exit-mask-repeat","--greese-motion-drawer-exit-mask-size","--greese-motion-drawer-exit-opacity","--greese-motion-drawer-exit-scale","--greese-motion-drawer-exit-transform","--greese-motion-drawer-exit-transform-origin","--greese-motion-drawer-exit-translate","--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin","--greese-sidebar-dir","--greese-sidebar-top","--greese-sidebar-width"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport {\n AppBar,\n Button,\n Sidebar,\n SidebarLayout,\n SidebarTrigger,\n Stack,\n Text,\n} from '@greese/react'\n\n/** The navigation column of a SidebarLayout: persistent from its breakpoint, off-canvas below. */\nconst meta = {\n title: 'Navigation/Sidebar',\n component: Sidebar,\n parameters: { layout: 'fullscreen' },\n args: {\n label: 'Main navigation',\n children: (\n <Stack gap={1} p={2}>\n {['Overview', 'Projects', 'Settings'].map((item) => (\n <Button\n key={item}\n asChild\n variant=\"ghost\"\n tone=\"neutral\"\n style={{ justifyContent: 'flex-start' }}\n >\n <a href={`#${item.toLowerCase()}`}>{item}</a>\n </Button>\n ))}\n </Stack>\n ),\n },\n decorators: [\n (Story) => (\n <SidebarLayout breakpoint=\"md\">\n <Story />\n <div>\n <AppBar>\n <SidebarTrigger />\n <Text weight=\"semibold\">Greese</Text>\n </AppBar>\n <Stack p={5}>\n <Text tone=\"muted\">Resize below md to move the sidebar off-canvas.</Text>\n </Stack>\n </div>\n </SidebarLayout>\n ),\n ],\n} satisfies Meta<typeof Sidebar>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Icons only, from the breakpoint up. */\nexport const Collapsed: Story = { args: { collapsed: true } }\n"},{"name":"SidebarLayout","category":"Navigation","description":"App shell: a sidebar beside the content from `breakpoint` up; below it the\nsidebar is off-canvas, opened by a SidebarTrigger. Put Sidebar first, then\nthe content (which can include an AppBar holding the trigger).\n\n```tsx\n<SidebarLayout breakpoint=\"md\">\n <Sidebar label=\"Main\">…</Sidebar>\n <main>\n <AppBar><SidebarTrigger /></AppBar>\n …\n </main>\n</SidebarLayout>\n```","file":"packages/react/src/components/Sidebar/Sidebar.tsx","props":[{"name":"breakpoint","type":"SidebarBreakpoint","required":false,"default":"md","description":"From this breakpoint the sidebar is always visible; below it, off-canvas."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-SidebarLayout","parts":[],"modifiers":["lg","md","sm","xl"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport {\n AppBar,\n Button,\n Sidebar,\n SidebarLayout,\n SidebarTrigger,\n Spacer,\n Stack,\n Text,\n} from '@greese/react'\n\nconst meta = {\n title: 'Navigation/SidebarLayout',\n component: SidebarLayout,\n subcomponents: { Sidebar, SidebarTrigger },\n parameters: { layout: 'fullscreen' },\n args: { breakpoint: 'md' },\n argTypes: {\n breakpoint: { control: 'inline-radio', options: ['sm', 'md', 'lg', 'xl'] },\n },\n render: (args) => (\n <SidebarLayout {...args}>\n <Sidebar label=\"Main navigation\">\n <Stack gap={1} p={2}>\n {['Overview', 'Projects', 'Members', 'Settings'].map((item) => (\n <Button\n key={item}\n asChild\n variant=\"ghost\"\n tone=\"neutral\"\n style={{ justifyContent: 'flex-start' }}\n >\n <a href={`#${item.toLowerCase()}`}>{item}</a>\n </Button>\n ))}\n </Stack>\n </Sidebar>\n <div>\n <AppBar>\n <SidebarTrigger />\n <Text weight=\"semibold\">Greese</Text>\n <Spacer />\n </AppBar>\n <Stack gap={5} p={5}>\n <Text tone=\"muted\">\n A persistent column from the breakpoint up, off-canvas below it. Resize to see\n both.\n </Text>\n </Stack>\n </div>\n </SidebarLayout>\n ),\n} satisfies Meta<typeof SidebarLayout>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"SidebarTrigger","category":"Navigation","description":"Opens the off-canvas sidebar; hidden once the sidebar is persistent.\n\n```tsx\n<AppBar>\n <SidebarTrigger />\n</AppBar>\n```","file":"packages/react/src/components/Sidebar/Sidebar.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element, e.g. a router `<Link>`, as the button."},{"name":"children","type":"ReactNode","required":false,"description":"Your menu icon. A built-in one is used if omitted."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"href","type":"undefined","required":false,"description":"A button that goes somewhere takes `href` instead of `onClick`."},{"name":"label","type":"string","required":false,"default":"Open navigation","description":"Accessible name of the button."},{"name":"loading","type":"boolean","required":false,"description":"Shows a spinner and ignores clicks, but stays focusable (`aria-disabled`,\nnot `disabled`) so keyboard focus is not lost mid-action. A submit button\ndoesn't submit while it's loading."},{"name":"onClick","type":"MouseEventHandler<HTMLButtonElement>","required":false,"description":"Called when it's pressed; never while it's loading or disabled."},{"name":"ref","type":"Ref<HTMLButtonElement>","required":false,"description":"The rendered `<button>` (or your element, with `asChild`)."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `xs`, `sm`, `md`, `lg` or `xl`. Touch targets stay at\nleast 44px."},{"name":"tone","type":"ButtonTone","required":false,"default":"'primary'","description":"Color role: `accent`, a brand color (primary, secondary, tertiary),\n`neutral`, or `negative` for destructive actions."},{"name":"variant","type":"ButtonVariant","required":false,"default":"'solid'","description":"Visual weight: `solid` for the main action, `soft`, `outline`, then `ghost`\nfor the least. `text` drops the box and takes the surrounding text's color,\nso the button reads as plain text."}],"styles":{"className":"greese-SidebarTrigger","parts":[],"modifiers":["lg","md","sm","xl"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport {\n AppBar,\n Sidebar,\n SidebarLayout,\n SidebarTrigger,\n Stack,\n Text,\n} from '@greese/react'\n\n/** The button that opens a SidebarLayout's sidebar below its breakpoint. */\nconst meta = {\n title: 'Navigation/SidebarTrigger',\n component: SidebarTrigger,\n parameters: { layout: 'fullscreen' },\n args: { label: 'Open navigation' },\n decorators: [\n (Story) => (\n <SidebarLayout breakpoint=\"md\">\n <Sidebar label=\"Main navigation\">\n <Stack p={3}>\n <Text>Navigation</Text>\n </Stack>\n </Sidebar>\n <div>\n <AppBar>\n <Story />\n <Text weight=\"semibold\">Greese</Text>\n </AppBar>\n </div>\n </SidebarLayout>\n ),\n ],\n} satisfies Meta<typeof SidebarTrigger>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** In the app bar; resize below md, where it opens the sidebar. */\nexport const Playground: Story = {}\n"},{"name":"Skeleton","category":"Content","description":"A placeholder in the shape of content that is still loading. Hidden from\nscreen readers: announce loading on the container (e.g. `aria-busy`)\ninstead. The shimmer stops under reduced motion.\n\n```tsx\n<Skeleton shape=\"circle\" width=\"3rem\" />\n<Skeleton lines={3} />\n```","file":"packages/react/src/components/Skeleton/Skeleton.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"height","type":"string","required":false,"description":"Any CSS length. Text is one line high."},{"name":"lines","type":"number","required":false,"description":"For text: render this many lines, the last one shorter."},{"name":"shape","type":"\"circle\" | \"rect\" | \"text\"","required":false,"default":"text","description":"`text` lines, a `rect` block (for images and cards) or a `circle` (for\navatars)."},{"name":"width","type":"string","required":false,"description":"Any CSS length. Text defaults to full width; circles to 2.5rem."}],"styles":{"className":"greese-Skeleton","parts":["lines"],"modifiers":["circle","rect","text"],"attributes":[],"variables":["--greese-skeleton-height","--greese-skeleton-width"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Skeleton, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/Skeleton',\n component: Skeleton,\n args: { lines: 3 },\n argTypes: { shape: { control: 'inline-radio', options: ['text', 'rect', 'circle'] } },\n decorators: [(Story) => <div style={{ maxInlineSize: '28rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Skeleton>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Hidden from screen readers; the shimmer stops under reduced motion. */\nexport const Playground: Story = {}\n\nexport const CardPlaceholder: Story = {\n render: () => (\n <Stack gap={3}>\n <Stack direction=\"row\" gap={3} align=\"center\">\n <Skeleton shape=\"circle\" />\n <Skeleton lines={2} />\n </Stack>\n <Skeleton shape=\"rect\" />\n </Stack>\n ),\n}\n"},{"name":"Slider","category":"Forms","description":"A native range input: arrow keys, Page Up/Down, Home/End and touch dragging\nall work as the platform defines. Label it with a Field or `aria-label`.\n\nThe filled part of the track is one CSS variable, written straight to the\nelement while dragging: no React re-render per step when uncontrolled.\n\n```tsx\n<Field label=\"Volume\">\n <Slider name=\"volume\" defaultValue={40} />\n</Field>\n```","file":"packages/react/src/components/Slider/Slider.tsx","props":[{"name":"defaultValue","type":"number","required":false,"description":"The starting value, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid and colors it as an error. A surrounding Field's `error`\nsets it too."},{"name":"max","type":"number","required":false,"default":"100","description":"The value at the inline end."},{"name":"min","type":"number","required":false,"default":"0","description":"The value at the inline start."},{"name":"onValueChange","type":"((value: number) => void)","required":false,"description":"Called with the new value as it moves."},{"name":"step","type":"number","required":false,"default":"1","description":"The increment the arrow keys and dragging snap to."},{"name":"value","type":"number","required":false,"description":"The value, when you control it. Pair with `onValueChange`."}],"styles":{"className":"greese-Slider","parts":[],"modifiers":[],"attributes":["[aria-invalid=true]"],"variables":["--greese-slider-fill","--greese-slider-thumb","--greese-slider-towards"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, Slider } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Slider',\n component: Slider,\n args: { defaultValue: 40, min: 0, max: 100, step: 1 },\n render: (args) => (\n <Field label=\"Volume\" style={{ maxInlineSize: '24rem' }}>\n <Slider {...args} />\n </Field>\n ),\n} satisfies Meta<typeof Slider>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native range input: arrows, Page Up/Down, Home/End and touch all work. */\nexport const Playground: Story = {}\n\nexport const Stepped: Story = { args: { min: 0, max: 10, step: 2, defaultValue: 4 } }\n"},{"name":"Slot","category":"Utilities","description":"Renders its single child element with the Slot's props merged in. Powers\n`asChild` on greese ui components, so a component's behaviour and styling can\nland on your element (a router `<Link>`, say) instead of a wrapper.\n\nMerge rules: the child's props win; `className`s are joined; `style`s are\nmerged (child wins per property); event handlers both run, child first; refs\nare composed.","file":"packages/react/src/components/Slot/Slot.tsx","props":[{"name":"children","type":"ReactNode","required":false,"description":"One element, which receives Slot's props, merged with its own."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"Merged with the child's own ref; both receive the element."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Icon, Slot, Slottable } from '@greese/react'\nimport type { ComponentPropsWithRef, ReactNode } from 'react'\nimport { ArrowRightIcon } from '@greese/icons'\n\n/** A component with an `asChild` prop, built on Slot, the way greese ui's own are. */\nconst Action = ({\n asChild,\n icon,\n children,\n ...props\n}: ComponentPropsWithRef<'button'> & { asChild?: boolean; icon?: ReactNode }) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n {...props}\n style={{\n display: 'inline-flex',\n gap: '0.5rem',\n alignItems: 'center',\n whiteSpace: 'nowrap',\n ...props.style,\n }}\n >\n <Slottable>{children}</Slottable>\n {icon && <Icon>{icon}</Icon>}\n </Comp>\n )\n}\n\nconst meta = {\n title: 'Utilities/Slot',\n component: Slot,\n subcomponents: { Slottable },\n args: { title: 'Merged onto the link', style: { fontWeight: 600 } },\n} satisfies Meta<typeof Slot>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Its props land on its one child: here the link gets the title and style. */\nexport const Playground: Story = {\n render: (args) => (\n <Slot {...args}>\n <a href=\"#somewhere\">A link</a>\n </Slot>\n ),\n}\n\n/**\n * Slot merges its props (className, style, handlers, ref) onto its one child.\n * Here the same `Action` renders a button, then, with `asChild`, a link.\n */\nexport const AsChild: Story = {\n render: () => (\n <div style={{ display: 'flex', gap: '1rem' }}>\n <Action icon={<ArrowRightIcon />}>A button</Action>\n <Action asChild icon={<ArrowRightIcon />}>\n <a href=\"#somewhere\">A link</a>\n </Action>\n </div>\n ),\n}\n"},{"name":"Slottable","category":"Utilities","description":"Marks which child of a Slot is the host element. Components that add their\nown content (icons, spinners) wrap `children` in it, so `asChild` still works:\n\n```tsx\n<Root>{icon}<Slottable>{children}</Slottable></Root>\n```\n\nOutside a Slot it renders its children unchanged.","file":"packages/react/src/components/Slot/Slot.tsx","props":[],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Icon, Slot, Slottable } from '@greese/react'\nimport type { ComponentPropsWithRef, ReactNode } from 'react'\nimport { ArrowRightIcon } from '@greese/icons'\n\n/** A button-like component whose `asChild` child receives its props. */\nconst Action = ({\n asChild,\n children,\n ...props\n}: ComponentPropsWithRef<'button'> & { asChild?: boolean; children?: ReactNode }) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n {...props}\n style={{ display: 'inline-flex', gap: '0.5rem', alignItems: 'center' }}\n >\n <Slottable>{children}</Slottable>\n <Icon>\n <ArrowRightIcon />\n </Icon>\n </Comp>\n )\n}\n\n/**\n * Marks which child of a Slot receives its props when the Slot has other\n * children too: here the link gets the styles, and the icon is kept beside it.\n */\nconst meta = {\n title: 'Utilities/Slottable',\n component: Slottable,\n render: () => (\n <Action asChild>\n <a href=\"#somewhere\">A link with a trailing icon</a>\n </Action>\n ),\n // The web app's Try it: the example's own component, in scope.\n parameters: { tryIt: { scope: { Action } } },\n} satisfies Meta<typeof Slottable>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Spacer","category":"Layout","description":"Flexible or fixed empty space inside a Stack (or any flex container).\n\n```tsx\n<Stack direction=\"row\">\n <Logo />\n <Spacer />\n <Button>Sign in</Button>\n</Stack>\n```","file":"packages/react/src/components/Spacer/Spacer.tsx","props":[{"name":"size","type":"Responsive<SpaceValue>","required":false,"description":"A fixed gap along the parent's main axis. Omit to grow and push\nneighbours apart, e.g. a toolbar's trailing actions."}],"styles":{"className":"greese-Spacer","parts":[],"modifiers":["fixed"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Spacer, Stack, Tile } from '@greese/react'\n\nconst meta = { title: 'Layout/Spacer', component: Spacer } satisfies Meta<typeof Spacer>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** A row with the spacer between: try a `size` to fix its length. */\nexport const Playground: Story = {\n render: (args) => (\n <Stack direction=\"row\" align=\"center\">\n <Tile>Logo</Tile>\n <Spacer {...args} />\n <Tile>Sign in</Tile>\n </Stack>\n ),\n}\n\n/** Without `size`, it grows and pushes its neighbours apart. */\nexport const Flexible: Story = {\n render: () => (\n <Stack direction=\"row\" align=\"center\">\n <Tile>Logo</Tile>\n <Spacer />\n <Tile>Sign in</Tile>\n </Stack>\n ),\n}\n\n/** With `size`, a fixed gap along the main axis, per breakpoint if needed. */\nexport const Fixed: Story = {\n render: () => (\n <Stack direction=\"row\">\n <Tile>One</Tile>\n <Spacer size={{ xs: 2, md: 8 }} />\n <Tile>Two</Tile>\n </Stack>\n ),\n}\n"},{"name":"SpeedDial","category":"Overlays","description":"A floating action button that opens a short stack of related actions\n(FAB, speed dial). The stack is a native popover: Escape and a click\noutside close it, and Tab moves from the button into the actions. The\nbutton and each action's icon are greese ui Buttons, so they take the\ntheme's button shape, depth and states.\n\n```tsx\n<SpeedDial label=\"Create\">\n <SpeedDialAction label=\"Document\" icon={<DocIcon />} onClick={newDoc} />\n <SpeedDialAction label=\"Folder\" icon={<FolderIcon />} onClick={newFolder} />\n</SpeedDial>\n```","file":"packages/react/src/components/SpeedDial/SpeedDial.tsx","props":[{"name":"children","type":"ReactNode","required":true,"description":"The actions: SpeedDialAction elements."},{"name":"label","type":"string","required":true,"description":"The main button's accessible name (\"Create\")."},{"name":"defaultOpen","type":"boolean","required":false,"default":"false","description":"Whether it starts open, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"default":"<PlusIcon />","description":"The main button's icon. Turns 45° while open."},{"name":"onOpenChange","type":"((open: boolean) => void)","required":false,"description":"Called with the new state when it opens or closes (the button, an action,\nEscape, a click outside)."},{"name":"open","type":"boolean","required":false,"description":"Whether the actions are showing, when you control it. Pair with `onOpenChange`."},{"name":"position","type":"\"fixed\" | \"static\"","required":false,"default":"fixed","description":"`fixed` floats it in the bottom inline-end corner, clear of the home\nindicator; `static` leaves it in the flow."}],"styles":{"className":"greese-SpeedDial","parts":["actions","icon","trigger"],"modifiers":["fixed"],"attributes":["[aria-expanded=true]"],"variables":["--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-motion-popover","--greese-motion-popover-exit-mask-from","--greese-motion-popover-exit-mask-image","--greese-motion-popover-exit-mask-position","--greese-motion-popover-exit-mask-repeat","--greese-motion-popover-exit-mask-size","--greese-motion-popover-exit-opacity","--greese-motion-popover-exit-scale","--greese-motion-popover-exit-transform","--greese-motion-popover-exit-transform-origin","--greese-motion-popover-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { SpeedDial, SpeedDialAction } from '@greese/react'\nimport { DocumentIcon, FolderIcon, UserIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Overlays/SpeedDial',\n component: SpeedDial,\n subcomponents: { SpeedDialAction },\n // Static in the docs; `fixed` (the default) floats it in the corner.\n args: {\n label: 'Create',\n position: 'static',\n children: (\n <>\n <SpeedDialAction label=\"Document\" icon={<DocumentIcon />} />\n <SpeedDialAction label=\"Folder\" icon={<FolderIcon />} />\n <SpeedDialAction label=\"Invite someone\" icon={<UserIcon />} />\n </>\n ),\n },\n argTypes: { position: { control: 'inline-radio', options: ['fixed', 'static'] } },\n decorators: [\n (Story) => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n paddingBlockStart: '12rem',\n }}\n >\n <Story />\n </div>\n ),\n ],\n} satisfies Meta<typeof SpeedDial>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Press the button; Escape or a click outside closes it. */\nexport const Playground: Story = {}\n"},{"name":"SpeedDialAction","category":"Overlays","description":"One action in a SpeedDial. Choosing it closes the dial.","file":"packages/react/src/components/SpeedDial/SpeedDial.tsx","props":[{"name":"label","type":"string","required":true,"description":"Shown beside the icon, and its accessible name."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"icon","type":"ReactNode","required":false,"default":"<PlusIcon />","description":"The icon in the round button. Decorative: `label` names the action."}],"styles":{"className":"greese-SpeedDialAction","parts":["icon","label"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { SpeedDial, SpeedDialAction } from '@greese/react'\nimport { DocumentIcon, FolderIcon } from '@greese/icons'\n\n/** One action in a SpeedDial: a labelled round button. Open the dial to see it. */\nconst meta = {\n title: 'Overlays/SpeedDialAction',\n component: SpeedDialAction,\n args: { label: 'Document', icon: <DocumentIcon /> },\n decorators: [\n (Story) => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n paddingBlockStart: '10rem',\n }}\n >\n <SpeedDial label=\"Create\" position=\"static\">\n <Story />\n <SpeedDialAction label=\"Folder\" icon={<FolderIcon />} />\n </SpeedDial>\n </div>\n ),\n ],\n} satisfies Meta<typeof SpeedDialAction>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Spinner","category":"Content","description":"An indeterminate loading indicator (`role=\"status\"`). Under reduced motion\nit pulses gently instead of spinning.\n\n```tsx\n<Spinner label=\"Loading results\" />\n```","file":"packages/react/src/components/Spinner/Spinner.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"default":"Loading","description":"Announced to screen readers."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Diameter: `sm` (1rem), `md` (1.5rem) or `lg` (2.5rem)."}],"styles":{"className":"greese-Spinner","parts":[],"modifiers":["lg","md","sm","xl","xs"],"attributes":[],"variables":["--greese-spinner-size"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Spinner, Stack } from '@greese/react'\n\nconst meta = {\n title: 'Content/Spinner',\n component: Spinner,\n args: { label: 'Loading results' },\n argTypes: { size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] } },\n} satisfies Meta<typeof Spinner>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Announced as a status; pulses instead of spinning under reduced motion. */\nexport const Playground: Story = {}\n\nexport const Sizes: Story = {\n render: () => (\n <Stack direction=\"row\" gap={4} align=\"center\">\n <Spinner size=\"sm\" />\n <Spinner />\n <Spinner size=\"lg\" />\n </Stack>\n ),\n}\n"},{"name":"Stack","category":"Layout","description":"One-dimensional flex layout, vertical by default (mobile-first).\n\n```tsx\n<Stack direction={{ xs: 'column', md: 'row' }} gap={{ xs: 2, md: 4 }} align=\"center\">\n```\n\nAccepts every Box style prop and `asChild`. Server-component safe.","file":"packages/react/src/components/Stack/Stack.tsx","props":[{"name":"align","type":"Responsive<StackAlign>","required":false,"description":"Cross-axis alignment (`align-items`)."},{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"direction","type":"Responsive<StackDirection>","required":false,"description":"Main axis. Mobile-first default: `column`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children: a scale token (`0`–`8`) or any CSS length."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"justify","type":"Responsive<StackJustify>","required":false,"description":"Main-axis distribution (`justify-content`)."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."},{"name":"wrap","type":"Responsive<\"wrap\" | \"nowrap\" | \"wrap-reverse\">","required":false,"description":"Whether items move to a new line when they don't fit, per breakpoint if you like."}],"styles":{"className":"greese-Stack","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Divider, Spacer, Stack, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Stack',\n component: Stack,\n args: { gap: 3 },\n argTypes: {\n direction: {\n control: 'inline-radio',\n options: ['column', 'row', 'row-reverse', 'column-reverse'],\n },\n gap: { control: { type: 'range', min: 0, max: 8 } },\n align: {\n control: 'inline-radio',\n options: ['start', 'center', 'end', 'stretch', 'baseline'],\n },\n justify: {\n control: 'select',\n options: ['start', 'center', 'end', 'between', 'around', 'evenly'],\n },\n wrap: { control: 'inline-radio', options: ['nowrap', 'wrap', 'wrap-reverse'] },\n },\n render: (args) => (\n <Stack {...args}>\n <Tile>One</Tile>\n <Tile>Two</Tile>\n <Tile>Three</Tile>\n </Stack>\n ),\n} satisfies Meta<typeof Stack>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Column on phones, row from `md`; gap grows at `lg`. Resize the viewport. */\nexport const Responsive: Story = {\n args: { direction: { xs: 'column', md: 'row' }, gap: { xs: 2, lg: 6 } },\n}\n\nexport const ToolbarWithSpacer: Story = {\n render: () => (\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Tile>Logo</Tile>\n <Spacer />\n <Tile>Sign in</Tile>\n <Divider orientation=\"vertical\" />\n <Tile>Menu</Tile>\n </Stack>\n ),\n}\n"},{"name":"Stat","category":"Content","description":"One headline number with its label: a native `<dl>`, so the label and the\nvalue are read together. Put several in a StatGroup.\n\n```tsx\n<Stat label=\"Revenue\" value=\"$48,200\" description=\"up 12% on last month\" tone=\"positive\" />\n```","file":"packages/react/src/components/Stat/Stat.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"What is measured: \"Revenue\"."},{"name":"value","type":"ReactNode","required":true,"description":"The figure: \"$48,200\"."},{"name":"description","type":"ReactNode","required":false,"description":"Context below it: \"+12% on last month\"."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"media","type":"ReactNode","required":false,"description":"A figure or icon at the inline end."},{"name":"tone","type":"\"positive\" | \"negative\" | BrandTone | \"muted\"","required":false,"default":"muted","description":"Colors the description, for a change worth noticing (`positive`,\n`negative`) or in a brand color (primary, secondary, tertiary). Say the\ndirection in its text too (\"up 12%\"): color alone isn't enough."}],"styles":{"className":"greese-Stat","parts":["description","label","media","value"],"modifiers":[],"attributes":[],"variables":["--greese-stat-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stat } from '@greese/react'\nimport { StarIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Content/Stat',\n component: Stat,\n args: {\n label: 'Revenue',\n value: '$48,200',\n description: 'up 12% on last month',\n tone: 'positive',\n },\n argTypes: {\n tone: { control: 'inline-radio', options: ['muted', 'positive', 'negative'] },\n },\n} satisfies Meta<typeof Stat>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\nexport const WithMedia: Story = {\n args: {\n label: 'Rating',\n value: '4.8',\n description: 'from 1,204 reviews',\n tone: 'muted',\n media: <StarIcon size=\"2.5rem\" />,\n },\n}\n"},{"name":"StatGroup","category":"Content","description":"Stats side by side with dividers, stacking on narrow screens.","file":"packages/react/src/components/Stat/Stat.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"rowFrom","type":"\"xs\" | \"sm\" | \"md\" | \"lg\"","required":false,"default":"sm","description":"Lay the stats out in a row with dividers from this width up; stacked\nbelow."}],"styles":{"className":"greese-StatGroup","parts":[],"modifiers":["row-lg","row-md","row-sm","row-xs"],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stat, StatGroup } from '@greese/react'\n\n/** Stats side by side with dividers, stacked on narrow screens. */\nconst meta = {\n title: 'Content/StatGroup',\n component: StatGroup,\n args: {\n children: (\n <>\n <Stat label=\"Revenue\" value=\"$48,200\" description=\"up 12%\" tone=\"positive\" />\n <Stat label=\"Orders\" value=\"1,204\" description=\"up 3%\" tone=\"positive\" />\n <Stat\n label=\"Refunds\"\n value=\"18\"\n description=\"up 2 on last month\"\n tone=\"negative\"\n />\n </>\n ),\n },\n argTypes: { rowFrom: { control: 'inline-radio', options: ['xs', 'sm', 'md', 'lg'] } },\n} satisfies Meta<typeof StatGroup>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Stacked on phones, a row from sm. */\nexport const Playground: Story = {}\n"},{"name":"Status","category":"Content","description":"A small dot showing a state: online, error, building. Color alone isn't\nenough, so give it a `label` or put the state in text beside it.\n\n```tsx\n<Status tone=\"positive\" label=\"Online\" pulse />\n```","file":"packages/react/src/components/Status/Status.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"description":"What it means, for assistive tech (\"Online\"). Without it the dot is\ndecorative: say it in nearby text instead."},{"name":"pulse","type":"boolean","required":false,"description":"A ring that pulses outward, for live states. Still under reduced motion."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Dot diameter, from the shared control sizes."},{"name":"tone","type":"StatusTone","required":false,"default":"neutral","description":"The dot's color: neutral, accent, a brand color (primary, secondary,\ntertiary), positive, negative, warning or info."}],"styles":{"className":"greese-Status","parts":[],"modifiers":["accent","info","lg","md","negative","neutral","positive","primary","pulse","secondary","sm","tertiary","warning","xl","xs"],"attributes":[],"variables":["--greese-status-size","--greese-status-tone","--greese-status-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stack, Status, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Status',\n component: Status,\n args: { tone: 'positive', label: 'Online' },\n argTypes: {\n tone: {\n control: 'select',\n options: [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ],\n },\n size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },\n },\n} satisfies Meta<typeof Status>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Decorative dots beside text that says the state. */\nexport const WithText: Story = {\n render: () => (\n <Stack gap={2}>\n {(\n [\n ['positive', 'Operational'],\n ['warning', 'Degraded'],\n ['negative', 'Outage'],\n ['neutral', 'Unknown'],\n ] as const\n ).map(([tone, text]) => (\n <Stack key={tone} direction=\"row\" gap={2} align=\"center\">\n <Status tone={tone} pulse={tone === 'negative'} />\n <Text variant=\"p3\">{text}</Text>\n </Stack>\n ))}\n </Stack>\n ),\n}\n"},{"name":"Step","category":"Navigation","description":"One step in Steps.","file":"packages/react/src/components/Steps/Steps.tsx","props":[{"name":"description","type":"ReactNode","required":false,"description":"Detail under the title: a line of text, or richer content."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"marker","type":"ReactNode","required":false,"description":"What the marker shows: the step number by default (a tick once\ncomplete), a dot with `markers=\"dots\"`, or this: a small icon."},{"name":"prefix","type":"ReactNode","required":false,"description":"Content ahead of the step, such as a time or a date. Above the title by\ndefault; see `prefixBefore`."},{"name":"prefixBefore","type":"boolean","required":false,"default":"false","description":"Put the prefix before the marker instead of above the title: in its own\ncolumn on vertical steps (a column every step then shares), above the\nmarker on horizontal ones."},{"name":"status","type":"StepStatus","required":false,"description":"Set by Steps from its `current`; set it here to override."},{"name":"tone","type":"\"info\" | \"positive\" | \"warning\" | \"negative\" | \"neutral\" | BrandTone","required":false,"default":"primary","description":"The color of this step's marker, and of the line on to the next step\nonce it's complete: neutral, accent, a brand color (primary, secondary,\ntertiary), positive, negative, warning or info."}],"styles":{"className":"greese-Step","parts":["body","description","marker","prefix","title"],"modifiers":["accent","complete","current","event","info","muted","negative","neutral","positive","prefix-before","primary","secondary","tertiary","warning"],"attributes":[],"variables":["--greese-step-tone","--greese-step-tone-on"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Step, Steps } from '@greese/react'\n\n/** One step. Steps sets its status from `current`; set it here to override. */\nconst meta = {\n title: 'Navigation/Step',\n component: Step,\n args: { children: 'Shipping', description: 'Standard, 2–4 days', status: 'current' },\n argTypes: {\n status: { control: 'inline-radio', options: ['complete', 'current', 'upcoming'] },\n tone: {\n control: 'select',\n options: [\n 'neutral',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ],\n },\n },\n decorators: [\n (Story) => (\n <Steps current={1}>\n <Step>Cart</Step>\n <Story />\n <Step>Payment</Step>\n </Steps>\n ),\n ],\n} satisfies Meta<typeof Step>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The middle step. */\nexport const Playground: Story = {}\n\n/** With a prefix above its marker. */\nexport const WithPrefix: Story = { args: { prefix: 'Step 2', prefixBefore: true } }\n"},{"name":"Steps","category":"Navigation","description":"Steps in order: the stages of a process, or events on a timeline. A native\n`<ol>`; with `current`, the current step is `aria-current=\"step\"` and\ncompleted ones say so to screen readers.\n\n```tsx\n<Steps current={1}>\n <Step>Cart</Step>\n <Step>Shipping</Step>\n <Step>Payment</Step>\n</Steps>\n\n<Steps direction=\"vertical\" markers=\"dots\">\n <Step prefix={<time dateTime=\"2026-10-19T09:12\">09:12</time>} prefixBefore tone=\"positive\"\n description=\"Version 1.4 is live.\">Deployed</Step>\n <Step prefix=\"08:55\" prefixBefore>Build passed</Step>\n</Steps>\n```","file":"packages/react/src/components/Steps/Steps.tsx","props":[{"name":"current","type":"number","required":false,"description":"The current step's index, from 0: earlier steps are complete, later ones\nupcoming. Leave it out for a list of events (a timeline), where no step\nis complete or current and each marker shows its own tone."},{"name":"direction","type":"\"horizontal\" | \"vertical\"","required":false,"default":"horizontal","description":"`horizontal`: a row, with the steps' text under their markers; it\nscrolls sideways when it doesn't fit. `vertical`: a column, with the\ntext beside each marker."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"markers","type":"\"numbers\" | \"dots\"","required":false,"default":"numbers","description":"What the markers show: the step `numbers` (a tick once complete), or\nsmall `dots`, as on a timeline. A Step's own `marker` replaces either."}],"styles":{"className":"greese-Steps","parts":[],"modifiers":["dots","horizontal","vertical"],"attributes":[],"variables":["--greese-steps-before","--greese-steps-marker","--greese-steps-prefix"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Step, Steps } from '@greese/react'\nimport { StarIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Navigation/Steps',\n component: Steps,\n subcomponents: { Step },\n args: {\n current: 1,\n 'aria-label': 'Checkout',\n children: (\n <>\n <Step>Cart</Step>\n <Step>Shipping</Step>\n <Step>Payment</Step>\n <Step>Done</Step>\n </>\n ),\n },\n argTypes: {\n current: { control: { type: 'number', min: 0, max: 4 } },\n direction: { control: 'inline-radio', options: ['horizontal', 'vertical'] },\n markers: { control: 'inline-radio', options: ['numbers', 'dots'] },\n },\n} satisfies Meta<typeof Steps>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The stages of a process: completed, current, upcoming. */\nexport const Playground: Story = {}\n\nexport const Vertical: Story = {\n args: {\n direction: 'vertical',\n current: 2,\n children: (\n <>\n <Step description=\"Two items\">Cart</Step>\n <Step description=\"Standard, 2–4 days\">Shipping</Step>\n <Step description=\"Card ending 4242\">Payment</Step>\n <Step>Confirmation</Step>\n </>\n ),\n },\n}\n\n/** A step's own `status` and `tone` override the derived ones. */\nexport const WithAProblem: Story = {\n args: {\n current: 2,\n children: (\n <>\n <Step>Upload</Step>\n <Step>Check</Step>\n <Step tone=\"negative\" marker=\"!\">\n Publish failed\n </Step>\n </>\n ),\n },\n}\n\n/**\n * A timeline: no `current`, so steps are events in their own tones; dots for\n * markers, and times in a column before them (`prefixBefore`).\n */\nexport const Timeline: Story = {\n args: {\n current: undefined,\n direction: 'vertical',\n markers: 'dots',\n 'aria-label': 'Activity',\n style: { maxInlineSize: '36rem' },\n children: (\n <>\n <Step\n prefix={<time dateTime=\"2026-10-19T09:12\">09:12</time>}\n prefixBefore\n tone=\"positive\"\n description=\"Version 1.4 is live in every region.\"\n >\n Deployed\n </Step>\n <Step prefix={<time dateTime=\"2026-10-19T08:55\">08:55</time>} prefixBefore>\n Build passed\n </Step>\n <Step\n prefix={<time dateTime=\"2026-10-19T08:31\">08:31</time>}\n prefixBefore\n tone=\"warning\"\n marker={<StarIcon />}\n description=\"Two approvals from the core team.\"\n >\n Review approved\n </Step>\n <Step\n prefix={<time dateTime=\"2026-10-18\">Yesterday</time>}\n prefixBefore\n tone=\"neutral\"\n >\n Opened\n </Step>\n </>\n ),\n },\n}\n\n/** Without `prefixBefore`, the prefix sits above each title instead. */\nexport const TimelinePrefixAbove: Story = {\n args: {\n current: undefined,\n direction: 'vertical',\n markers: 'dots',\n 'aria-label': 'Activity',\n style: { maxInlineSize: '36rem' },\n children: (\n <>\n <Step prefix=\"Today, 09:12\" tone=\"positive\" description=\"Version 1.4 is live.\">\n Deployed\n </Step>\n <Step prefix=\"Today, 08:55\">Build passed</Step>\n <Step prefix=\"Yesterday\" tone=\"neutral\">\n Opened\n </Step>\n </>\n ),\n },\n}\n\n/** Horizontal, with dates above the markers. */\nexport const Roadmap: Story = {\n args: {\n current: 1,\n markers: 'dots',\n 'aria-label': 'Roadmap',\n children: (\n <>\n <Step prefix=\"Q1\" prefixBefore description=\"Shipped\">\n Beta\n </Step>\n <Step prefix=\"Q2\" prefixBefore description=\"In progress\">\n 1.0\n </Step>\n <Step prefix=\"Q3\" prefixBefore>\n Plugins\n </Step>\n <Step prefix=\"Q4\" prefixBefore>\n 2.0\n </Step>\n </>\n ),\n },\n}\n"},{"name":"Swap","category":"Forms","description":"A toggle that swaps between two pieces of content, such as a sun and a\nmoon: an `aria-pressed` button with no frame of its own, so it fits in an\nAppBar or around an icon.\n\n```tsx\n<Swap label=\"Dark mode\" off={<SunIcon />} on={<MoonIcon />} effect=\"rotate\" />\n```","file":"packages/react/src/components/Swap/Swap.tsx","props":[{"name":"label","type":"string","required":true,"description":"The accessible name, for what it toggles (\"Dark mode\"); stays the same in both states."},{"name":"off","type":"ReactNode","required":true,"description":"Shown while not pressed."},{"name":"on","type":"ReactNode","required":true,"description":"Shown while pressed."},{"name":"defaultPressed","type":"boolean","required":false,"default":"false","description":"Whether it starts showing `on`, when it keeps its own state."},{"name":"effect","type":"\"rotate\" | \"fade\" | \"flip\"","required":false,"default":"fade","description":"How one gives way to the other."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onPressedChange","type":"((pressed: boolean) => void)","required":false,"description":"Called with the new state when it's pressed."},{"name":"pressed","type":"boolean","required":false,"description":"Whether it shows `on`, when you control it. Pair with `onPressedChange`."}],"styles":{"className":"greese-Swap","parts":["off","on"],"modifiers":["flip","rotate"],"attributes":["[aria-pressed=false]","[aria-pressed=true]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stack, Swap } from '@greese/react'\nimport { MoonIcon, SunIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Forms/Swap',\n component: Swap,\n args: { label: 'Dark mode', off: <SunIcon />, on: <MoonIcon /> },\n argTypes: { effect: { control: 'inline-radio', options: ['fade', 'rotate', 'flip'] } },\n} satisfies Meta<typeof Swap>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Its name stays \"Dark mode\"; `aria-pressed` says whether it's on. */\nexport const Playground: Story = {}\n\nexport const Effects: Story = {\n render: () => (\n <Stack direction=\"row\" gap={2}>\n <Swap label=\"Fade\" off={<SunIcon />} on={<MoonIcon />} />\n <Swap\n label=\"Rotate\"\n effect=\"rotate\"\n off={<SunIcon />}\n on={<MoonIcon />}\n defaultPressed\n />\n <Swap label=\"Flip\" effect=\"flip\" off=\"👍\" on=\"👎\" />\n </Stack>\n ),\n}\n"},{"name":"Switch","category":"Forms","description":"An on/off switch for settings that apply immediately: a native checkbox\nwith `role=\"switch\"`, so it is announced as on/off and submits like a\ncheckbox.\n\n```tsx\n<Switch label=\"Email me updates\" name=\"updates\" />\n```","file":"packages/react/src/components/Switch/Switch.tsx","props":[{"name":"description","type":"ReactNode","required":false,"description":"A muted line under the label, announced with it."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid and colors it as an error. A surrounding Field's `error`\nsets it too."},{"name":"label","type":"ReactNode","required":false,"description":"Text beside the switch. Without it, give the switch an `aria-label`."},{"name":"onCheckedChange","type":"((checked: boolean) => void)","required":false,"description":"Called with the new state when it's turned on or off."}],"styles":{"className":"greese-Switch","parts":["input","thumb","track"],"modifiers":[],"attributes":["[aria-invalid=true]","[data-disabled]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stack, Switch } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Switch',\n component: Switch,\n args: { label: 'Dark mode', description: 'Applies immediately' },\n} satisfies Meta<typeof Switch>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** A checkbox announced as on/off: for settings that apply at once. */\nexport const Playground: Story = {}\n\nexport const States: Story = {\n render: () => (\n <Stack gap={3}>\n <Switch label=\"On\" defaultChecked />\n <Switch label=\"Off\" />\n <Switch label=\"Disabled\" disabled />\n </Stack>\n ),\n}\n"},{"name":"Tab","category":"Content","description":"One tab. Only the selected tab is in the Tab order.","file":"packages/react/src/components/Tabs/Tabs.tsx","props":[{"name":"value","type":"string","required":true,"description":"Pairs the tab with the TabPanel of the same value."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-Tab","parts":[],"modifiers":[],"attributes":["[aria-selected=true]"],"variables":["--greese-tab-current-bg","--greese-tab-current-edge"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Tab, TabList, TabPanel, Tabs, Text } from '@greese/react'\n\n/** One tab. Its `value` pairs it with the TabPanel of the same value. */\nconst meta = {\n title: 'Content/Tab',\n component: Tab,\n args: { value: 'activity', children: 'Activity' },\n decorators: [\n (Story) => (\n <Tabs defaultValue=\"activity\">\n <TabList aria-label=\"Project\">\n <Tab value=\"overview\">Overview</Tab>\n <Story />\n <Tab value=\"settings\">Settings</Tab>\n </TabList>\n {['overview', 'activity', 'settings'].map((value) => (\n <TabPanel key={value} value={value}>\n <Text>The {value} panel.</Text>\n </TabPanel>\n ))}\n </Tabs>\n ),\n ],\n} satisfies Meta<typeof Tab>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The middle tab, selected. */\nexport const Playground: Story = {}\n\nexport const Disabled: Story = {\n args: { value: 'billing', children: 'Billing', disabled: true },\n}\n"},{"name":"Table","category":"Content","description":"A data table: native `<table>` semantics in a keyboard-scrollable region.\n\n```tsx\n<Table caption=\"Invoices\" stackBelow=\"sm\">\n <TableHead><TableRow><TableHeaderCell>Number</TableHeaderCell>…</TableRow></TableHead>\n <TableBody><TableRow><TableCell label=\"Number\">INV-001</TableCell>…</TableRow></TableBody>\n</Table>\n```","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"caption","type":"ReactNode","required":true,"description":"Names the table (rendered as `<caption>`). Required: tables need a name."},{"name":"density","type":"\"compact\" | \"comfortable\"","required":false,"default":"comfortable","description":"Row height: `comfortable`, or `compact` for dense data."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideCaption","type":"boolean","required":false,"description":"Keep the caption for assistive tech but hide it on screen."},{"name":"hoverable","type":"boolean","required":false,"description":"Highlight the row under the pointer."},{"name":"maxHeight","type":"string","required":false,"description":"Maximum height of the scroll region, any CSS length."},{"name":"stackBelow","type":"TableStackBreakpoint","required":false,"description":"Below this breakpoint, each row becomes a card of label/value pairs\n(give every TableCell a `label`). Wide tables stay readable on phones."},{"name":"stickyHeader","type":"boolean","required":false,"description":"Keep the header visible while the table body scrolls. Needs `maxHeight`:\nthe table scrolls inside its own region (a horizontally scrollable box\ncan't stick to the page)."},{"name":"striped","type":"boolean","required":false,"description":"Shade every other body row."}],"styles":{"className":"greese-Table","parts":["caption","table"],"modifiers":["comfortable","compact","hoverable","stack-below-lg","stack-below-md","stack-below-sm","sticky","striped"],"attributes":[],"variables":["--greese-motion-enter-ease","--greese-motion-rows","--greese-motion-rows-duration","--greese-motion-stagger","--greese-table-cell-padding","--greese-table-max-height"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\nimport {\n Badge,\n Table,\n TableBody,\n TableCell,\n TableFoot,\n TableHead,\n TableHeaderCell,\n TableRow,\n type SortDirection,\n} from '@greese/react'\n\nconst meta = {\n title: 'Content/Table',\n component: Table,\n subcomponents: {\n TableHead,\n TableBody,\n TableFoot,\n TableRow,\n TableHeaderCell,\n TableCell,\n },\n args: { caption: 'Invoices' },\n} satisfies Meta<typeof Table>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nconst invoices = [\n { id: 'INV-001', client: 'Acme Ltd', status: 'Paid', total: 1200 },\n { id: 'INV-002', client: 'Globex', status: 'Overdue', total: 860.5 },\n { id: 'INV-003', client: 'Initech', status: 'Draft', total: 3400 },\n { id: 'INV-004', client: 'Umbrella', status: 'Paid', total: 95 },\n { id: 'INV-005', client: 'Hooli', status: 'Paid', total: 2210 },\n { id: 'INV-006', client: 'Stark', status: 'Overdue', total: 18000 },\n]\nconst tone = { Paid: 'positive', Overdue: 'negative', Draft: 'neutral' } as const\nconst money = (n: number) =>\n n.toLocaleString('en-NZ', { style: 'currency', currency: 'NZD' })\n\n/** A captioned table: try `density`, `striped` and `hoverable`. */\nexport const Playground: Story = {\n render: (args) => (\n <Table {...args}>\n <TableHead>\n <TableRow>\n <TableHeaderCell>Number</TableHeaderCell>\n <TableHeaderCell>Client</TableHeaderCell>\n <TableHeaderCell>Total</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {invoices.slice(0, 3).map((row) => (\n <TableRow key={row.id}>\n <TableCell>{row.id}</TableCell>\n <TableCell>{row.client}</TableCell>\n <TableCell>{money(row.total)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n ),\n}\n\n/** Sortable columns (`aria-sort`); rows stack into cards below sm. Resize to see. */\nexport const SortableAndResponsive: Story = {\n render: function Render() {\n const [sort, setSort] = useState<{ key: 'client' | 'total'; dir: SortDirection }>({\n key: 'total',\n dir: 'descending',\n })\n const rows = [...invoices].sort((a, b) => {\n const order = a[sort.key] < b[sort.key] ? -1 : a[sort.key] > b[sort.key] ? 1 : 0\n return sort.dir === 'ascending' ? order : -order\n })\n const sortBy = (key: 'client' | 'total') =>\n setSort((s) => ({\n key,\n dir: s.key === key && s.dir === 'ascending' ? 'descending' : 'ascending',\n }))\n return (\n <Table caption=\"Invoices\" stackBelow=\"sm\" hoverable>\n <TableHead>\n <TableRow>\n <TableHeaderCell>Number</TableHeaderCell>\n <TableHeaderCell\n sort={sort.key === 'client' ? sort.dir : 'none'}\n onSort={() => sortBy('client')}\n >\n Client\n </TableHeaderCell>\n <TableHeaderCell>Status</TableHeaderCell>\n <TableHeaderCell\n align=\"end\"\n sort={sort.key === 'total' ? sort.dir : 'none'}\n onSort={() => sortBy('total')}\n >\n Total\n </TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map((r) => (\n <TableRow key={r.id}>\n <TableCell label=\"Number\">{r.id}</TableCell>\n <TableCell label=\"Client\">{r.client}</TableCell>\n <TableCell label=\"Status\">\n <Badge tone={tone[r.status as keyof typeof tone]}>{r.status}</Badge>\n </TableCell>\n <TableCell label=\"Total\" align=\"end\">\n {money(r.total)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )\n },\n}\n\n/** Compact and striped, with a header that sticks inside a 12rem scroll region. */\nexport const CompactSticky: Story = {\n render: () => (\n <Table caption=\"Activity\" density=\"compact\" striped stickyHeader maxHeight=\"12rem\">\n <TableHead>\n <TableRow>\n <TableHeaderCell>Time</TableHeaderCell>\n <TableHeaderCell>Event</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: 14 }, (_, i) => (\n <TableRow key={i}>\n <TableCell>{`09:${String(10 + i * 3).padStart(2, '0')}`}</TableCell>\n <TableCell>Deployment step {i + 1} finished</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n ),\n}\n"},{"name":"TableBody","category":"Content","description":"Rows here can enter in sequence: `greese={{ enter: 'fadeUp', stagger: 0.04 }}`.","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Table, TableBody, TableHead } from '@greese/react'\nimport { bodyRows, headerRow } from '../_shared/table.tsx'\n\n/** A table's data rows: a native `<tbody>`. Striped and hoverable tables style its rows. */\nconst meta = {\n title: 'Content/TableBody',\n component: TableBody,\n args: { children: bodyRows },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\" striped>\n <TableHead>{headerRow}</TableHead>\n <Story />\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableBody>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"TableCell","category":"Content","description":"A data cell. Give it the column's `label` so stacked rows can show it.\n\n```tsx\n<TableCell label=\"Total\" align=\"end\">$10</TableCell>\n```","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"align","type":"\"center\" | \"start\" | \"end\"","required":false,"default":"'start'","description":"Text alignment in the cell. Use `end` for numbers."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"label","type":"string","required":false,"description":"The column name, shown beside the value when rows stack into cards."}],"styles":{"className":"greese-TableCell","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Table, TableBody, TableCell, TableHead, TableRow } from '@greese/react'\nimport { bodyRows, headerRow } from '../_shared/table.tsx'\n\n/** A data cell. `label` names it when rows stack into cards on phones. */\nconst meta = {\n title: 'Content/TableCell',\n component: TableCell,\n args: { label: 'Total', align: 'end', children: '$95.00' },\n argTypes: { align: { control: 'inline-radio', options: ['start', 'center', 'end'] } },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\" stackBelow=\"sm\">\n <TableHead>{headerRow}</TableHead>\n <TableBody>\n {bodyRows}\n <TableRow>\n <TableCell label=\"Number\">INV-004</TableCell>\n <TableCell label=\"Client\">Umbrella</TableCell>\n <Story />\n </TableRow>\n </TableBody>\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableCell>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The last cell; resize below sm to see its label. */\nexport const Playground: Story = {}\n"},{"name":"TableFoot","category":"Content","description":"The footer row group, for totals: stays a row group when the table stacks.\n\n```tsx\n<TableFoot><TableRow><TableCell label=\"Total\">$420</TableCell></TableRow></TableFoot>\n```","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport {\n Table,\n TableBody,\n TableCell,\n TableFoot,\n TableHead,\n TableRow,\n} from '@greese/react'\nimport { bodyRows, headerRow } from '../_shared/table.tsx'\n\n/** A table's summary rows: a native `<tfoot>`. */\nconst meta = {\n title: 'Content/TableFoot',\n component: TableFoot,\n args: {\n children: (\n <TableRow>\n <TableCell colSpan={2}>Total</TableCell>\n <TableCell align=\"end\">$5,460.50</TableCell>\n </TableRow>\n ),\n },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\">\n <TableHead>{headerRow}</TableHead>\n <TableBody>{bodyRows}</TableBody>\n <Story />\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableFoot>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"TableHead","category":"Content","description":"The header row group: the TableRow of column headers.\n\n```tsx\n<TableHead><TableRow><TableHeaderCell>Name</TableHeaderCell></TableRow></TableHead>\n```","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Table, TableBody, TableHead } from '@greese/react'\nimport { bodyRows, headerRow } from '../_shared/table.tsx'\n\n/** A table's header rows: a native `<thead>`. */\nconst meta = {\n title: 'Content/TableHead',\n component: TableHead,\n args: { children: headerRow },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\">\n <Story />\n <TableBody>{bodyRows}</TableBody>\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableHead>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"TableHeaderCell","category":"Content","description":"A column header; sortable with `onSort` (announced through `aria-sort`).","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"align","type":"\"center\" | \"start\" | \"end\"","required":false,"default":"'start'","description":"Text alignment in the column. Use `end` for numbers."},{"name":"children","type":"ReactNode","required":false,"description":"The column's name."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onSort","type":"(() => void)","required":false,"description":"Makes the header a sort button."},{"name":"sort","type":"SortDirection","required":false,"description":"Current sort of this column. Set `ascending`/`descending` on one column only."}],"styles":{"className":"greese-TableHeaderCell","parts":["sort"],"modifiers":[],"attributes":["[data-sort=ascending]","[data-sort=descending]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Table, TableBody, TableHead, TableHeaderCell, TableRow } from '@greese/react'\nimport { bodyRows } from '../_shared/table.tsx'\n\n/** A column or row header. With `onSort`, a button that reports `aria-sort`. */\nconst meta = {\n title: 'Content/TableHeaderCell',\n component: TableHeaderCell,\n args: { children: 'Total', align: 'end', sort: 'descending', onSort: () => {} },\n argTypes: {\n sort: { control: 'inline-radio', options: ['none', 'ascending', 'descending'] },\n align: { control: 'inline-radio', options: ['start', 'center', 'end'] },\n },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\">\n <TableHead>\n <TableRow>\n <TableHeaderCell>Number</TableHeaderCell>\n <TableHeaderCell>Client</TableHeaderCell>\n <Story />\n </TableRow>\n </TableHead>\n <TableBody>{bodyRows}</TableBody>\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableHeaderCell>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The Total header, sortable. */\nexport const Playground: Story = {}\n\nexport const NotSortable: Story = { args: { sort: undefined, onSort: undefined } }\n"},{"name":"TableRow","category":"Content","description":"One row; a card of label/value pairs when the table stacks.\n\n```tsx\n<TableRow><TableCell label=\"Number\">INV-001</TableCell></TableRow>\n```","file":"packages/react/src/components/Table/Table.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-TableRow","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Table, TableBody, TableCell, TableHead, TableRow } from '@greese/react'\nimport { bodyRows, headerRow } from '../_shared/table.tsx'\n\n/** One row. Below a table's `stackBelow` breakpoint, each row becomes a card. */\nconst meta = {\n title: 'Content/TableRow',\n component: TableRow,\n args: {\n children: (\n <>\n <TableCell label=\"Number\">INV-004</TableCell>\n <TableCell label=\"Client\">Umbrella</TableCell>\n <TableCell label=\"Total\" align=\"end\">\n $95.00\n </TableCell>\n </>\n ),\n },\n decorators: [\n (Story) => (\n <Table caption=\"Invoices\" hoverable stackBelow=\"sm\">\n <TableHead>{headerRow}</TableHead>\n <TableBody>\n {bodyRows}\n <Story />\n </TableBody>\n </Table>\n ),\n ],\n} satisfies Meta<typeof TableRow>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** The last row; resize below sm to see the rows stack. */\nexport const Playground: Story = {}\n"},{"name":"TabList","category":"Content","description":"The row (or column) of tabs. Give it an `aria-label`.","file":"packages/react/src/components/Tabs/Tabs.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-TabList","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Tab, TabList, TabPanel, Tabs, Text } from '@greese/react'\n\n/** The row of tabs inside Tabs: arrow keys move between them. */\nconst meta = {\n title: 'Content/TabList',\n component: TabList,\n args: {\n 'aria-label': 'Project',\n children: (\n <>\n <Tab value=\"overview\">Overview</Tab>\n <Tab value=\"activity\">Activity</Tab>\n <Tab value=\"settings\">Settings</Tab>\n </>\n ),\n },\n decorators: [\n (Story) => (\n <Tabs defaultValue=\"overview\">\n <Story />\n {['overview', 'activity', 'settings'].map((value) => (\n <TabPanel key={value} value={value}>\n <Text>The {value} panel.</Text>\n </TabPanel>\n ))}\n </Tabs>\n ),\n ],\n} satisfies Meta<typeof TabList>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"TabPanel","category":"Content","description":"The content for one tab. Focusable, so keyboard users can reach content\nwith no focusable elements of its own.","file":"packages/react/src/components/Tabs/Tabs.tsx","props":[{"name":"value","type":"string","required":true,"description":"Shown while the Tab of the same value is selected."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-TabPanel","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Tab, TabList, TabPanel, Tabs, Text } from '@greese/react'\n\n/** The content for one tab, shown while that tab is selected. */\nconst meta = {\n title: 'Content/TabPanel',\n component: TabPanel,\n args: {\n value: 'overview',\n children: <Text>The overview panel: whatever belongs to the selected tab.</Text>,\n },\n decorators: [\n (Story) => (\n <Tabs defaultValue=\"overview\">\n <TabList aria-label=\"Project\">\n <Tab value=\"overview\">Overview</Tab>\n <Tab value=\"activity\">Activity</Tab>\n </TabList>\n <Story />\n <TabPanel value=\"activity\">\n <Text>The activity panel.</Text>\n </TabPanel>\n </Tabs>\n ),\n ],\n} satisfies Meta<typeof TabPanel>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n"},{"name":"Tabs","category":"Content","description":"Tabs, per the WAI-ARIA pattern: one tab stop for the whole list, arrow keys\nto move (mirrored in right-to-left), Home/End to jump. Every panel stays in\nthe server-rendered HTML; inactive ones are `hidden`.\n\n```tsx\n<Tabs defaultValue=\"overview\">\n <TabList aria-label=\"Project\">\n <Tab value=\"overview\">Overview</Tab>\n <Tab value=\"activity\">Activity</Tab>\n </TabList>\n <TabPanel value=\"overview\">…</TabPanel>\n <TabPanel value=\"activity\">…</TabPanel>\n</Tabs>\n```","file":"packages/react/src/components/Tabs/Tabs.tsx","props":[{"name":"activation","type":"\"manual\" | \"automatic\"","required":false,"default":"automatic","description":"`automatic` selects a tab as soon as it is focused with the arrow keys;\n`manual` waits for Enter or Space (better when panels are slow to render)."},{"name":"defaultValue","type":"string","required":false,"description":"The tab selected at first, when it keeps its own state."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"onValueChange","type":"((value: string) => void)","required":false,"description":"Called with the newly selected tab's value."},{"name":"orientation","type":"\"horizontal\" | \"vertical\"","required":false,"default":"horizontal","description":"Tabs in a row above the panels (`horizontal`) or a column beside them\n(`vertical`). Sets which arrow keys move between them."},{"name":"value","type":"string","required":false,"description":"The selected tab's value, when you control it. Pair with `onValueChange`."}],"styles":{"className":"greese-Tabs","parts":[],"modifiers":[],"attributes":["[data-orientation=vertical]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Tab, TabList, TabPanel, Tabs, Text } from '@greese/react'\n\nconst sections = [\n 'Overview',\n 'Activity',\n 'Settings',\n 'Members',\n 'Billing',\n 'Integrations',\n]\n\nconst meta = {\n title: 'Content/Tabs',\n component: Tabs,\n subcomponents: { TabList, Tab, TabPanel },\n args: {\n defaultValue: 'overview',\n children: (\n <>\n <TabList aria-label=\"Project\">\n {sections.map((t) => (\n <Tab key={t} value={t.toLowerCase()}>\n {t}\n </Tab>\n ))}\n </TabList>\n {sections.map((t) => (\n <TabPanel key={t} value={t.toLowerCase()}>\n <Text>The {t.toLowerCase()} panel.</Text>\n </TabPanel>\n ))}\n </>\n ),\n },\n} satisfies Meta<typeof Tabs>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Arrow keys move between tabs; on narrow screens the list scrolls sideways. */\nexport const Playground: Story = {}\n\nexport const Vertical: Story = {\n args: {\n orientation: 'vertical',\n defaultValue: 'profile',\n children: (\n <>\n <TabList aria-label=\"Account\">\n <Tab value=\"profile\">Profile</Tab>\n <Tab value=\"security\">Security</Tab>\n <Tab value=\"billing\" disabled>\n Billing\n </Tab>\n </TabList>\n <TabPanel value=\"profile\">Profile settings.</TabPanel>\n <TabPanel value=\"security\">Security settings.</TabPanel>\n </>\n ),\n },\n}\n\n/** `manual`: arrows move focus; Enter or Space selects. */\nexport const ManualActivation: Story = { args: { activation: 'manual' } }\n"},{"name":"Text","category":"Content","description":"Body text: a `<p>` by default. Use `asChild` for any other element.\n\n```tsx\n<Text variant=\"p2\">Body copy that follows the theme's type system.</Text>\n<Text variant=\"p3\" tone=\"muted\" truncate={2}>…</Text>\n<Text asChild weight=\"semibold\"><span>inline</span></Text>\n```","file":"packages/react/src/components/Text/Text.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render another element (`<span>`, `<label>`, `<li>`) with Text's styling."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The rendered element: a `<p>`, or yours with `asChild`."},{"name":"tone","type":"TextTone","required":false,"default":"'neutral'","description":"Text color: neutral, muted, accent, a brand color (primary, secondary,\ntertiary), positive, negative, warning or info."},{"name":"truncate","type":"number | boolean","required":false,"description":"`true` cuts to one line with an ellipsis; a number clamps to that many lines."},{"name":"variant","type":"\"button\" | \"caption\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p1\" | \"p2\" | \"p3\" | \"s1\" | \"s2\"","required":false,"description":"A named text style from the theme's type system (`p1`–`p3`, `s1`, `s2`,\n`caption`, and the heading styles `h1`–`h6`): size, weight, letter spacing,\nline height and more, set for every breakpoint. Without one, the text\ninherits its size from where it sits. Adjust a variant in the theme, or per\ninstance through its `--greese-type-<variant>-*` custom properties."},{"name":"weight","type":"FontWeight","required":false,"description":"Font weight: regular, medium, semibold or bold. Ignored with a `variant`, which sets it."}],"styles":{"className":"greese-Text","parts":[],"modifiers":["accent","bold","clamp","info","medium","muted","negative","neutral","positive","primary","regular","secondary","semibold","tertiary","truncate","warning"],"attributes":[],"variables":["--greese-text-lines"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Stack, Text } from '@greese/react'\n\nconst meta = {\n title: 'Content/Text',\n component: Text,\n args: {\n variant: 'p1',\n children: 'Body text in the p1 style: larger from md up.',\n },\n argTypes: {\n variant: {\n control: 'select',\n options: [\n undefined,\n 'p1',\n 'p2',\n 'p3',\n 's1',\n 's2',\n 'caption',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'button',\n ],\n },\n weight: {\n control: 'inline-radio',\n options: ['regular', 'medium', 'semibold', 'bold'],\n },\n tone: {\n control: 'select',\n options: [\n 'neutral',\n 'muted',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ],\n },\n },\n} satisfies Meta<typeof Text>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** A named style from the type system: size, weight, spacing and line height for every breakpoint. */\nexport const Variants: Story = {\n render: () => (\n <Stack gap={2}>\n {(['p1', 'p2', 'p3', 's1', 's2', 'caption'] as const).map((variant) => (\n <Text key={variant} variant={variant}>\n {variant}: The quick brown fox jumps over the lazy dog.\n </Text>\n ))}\n </Stack>\n ),\n}\n\nexport const Tones: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} wrap=\"wrap\">\n {(\n [\n 'neutral',\n 'muted',\n 'primary',\n 'secondary',\n 'tertiary',\n 'accent',\n 'positive',\n 'negative',\n 'warning',\n 'info',\n ] as const\n ).map((tone) => (\n <Text key={tone} tone={tone} weight=\"semibold\">\n {tone}\n </Text>\n ))}\n </Stack>\n ),\n}\n\n/** `truncate` cuts to one line; a number clamps to that many lines. */\nexport const Truncation: Story = {\n args: {\n variant: 'p2',\n truncate: 2,\n style: { maxInlineSize: '24rem' },\n children:\n 'Clamped to two lines. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.',\n },\n}\n"},{"name":"TEXT_ROTATE_MAX","category":"Other","description":"The most items TextRotate cycles through: one keyframe set is compiled per count.","file":"packages/react/src/components/TextRotate/TextRotate.tsx","props":[]},{"name":"Textarea","category":"Forms","description":"A native `<textarea>`, Field-aware, that grows with its content, in a\nstyled frame like Input's (so a theme's field shape takes it too).\n`className` and `style` go to the frame; every other prop (and `ref`) goes\nto the textarea itself.\n\n```tsx\n<Field label=\"Message\">\n <Textarea name=\"message\" maxRows={8} />\n</Field>\n```","file":"packages/react/src/components/Textarea/Textarea.tsx","props":[{"name":"autosize","type":"boolean","required":false,"default":"true","description":"Grow with the content (CSS `field-sizing`, no JS). Where unsupported, it\nfalls back to a manually resizable box."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"invalid","type":"boolean","required":false,"description":"Marks it invalid (`aria-invalid`) and colors it as an error. A surrounding\nField's `error` sets it too."},{"name":"maxRows","type":"number","required":false,"description":"Cap on autosize growth, in lines."},{"name":"size","type":"ControlSize","required":false,"default":"md","description":"Padding and text size: `sm`, `md` or `lg`. Text stays at least 16px on touch\nscreens."}],"styles":{"className":"greese-Textarea","parts":["control"],"modifiers":["autosize","size-lg","size-md","size-sm","size-xl","size-xs"],"attributes":["[aria-invalid=true]","[data-disabled]","[data-invalid]"],"variables":["--greese-textarea-max-rows","--greese-textarea-padding","--greese-textarea-rows"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Field, Textarea } from '@greese/react'\n\nconst meta = {\n title: 'Forms/Textarea',\n component: Textarea,\n args: { placeholder: 'A few words about you', maxRows: 8 },\n render: (args) => (\n <Field\n label=\"Bio\"\n description=\"Grows as you type (where supported), up to 8 lines.\"\n style={{ maxInlineSize: '28rem' }}\n >\n <Textarea {...args} />\n </Field>\n ),\n} satisfies Meta<typeof Textarea>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** `autosize={false}`: a fixed, manually resizable box. */\nexport const Fixed: Story = { args: { autosize: false, rows: 4 } }\n"},{"name":"TextField","category":"Forms","description":"Field + Input in one: the quick way to a labelled, accessible text input.\n`className` and `style` go to the Field; the rest to the Input.\n\n```tsx\n<TextField label=\"Email\" type=\"email\" name=\"email\" required error={errors.email} />\n```","file":"packages/react/src/components/TextField/TextField.tsx","props":[{"name":"label","type":"ReactNode","required":true,"description":"The visible label. Required: use `hideLabel` to hide it visually."},{"name":"description","type":"ReactNode","required":false,"description":"Help text under the label, announced with the input."},{"name":"endAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, after the text: a unit, a clear button."},{"name":"error","type":"ReactNode","required":false,"description":"Error text. Setting it marks the input invalid."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"hideLabel","type":"boolean","required":false,"description":"Keep the label for screen readers but hide it on screen."},{"name":"invalid","type":"boolean","required":false,"description":"Mark invalid (also set by a surrounding Field's `error`)."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `sm`, `md` or `lg`. Text stays at least 16px\non touch screens."},{"name":"startAdornment","type":"ReactNode","required":false,"description":"Content inside the frame, before the text: an icon, a currency sign."}],"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { TextField } from '@greese/react'\n\nconst meta = {\n title: 'Forms/TextField',\n component: TextField,\n args: { label: 'Full name', name: 'name', autoComplete: 'name' },\n decorators: [(Story) => <div style={{ maxInlineSize: '24rem' }}>{Story()}</div>],\n} satisfies Meta<typeof TextField>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Field + Input in one. */\nexport const Playground: Story = {}\n\nexport const WithDescriptionAndError: Story = {\n args: {\n label: 'Email',\n type: 'email',\n required: true,\n description: \"We'll only use it for receipts.\",\n error: 'Enter an email address like name@example.com',\n },\n}\n"},{"name":"TextRotate","category":"Motion","description":"Cycles through a few words in place, in CSS alone (\"Build *faster* /\n*smaller* / *lighter*\"). Screen readers hear every item once, and under\nreduced motion the first item simply stays.\n\n```tsx\n<Text>Build <TextRotate items={['faster', 'smaller', 'lighter']} /></Text>\n```","file":"packages/react/src/components/TextRotate/TextRotate.tsx","props":[{"name":"items","type":"string[]","required":true,"description":"The words or lines to cycle through: 2 to 6."},{"name":"duration","type":"number","required":false,"default":"2.5","description":"Seconds each item shows, the move included."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."}],"styles":{"className":"greese-TextRotate","parts":["item","track"],"modifiers":["2","3","4","5","6"],"attributes":[],"variables":["--greese-textrotate-duration"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Heading, TextRotate } from '@greese/react'\n\nconst meta = {\n title: 'Motion/TextRotate',\n component: TextRotate,\n args: { items: ['faster', 'smaller', 'lighter'] },\n argTypes: { duration: { control: { type: 'number', min: 0.5, step: 0.5 } } },\n render: (args) => (\n <Heading level={2} variant=\"h2\">\n Build <TextRotate {...args} style={{ color: 'var(--greese-color-primary)' }} />\n </Heading>\n ),\n} satisfies Meta<typeof TextRotate>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** CSS only. Under reduced motion the first word stays. */\nexport const Playground: Story = {}\n\nexport const Slower: Story = {\n args: { items: ['design', 'build', 'ship', 'repeat'], duration: 4 },\n}\n"},{"name":"ThemeProvider","category":"Foundations","description":"Scopes a theme and/or color scheme to its subtree.\n\nCosts nothing per render: the theme's CSS is static (built once by\n`createTheme`) and React hoists and de-duplicates it into `<head>`; the\nwrapper only carries two attributes. Nested providers inherit what they\ndon't set, so a scheme override inside a theme keeps the theme.\n\nThe wrapper is `display: contents`, so it never affects layout.\n\n```tsx\n<ThemeProvider theme={brand} scheme=\"dark\">\n <Card>…</Card>\n</ThemeProvider>\n```","file":"packages/react/src/components/ThemeProvider/ThemeProvider.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Scope your own element instead of rendering a wrapper."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The wrapper `<div>`, or your element with `asChild`."},{"name":"scheme","type":"ColorScheme","required":false,"description":"Force `light` or `dark` for this subtree, or `system` to follow the OS."},{"name":"theme","type":"string | Theme","required":false,"description":"A theme from `createTheme()`, or the name of one whose CSS you load\nyourself, such as a theme compiled with the SCSS kit's `theme()`. Omit to\nonly set a scheme."}],"styles":{"className":"greese-ThemeProvider","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { createTheme, ThemeProvider } from '@greese/react'\nimport { palette } from '@greese/ui'\n\nconst brand = createTheme({\n name: 'docs-brand',\n color: { primary: { light: palette.lavender[600], dark: palette.lavender[300] } },\n radius: { md: '16px' },\n})\n\nconst Card = ({ title }: { title: string }) => (\n <div\n style={{\n padding: 'var(--greese-space-5)',\n background: 'var(--greese-color-surface)',\n color: 'var(--greese-color-fg)',\n border: '1px solid var(--greese-color-border)',\n borderRadius: 'var(--greese-radius-md)',\n }}\n >\n <strong style={{ color: 'var(--greese-color-primary)' }}>{title}</strong>\n <p style={{ color: 'var(--greese-color-fg-muted)' }}>Reads --greese-* tokens only.</p>\n </div>\n)\n\nconst meta = {\n title: 'Foundations/Theming',\n component: ThemeProvider,\n // Its story builds a theme's CSS, which reads as a wall of text in the app's\n // live editor; the story above shows it better.\n parameters: { tryIt: false },\n} satisfies Meta<typeof ThemeProvider>\nexport default meta\n\n/**\n * `createTheme()` builds static CSS once; `ThemeProvider` scopes it with an\n * attribute. Nest providers to force a scheme for one section.\n */\nexport const NestedThemesAndSchemes: StoryObj<typeof meta> = {\n render: () => (\n <div\n style={{\n display: 'grid',\n gap: 'var(--greese-space-4)',\n gridTemplateColumns: 'repeat(auto-fit, minmax(14rem, 1fr))',\n }}\n >\n <Card title=\"Default theme\" />\n <ThemeProvider theme={brand}>\n <Card title=\"Brand theme\" />\n </ThemeProvider>\n <ThemeProvider theme={brand} scheme=\"dark\">\n <Card title=\"Brand, forced dark\" />\n </ThemeProvider>\n <ThemeProvider scheme=\"light\">\n <Card title=\"Default, forced light\" />\n </ThemeProvider>\n </div>\n ),\n}\n"},{"name":"Tile","category":"Layout","description":"A plain, compact surface: a grid cell, a placeholder, a swatch, a small\ndashboard tile. Padding comes from the style props (`p`, `px`…) and\ndefaults to a snug 3 × 4. For structured content (a title, media, actions,\npadding that grows at md) use Card.\n\n```tsx\n<Grid columns={3} gap={3}>\n <Tile>One</Tile>\n <Tile variant=\"dashed\">Drop files here</Tile>\n</Grid>\n```\n\nAccepts every Box style prop and `asChild`. Server-component safe.","file":"packages/react/src/components/Tile/Tile.tsx","props":[{"name":"asChild","type":"boolean","required":false,"description":"Render your own element (a `<section>`, a router `<Link>`) instead of a `<div>`."},{"name":"display","type":"Responsive<Display>","required":false,"description":"The CSS `display` value (`flex`, `grid`, `none`…), per breakpoint if you\nlike: `{ xs: 'none', md: 'block' }` shows it from md up."},{"name":"gap","type":"Responsive<SpaceValue>","required":false,"description":"Space between children, when this element is a flex or grid container: a\nspace token or any CSS length, per breakpoint if you like."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"m","type":"Responsive<SpaceValue>","required":false,"description":"Margin on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 2, md: 4 }`)."},{"name":"maxW","type":"Responsive<string>","required":false,"description":"Maximum inline size, any CSS length."},{"name":"mb","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"me","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ms","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"mt","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"mx","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"my","type":"Responsive<SpaceValue>","required":false,"description":"Margin on the block start and end (top and bottom). A space token or any CSS\nlength, per breakpoint if you like."},{"name":"p","type":"Responsive<SpaceValue>","required":false,"description":"Padding on all four sides: a space token (`0`–`8`, where `4` is 1rem) or any\nCSS length, per breakpoint if you like (`{ xs: 3, md: 5 }`)."},{"name":"pb","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block end (bottom). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"pe","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline end (right in left-to-right text, left in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"ps","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start (left in left-to-right text, right in\nright-to-left). A space token or any CSS length, per breakpoint if you like."},{"name":"pt","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start (top). A space token or any CSS length, per\nbreakpoint if you like."},{"name":"px","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the inline start and end (left and right in English). A space\ntoken or any CSS length, per breakpoint if you like."},{"name":"py","type":"Responsive<SpaceValue>","required":false,"description":"Padding on the block start and end (top and bottom). A space token or any\nCSS length, per breakpoint if you like."},{"name":"ref","type":"Ref<HTMLElement>","required":false,"description":"The `<div>`, or your element with `asChild`."},{"name":"textAlign","type":"Responsive<\"center\" | \"start\" | \"end\" | \"justify\">","required":false,"description":"Text alignment: logical `start` and `end` follow the writing direction. Per\nbreakpoint if you like."},{"name":"variant","type":"\"outline\" | \"filled\" | \"dashed\"","required":false,"default":"filled","description":"`filled` (a surface color with a hairline), `outline` (a border only) or\n`dashed` (a dashed border, for empty slots and drop zones)."},{"name":"w","type":"Responsive<string>","required":false,"description":"Inline size (width in horizontal writing), any CSS length."}],"styles":{"className":"greese-Tile","parts":[],"modifiers":["dashed","filled"],"attributes":[],"variables":["--greese-tile-padding"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Grid, Text, Tile } from '@greese/react'\n\nconst meta = {\n title: 'Layout/Tile',\n component: Tile,\n args: { children: 'A tile' },\n argTypes: {\n variant: { control: 'inline-radio', options: ['filled', 'outline', 'dashed'] },\n },\n} satisfies Meta<typeof Tile>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Playground: Story = {}\n\n/** Filled, outline and dashed (for empty slots and drop zones). */\nexport const Variants: Story = {\n render: () => (\n <Grid container columns={{ xs: 1, sm: 3 }} gap={3}>\n <Tile>Filled</Tile>\n <Tile variant=\"outline\">Outline</Tile>\n <Tile variant=\"dashed\" p={5} textAlign=\"center\">\n <Text variant=\"p3\" tone=\"muted\">\n Drop files here\n </Text>\n </Tile>\n </Grid>\n ),\n}\n"},{"name":"Toaster","category":"Overlays","description":"Where toasts appear: bottom centre on phones, bottom end from `md`. Lives in\nthe top layer, above open dialogs, and announces each toast politely\n(assertively for negative ones) through live regions that are always\npresent, so screen readers reliably pick them up.\n\n```tsx\n<Toaster /> // once, near the root\n\ntoast({ title: 'Saved', tone: 'positive' })\n```","file":"packages/react/src/components/Toast/Toast.tsx","props":[{"name":"dismissLabel","type":"string","required":false,"default":"Dismiss","description":"Accessible name of each dismiss button."},{"name":"label","type":"string","required":false,"default":"Notifications","description":"Accessible name of the region."},{"name":"max","type":"number","required":false,"default":"3","description":"At most this many on screen; older ones queue."}],"styles":{"className":"greese-Toaster","parts":["list"],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, Stack, toast, Toaster } from '@greese/react'\n\nconst meta = {\n title: 'Overlays/Toaster',\n component: Toaster,\n args: { max: 3 },\n render: (args) => (\n <>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n <Button\n onClick={() =>\n toast({\n title: 'Message archived',\n action: {\n label: 'Undo',\n onClick: () => toast({ title: 'Restored', tone: 'positive' }),\n },\n })\n }\n >\n Archive\n </Button>\n <Button\n variant=\"outline\"\n tone=\"negative\"\n onClick={() =>\n toast({\n title: \"Couldn't save\",\n description: 'Check your connection.',\n tone: 'negative',\n })\n }\n >\n Fail\n </Button>\n <Button\n variant=\"outline\"\n tone=\"neutral\"\n onClick={() => toast({ title: 'Stays until dismissed', duration: Infinity })}\n >\n Persistent\n </Button>\n </Stack>\n <Toaster {...args} />\n </>\n ),\n} satisfies Meta<typeof Toaster>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Render one `<Toaster />`, then call `toast()` from anywhere. Hover or focus pauses auto-dismiss. */\nexport const Playground: Story = {}\n"},{"name":"ToggleButton","category":"Forms","description":"A button that stays on or off (`aria-pressed`), like Bold in a toolbar.\nGroup several in an attached ButtonGroup for a segmented control.\n\n```tsx\n<ToggleButton defaultPressed>Bold</ToggleButton>\n```","file":"packages/react/src/components/ToggleButton/ToggleButton.tsx","props":[{"name":"defaultPressed","type":"boolean","required":false,"default":"false","description":"Initial pressed state when uncontrolled."},{"name":"endIcon","type":"ReactNode","required":false,"description":"Decorative icon after the label."},{"name":"fullWidth","type":"Responsive<boolean>","required":false,"description":"Fill the container's width, e.g. `{ xs: true, md: false }` on phones only."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"loading","type":"boolean","required":false,"description":"Shows a spinner and ignores clicks, but stays focusable (`aria-disabled`,\nnot `disabled`) so keyboard focus is not lost mid-action. A submit button\ndoesn't submit while it's loading."},{"name":"onClick","type":"MouseEventHandler<HTMLButtonElement>","required":false,"description":"Called when it's pressed; never while it's loading or disabled."},{"name":"onPressedChange","type":"((pressed: boolean) => void)","required":false,"description":"Called with the new state when it's pressed."},{"name":"pressed","type":"boolean","required":false,"description":"Controlled pressed state."},{"name":"ref","type":"Ref<HTMLButtonElement>","required":false,"description":"The rendered `<button>` (or your element, with `asChild`)."},{"name":"size","type":"ControlSize","required":false,"default":"'md'","description":"Height, padding and text size: `xs`, `sm`, `md`, `lg` or `xl`. Touch targets stay at\nleast 44px."},{"name":"startIcon","type":"ReactNode","required":false,"description":"Decorative icon before the label."},{"name":"tone","type":"ButtonTone","required":false,"default":"neutral","description":"Color role: `accent`, a brand color (primary, secondary, tertiary),\n`neutral`, or `negative` for destructive actions."},{"name":"variant","type":"ButtonVariant","required":false,"default":"outline","description":"Visual weight: `solid` for the main action, `soft`, `outline`, then `ghost`\nfor the least. `text` drops the box and takes the surrounding text's color,\nso the button reads as plain text."}],"styles":{"className":"greese-ToggleButton","parts":[],"modifiers":[],"attributes":["[aria-pressed=true]"],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { ButtonGroup, ToggleButton } from '@greese/react'\n\nconst meta = {\n title: 'Forms/ToggleButton',\n component: ToggleButton,\n args: { children: 'Bold', defaultPressed: false },\n} satisfies Meta<typeof ToggleButton>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Stays on or off (`aria-pressed`). */\nexport const Playground: Story = {}\n\nexport const Toolbar: Story = {\n render: () => (\n <ButtonGroup aria-label=\"Text formatting\" attached>\n <ToggleButton defaultPressed>Bold</ToggleButton>\n <ToggleButton>Italic</ToggleButton>\n <ToggleButton>Underline</ToggleButton>\n </ButtonGroup>\n ),\n}\n\n/** Pressed shows the button's tone; the default `neutral` presses to primary. */\nexport const Toned: Story = {\n render: () => (\n <ButtonGroup aria-label=\"Favourites\" attached>\n <ToggleButton tone=\"secondary\" defaultPressed>\n Starred\n </ToggleButton>\n <ToggleButton tone=\"secondary\">Pinned</ToggleButton>\n </ButtonGroup>\n ),\n}\n"},{"name":"Tooltip","category":"Overlays","description":"A short description shown on hover (mouse), keyboard focus or a tap (touch),\nlinked with `aria-describedby`. Meets WCAG 1.4.13: it can be hovered without\ndisappearing and dismissed with Escape without moving focus.\n\nFor icon-only buttons, the name still comes from the button's own label;\nthe tooltip adds a visible hint for sighted mouse users.\n\n```tsx\n<Tooltip content=\"Copy link\">\n <IconButton label=\"Copy link\"><CopyIcon /></IconButton>\n</Tooltip>\n```","file":"packages/react/src/components/Tooltip/Tooltip.tsx","props":[{"name":"children","type":"ReactElement<unknown, string | JSXElementConstructor<any>>","required":true,"description":"The element it describes: must be focusable (a Button, a link)."},{"name":"content","type":"ReactNode","required":true,"description":"The tooltip text: supplementary, never essential (a touch user sees it only if they tap)."},{"name":"className","type":"string","required":false,"description":"Classes for the tooltip itself (the floating text), not its child."},{"name":"delay","type":"number","required":false,"default":"400","description":"Hover delay before showing, ms. Keyboard focus shows it at once."},{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"openOnTap","type":"boolean","required":false,"default":"true","description":"On touch and pen, tapping the child shows the tooltip as well as doing\nwhat the child does; tapping it again, anywhere else, or Escape hides\nit. Turn it off for a control tapped so often the hint gets in the way."},{"name":"placement","type":"Placement","required":false,"default":"top","description":"Where it shows relative to its child. It flips if there's no room."}],"styles":{"className":"greese-Tooltip","parts":[],"modifiers":[],"attributes":[],"variables":["--greese-motion-enter-ease","--greese-motion-exit-duration","--greese-motion-exit-ease","--greese-motion-exit-mask-from","--greese-motion-exit-mask-image","--greese-motion-exit-mask-position","--greese-motion-exit-mask-repeat","--greese-motion-exit-mask-size","--greese-motion-exit-opacity","--greese-motion-exit-scale","--greese-motion-exit-transform","--greese-motion-exit-transform-origin","--greese-motion-exit-translate","--greese-motion-overlay","--greese-motion-overlay-duration","--greese-motion-overlay-exit-mask-from","--greese-motion-overlay-exit-mask-image","--greese-motion-overlay-exit-mask-position","--greese-motion-overlay-exit-mask-repeat","--greese-motion-overlay-exit-mask-size","--greese-motion-overlay-exit-opacity","--greese-motion-overlay-exit-scale","--greese-motion-overlay-exit-transform","--greese-motion-overlay-exit-transform-origin","--greese-motion-overlay-exit-translate","--greese-motion-tooltip","--greese-motion-tooltip-exit-mask-from","--greese-motion-tooltip-exit-mask-image","--greese-motion-tooltip-exit-mask-position","--greese-motion-tooltip-exit-mask-repeat","--greese-motion-tooltip-exit-mask-size","--greese-motion-tooltip-exit-opacity","--greese-motion-tooltip-exit-scale","--greese-motion-tooltip-exit-transform","--greese-motion-tooltip-exit-transform-origin","--greese-motion-tooltip-exit-translate","--greese-overlay-enter","--greese-overlay-exit-mask-from","--greese-overlay-exit-mask-image","--greese-overlay-exit-mask-position","--greese-overlay-exit-mask-repeat","--greese-overlay-exit-mask-size","--greese-overlay-exit-opacity","--greese-overlay-exit-scale","--greese-overlay-exit-transform","--greese-overlay-exit-transform-origin","--greese-overlay-exit-translate","--greese-overlay-origin"]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Button, IconButton, Stack, Tooltip } from '@greese/react'\nimport { TrashIcon } from '@greese/icons'\n\nconst meta = {\n title: 'Overlays/Tooltip',\n component: Tooltip,\n args: {\n content: 'Copies a share link to your clipboard',\n children: (\n <Button variant=\"ghost\" tone=\"neutral\">\n Share\n </Button>\n ),\n },\n argTypes: {\n placement: {\n control: 'select',\n options: [\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'top',\n 'top-start',\n 'top-end',\n 'start',\n 'end',\n ],\n },\n },\n} satisfies Meta<typeof Tooltip>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Opens on hover after a delay, at once on keyboard focus, and on a tap on touch screens. Never put essential information in one. */\nexport const Playground: Story = {}\n\nexport const Placements: Story = {\n render: () => (\n <Stack direction=\"row\" gap={3} wrap=\"wrap\" p={8}>\n {(['top', 'bottom', 'start', 'end'] as const).map((placement) => (\n <Tooltip key={placement} content={`Placed ${placement}`} placement={placement}>\n <IconButton label={`Delete (${placement})`} variant=\"outline\" tone=\"neutral\">\n <TrashIcon />\n </IconButton>\n </Tooltip>\n ))}\n </Stack>\n ),\n}\n"},{"name":"Video","category":"Content","description":"A native `<video>` in a ratio frame. Defaults suit phones: `controls`,\n`playsInline` (no forced fullscreen on iOS) and `preload=\"metadata\"`.\nAdd captions with a `<track kind=\"captions\">` child.\n\n```tsx\n<Video src=\"/demo.mp4\" poster=\"/demo.jpg\" />\n```","file":"packages/react/src/components/Media/Media.tsx","props":[{"name":"greese","type":"GreeseProp","required":false,"description":"Motion: entrances, scroll reveals, interactions, text effects, timelines."},{"name":"ratio","type":"Responsive<string | number>","required":false,"default":"16 / 9","description":"Width to height, as a number (`16 / 9`) or a string (`'4 / 3'`), per\nbreakpoint if you like."}],"styles":{"className":"greese-Video","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { Video } from '@greese/react'\nimport { art } from '../_shared/fixtures.tsx'\n\nconst meta = {\n title: 'Content/Video',\n component: Video,\n args: { poster: art(30), 'aria-label': 'Product walkthrough' },\n decorators: [(Story) => <div style={{ maxInlineSize: '32rem' }}>{Story()}</div>],\n} satisfies Meta<typeof Video>\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\n/** Native video in a ratio frame: controls, plays inline on iOS. */\nexport const Playground: Story = {}\n\nexport const Square: Story = { args: { ratio: 1 } }\n"},{"name":"VisuallyHidden","category":"Utilities","description":"Hides content visually while keeping it available to screen readers — for\nicon-only buttons, skip links, and extra context on terse labels.\n\n```tsx\n<button>\n <CloseIcon />\n <VisuallyHidden>Close</VisuallyHidden>\n</button>\n```","file":"packages/react/src/components/VisuallyHidden/VisuallyHidden.tsx","props":[],"styles":{"className":"greese-VisuallyHidden","parts":[],"modifiers":[],"attributes":[],"variables":[]},"example":"import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { VisuallyHidden } from '@greese/react'\n\nconst meta = {\n title: 'Utilities/VisuallyHidden',\n component: VisuallyHidden,\n args: { children: 'Close dialog' },\n} satisfies Meta<typeof VisuallyHidden>\n\nexport default meta\n\n/** The hidden text names an icon-only button: screen readers say \"Close dialog\". */\nexport const Playground: StoryObj<typeof meta> = {\n render: (args) => (\n <button type=\"button\">\n <span aria-hidden=\"true\">×</span>\n <VisuallyHidden {...args} />\n </button>\n ),\n}\n\nexport const IconButtonLabel: StoryObj<typeof meta> = {\n render: () => (\n <button type=\"button\">\n <span aria-hidden=\"true\">×</span>\n <VisuallyHidden>Close dialog</VisuallyHidden>\n </button>\n ),\n}\n"}],"tokens":{"color":{"canvas":{"light":"#ffffff","dark":"#11171c"},"surface":{"light":"#f5f7f9","dark":"#2a333c"},"surfaceOverlay":{"light":"#ffffff","dark":"#3c4854"},"fg":{"light":"#11171c","dark":"#e9edf2"},"fgMuted":{"light":"#505e6d","dark":"#a3b3c4"},"border":{"light":"#d7dfe7","dark":"#3c4854"},"borderStrong":{"light":"#a3b3c4","dark":"#505e6d"},"track":{"light":"#d7dfe7","dark":"#687889"},"primary":{"light":"#2771e0","dark":"#81b2ff"},"primaryStrong":{"light":"#1356b8","dark":"#aaccff"},"primaryContent":{"light":"#ffffff","dark":"#11171c"},"secondary":{"light":"#7e5bd0","dark":"#b69fff"},"secondaryStrong":{"light":"#6443ab","dark":"#cdbfff"},"secondaryContent":{"light":"#ffffff","dark":"#11171c"},"tertiary":{"light":"#007069","dark":"#5dcec5"},"tertiaryStrong":{"light":"#00544f","dark":"#94e1da"},"tertiaryContent":{"light":"#ffffff","dark":"#11171c"},"accent":{"light":"#c13b7b","dark":"#ff81b6"},"accentStrong":{"light":"#9c2661","dark":"#ffaecd"},"accentContent":{"light":"#ffffff","dark":"#11171c"},"focusRing":{"light":"var(--greese-color-primary)","dark":"var(--greese-color-primary-strong)"},"positive":{"light":"#007231","dark":"#61cf7e"},"negative":{"light":"#ae0914","dark":"#ff8b7f"},"negativeContent":{"light":"#ffffff","dark":"#11171c"},"warning":{"light":"#8a5f00","dark":"#feb93d"},"info":{"light":"#00668f","dark":"#5ac0f7"},"white":{"light":"#ffffff","dark":"#ffffff"},"black":{"light":"#000000","dark":"#000000"},"scrim":{"light":"color-mix(in srgb, var(--greese-color-black) 45%, transparent)","dark":"color-mix(in srgb, var(--greese-color-black) 60%, transparent)"}},"space":{"0":"0","1":"0.25rem","2":"0.5rem","3":"0.75rem","4":"1rem","5":"1.5rem","6":"2rem","7":"3rem","8":"4rem"},"radius":{"none":"0","sm":"4px","md":"8px","lg":"16px","xl":"24px","pill":"999px","round":"50%"},"corner":{"control":"var(--greese-radius-md)","field":"var(--greese-radius-md)","surface":"var(--greese-radius-lg)","panel":"var(--greese-radius-md)","inset":"var(--greese-radius-sm)","pill":"var(--greese-radius-pill)","round":"var(--greese-radius-round)"},"font":{"body":"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif","mono":"ui-monospace, SFMono-Regular, Menlo, monospace"},"fontWeight":{"regular":"400","medium":"500","semibold":"600","bold":"700"},"lineHeight":{"tight":"1.25","snug":"1.375","normal":"1.5"},"shadow":{"sm":"0 1px 2px color-mix(in srgb, var(--greese-color-black) 8%, transparent)","md":"0 4px 12px color-mix(in srgb, var(--greese-color-black) 12%, transparent)","lg":"0 12px 32px color-mix(in srgb, var(--greese-color-black) 18%, transparent)"},"zIndex":{"dropdown":"1000","sticky":"1100","overlay":"1300","modal":"1400","popover":"1500","toast":"1600","tooltip":"1700"},"duration":{"fast":"120ms","normal":"200ms","slow":"320ms"},"easing":{"standard":"cubic-bezier(0.2, 0, 0, 1)","enter":"cubic-bezier(0, 0, 0, 1)","exit":"cubic-bezier(0.3, 0, 1, 1)"},"breakpoints":{"xs":0,"sm":600,"md":900,"lg":1200,"xl":1536},"palette":{"steel":{"50":"#f5f7f9","100":"#e9edf2","200":"#d7dfe7","300":"#bfcbd8","400":"#a3b3c4","500":"#8597a9","600":"#687889","700":"#505e6d","800":"#3c4854","900":"#2a333c","999":"#11171c"},"gray":{"50":"#f7f7f7","100":"#ededed","200":"#dedede","300":"#cacaca","400":"#b1b1b1","500":"#949494","600":"#767676","700":"#5c5c5c","800":"#464646","900":"#323232","999":"#161616"},"silver":{"50":"#f6f7f7","100":"#ebedee","200":"#dadfe1","300":"#c5cbce","400":"#aab3b7","500":"#8d969b","600":"#6f777c","700":"#565e61","800":"#41474b","900":"#2e3335","999":"#141618"},"ash":{"50":"#f7f7f6","100":"#ededeb","200":"#dfdeda","300":"#cbcac4","400":"#b3b1aa","500":"#97958d","600":"#78766e","700":"#5e5c56","800":"#484641","900":"#33322e","999":"#171614"},"taupe":{"50":"#f8f6f5","100":"#f0ece9","200":"#e4dcd6","300":"#d3c7be","400":"#bdaea2","500":"#a29184","600":"#827366","700":"#67594f","800":"#4f443b","900":"#38302a","999":"#1a1511"},"red":{"50":"#fff4f2","100":"#ffe6e3","200":"#ffd2cc","300":"#ffb4ab","400":"#ff8b7f","500":"#fd4c45","600":"#d52727","700":"#ae0914","800":"#88030c","900":"#620407","999":"#330000"},"orange":{"50":"#fff4ee","100":"#ffe8da","200":"#ffd8c1","300":"#ffc19c","400":"#ff9d5e","500":"#ef7500","600":"#c05d00","700":"#964700","800":"#733400","900":"#522300","999":"#290d00"},"gold":{"50":"#fff5e7","100":"#ffeaca","200":"#ffe1b5","300":"#ffd593","400":"#feb93d","500":"#df9c00","600":"#b37d00","700":"#8a5f00","800":"#664500","900":"#472e00","999":"#211300"},"yellow":{"50":"#fcf8df","100":"#f8efb6","200":"#fce873","300":"#fbe136","400":"#f4d90b","500":"#d3bb00","600":"#ab9700","700":"#817100","800":"#5c5000","900":"#3d3500","999":"#1b1600"},"lime":{"50":"#f2fae9","100":"#e2f4ce","200":"#d2f4a9","300":"#c0ee82","400":"#a6dc51","500":"#87bf0e","600":"#6b9a00","700":"#517600","800":"#3a5600","900":"#263b00","999":"#0e1a00"},"green":{"50":"#effaf1","100":"#dcf5e0","200":"#bdeec6","300":"#95e2a5","400":"#61cf7e","500":"#25b459","600":"#009141","700":"#007231","800":"#005724","900":"#003e17","999":"#001d06"},"jade":{"50":"#eefaf4","100":"#daf4e8","200":"#baedd6","300":"#8ee1be","400":"#54cea1","500":"#00b283","600":"#008e68","700":"#006f51","800":"#00553d","900":"#003c2a","999":"#001c11"},"turquoise":{"50":"#eefaf8","100":"#daf3f0","200":"#bcece7","300":"#94e1da","400":"#5dcec5","500":"#13b3aa","600":"#009088","700":"#007069","800":"#00544f","900":"#003b38","999":"#001b19"},"aqua":{"50":"#eef9fb","100":"#daf2f5","200":"#beecf2","300":"#98e3ec","400":"#64d0de","500":"#23b5c4","600":"#00919f","700":"#00707b","800":"#00545c","900":"#003b41","999":"#001b1e"},"azure":{"50":"#eef9ff","100":"#daf1ff","200":"#bde6ff","300":"#91d6ff","400":"#5ac0f7","500":"#15a4e1","600":"#0082b6","700":"#00668f","800":"#004d6e","900":"#003750","999":"#001927"},"blue":{"50":"#f2f7ff","100":"#e2eeff","200":"#cbdfff","300":"#aaccff","400":"#81b2ff","500":"#4c92ff","600":"#2771e0","700":"#1356b8","800":"#0b4290","900":"#072e68","999":"#001337"},"royal":{"50":"#f4f6ff","100":"#e7ecff","200":"#d4dcff","300":"#bac6ff","400":"#9aaaff","500":"#7787ff","600":"#5963e5","700":"#444abc","800":"#333894","900":"#23276b","999":"#0d0f39"},"lavender":{"50":"#f7f5ff","100":"#edeaff","200":"#dfd8ff","300":"#cdbfff","400":"#b69fff","500":"#9d79f6","600":"#7e5bd0","700":"#6443ab","800":"#4c3285","900":"#362361","999":"#190c33"},"purple":{"50":"#fbf4ff","100":"#f6e6ff","200":"#eed1ff","300":"#e4b4ff","400":"#d78cff","500":"#be68ea","600":"#9d49c5","700":"#7e33a1","800":"#61257d","900":"#46195a","999":"#22062f"},"magenta":{"50":"#fff3fb","100":"#ffe3f7","200":"#ffccf1","300":"#ffa9ea","400":"#f97cde","500":"#e053c6","600":"#bb32a3","700":"#971c83","800":"#761266","900":"#550c49","999":"#2b0124"},"pink":{"50":"#fff3f7","100":"#ffe5ee","200":"#ffcfe0","300":"#ffaecd","400":"#ff81b6","500":"#e75a9a","600":"#c13b7b","700":"#9c2661","800":"#7a1a4a","900":"#581235","999":"#2d0318"},"ruby":{"50":"#fff4f4","100":"#ffe6e8","200":"#ffd0d5","300":"#ffb2ba","400":"#ff8798","500":"#f94b72","600":"#d12655","700":"#aa0b40","800":"#85042f","900":"#600421","999":"#32000b"}},"typography":{"h1":{"base":{"fontSize":"2.25rem","fontWeight":"700","lineHeight":"1.15","letterSpacing":"-0.02em","textWrap":"balance"},"md":{"fontSize":"2.75rem"},"lg":{"fontSize":"3.5rem","lineHeight":"1.1"}},"h2":{"base":{"fontSize":"1.875rem","fontWeight":"700","lineHeight":"1.2","letterSpacing":"-0.015em","textWrap":"balance"},"md":{"fontSize":"2.25rem"},"lg":{"fontSize":"2.75rem"}},"h3":{"base":{"fontSize":"1.5rem","fontWeight":"600","lineHeight":"1.25","letterSpacing":"-0.01em","textWrap":"balance"},"md":{"fontSize":"1.75rem"},"lg":{"fontSize":"2rem"}},"h4":{"base":{"fontSize":"1.25rem","fontWeight":"600","lineHeight":"1.3","letterSpacing":"0","textWrap":"balance"},"md":{"fontSize":"1.375rem"},"lg":{"fontSize":"1.5rem"}},"h5":{"base":{"fontSize":"1.125rem","fontWeight":"600","lineHeight":"1.35","letterSpacing":"0","textWrap":"balance"},"md":{"fontSize":"1.25rem"}},"h6":{"base":{"fontSize":"1rem","fontWeight":"600","lineHeight":"1.4","letterSpacing":"0","textWrap":"balance"},"md":{"fontSize":"1.0625rem"}},"s1":{"base":{"fontSize":"1.25rem","fontWeight":"500","lineHeight":"1.4","letterSpacing":"0"},"md":{"fontSize":"1.375rem"}},"s2":{"base":{"fontSize":"1.125rem","fontWeight":"500","lineHeight":"1.45","letterSpacing":"0"}},"p1":{"base":{"fontSize":"1.125rem","fontWeight":"400","lineHeight":"1.6","letterSpacing":"0"},"md":{"fontSize":"1.25rem"}},"p2":{"base":{"fontSize":"1rem","fontWeight":"400","lineHeight":"1.55","letterSpacing":"0"}},"p3":{"base":{"fontSize":"0.875rem","fontWeight":"400","lineHeight":"1.5","letterSpacing":"0"}},"caption":{"base":{"fontSize":"0.75rem","fontWeight":"400","lineHeight":"1.4","letterSpacing":"0.02em"}},"button":{"base":{"fontSize":"0.9375rem","fontWeight":"600","lineHeight":"1.25","letterSpacing":"0"}}}},"icons":["AccessibilityIcon","ArchiveIcon","ArrowRightIcon","BellIcon","CartIcon","CheckIcon","CheckDashIcon","ChevronDownIcon","ChevronLeftIcon","ChevronRightIcon","CloseIcon","ContrastIcon","CopyIcon","DocumentIcon","DotsIcon","FeatherIcon","FolderIcon","GithubIcon","HeartIcon","HomeIcon","ImportIcon","InboxIcon","InfoIcon","InspectIcon","LayersIcon","MenuIcon","MinusIcon","MoonIcon","MotionIcon","PhoneIcon","PlusIcon","ReplayIcon","SaveIcon","SearchIcon","SendIcon","ServerIcon","ShapesIcon","ShapesFilledIcon","SlidersIcon","SortIcon","SpeedIcon","SpeedFilledIcon","StarIcon","StarFilledIcon","SunIcon","TrashIcon","TrendDownIcon","TrendUpIcon","UserIcon"],"guides":[{"name":"Accessibility","title":"Accessibility","text":"# Accessibility\n\nWhat greese ui guarantees, and what stays your job.\n\n## Built in\n\n- **Native semantics.** Controls are real `<button>`, `<input>`, `<select>`,\n `<textarea>`, `<dialog>` and `<details>` elements, restyled, with native keyboard\n behaviour, form submission and screen-reader roles.\n- **Labelled fields.** `Field`/`TextField` wire label, description and error to the\n control (`aria-describedby`, `aria-invalid`). Descriptions are never folded into a\n checkbox's name.\n- **WAI-ARIA patterns** for Tabs, Menu, Accordion, Dialog and Tooltip (WCAG 1.4.13:\n hoverable, dismissible with Escape).\n- **Focus.** A visible focus ring on every control; dialogs trap and _reliably_\n return focus (including Safari, which doesn't focus buttons on click).\n- **Touch.** 44×44px hit areas on coarse pointers; control text never below 16px on\n phones, so iOS doesn't zoom.\n- **Motion.** Durations collapse under `prefers-reduced-motion`; spinners pulse\n instead of spinning; skeletons stop shimmering.\n- **Announcements.** Toasts announce through always-present live regions (assertive for\n errors) and stay usable above open dialogs. Static alerts don't interrupt.\n- **Tested** with axe in unit tests and with keyboard and touch in Chromium, Firefox,\n WebKit and an emulated iPhone.\n\n## Your job\n\n- Give every `IconButton` a `label` (required by its types), images real `alt` text,\n embeds a `title`, and menus/tab lists an `aria-label`.\n- Don't put essential information only in tooltips: touch users can't hover, and\n see one only after tapping the control.\n- Keep text contrast when theming: the default palette meets WCAG AA; custom colors\n are yours to check.\n- Use `Heading level` for the document outline and `size` for looks."},{"name":"Animation","title":"Animation in greese ui","text":"# Animation in greese ui\n\ngreese ui animates on three levels, from least to most code:\n\n| Level | What | Costs |\n| -------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| **The `greese` prop** | Presets and options on any component: entrances, scroll reveals, hover/press/focus, text effects, overlay exits | Presets: CSS only. Interactions and text: a small runtime, loaded on first use |\n| **`<Motion>` and `useGreese()`** | The prop for any element; greese.js tied to a component's lifetime | The same, plus what you build |\n| **greese.js directly** | Full timelines, re-exported from `@greese/react` | About 5.6 kB, only if imported |\n\nThe live demos are under **Motion/greese prop** and **Motion/greese.js**.\ngreese.js on its own, in every install form, is covered in\n**Guides/greese.js**.\n\n## Do you need any of it?\n\nComponents already animate their own states (menus, dialogs, toasts,\ntooltips) with CSS. That runs off the main thread, and the `--greese-duration-*`\ntokens collapse it under reduced motion. Add motion where it helps\nsomeone follow what changed, not everywhere.\n\n## The `greese` prop\n\nEvery greese ui component that draws something accepts `greese`. That's all of\nthem except Slot, VisuallyHidden, Break, Spacer, Show/Hide, ThemeProvider and\nToaster; a type check in the build enforces it.\n\n```tsx\n<Card greese=\"fadeUp\" /> // enter preset\n<Card greese={{ inView: 'fadeUp' }} /> // when scrolled into view\n<Stack greese={{ enter: 'fadeUp', stagger: 0.05 }}>…</Stack> // children in turn\n<Button greese={{ hover: 'rise', press: 'squish' }} /> // interaction feedback\n<Heading greese={{ text: 'split' }}>Served fast</Heading> // text effects\n<Dialog greese={{ enter: 'pop', exit: 'scaleOut' }} … /> // overlay enter and exit\n<Card greese=\"fadeIn+scaleIn,+2,fadeOut\" /> // a sequence of effects\n<Card greese=\"fadeUp,wobble\" /> // with your own effect\n```\n\n### Options\n\n| Option | Values | Needs JavaScript? |\n| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |\n| `enter` | An effect, a [sequence](#composing-effects), or greese.js keyframes | A preset alone: no. Else: yes |\n| `inView` | The same; plays once wholly in view, clear of the bottom 10% of the viewport (taller elements: half the viewport). Elements already in view stay as they are | Yes (an IntersectionObserver) |\n| `once` | `inView` plays only the first time (default `true`) | |\n| `exit` | An effect: how an overlay (Dialog, Popover, Menu, Tooltip) leaves. It fades, and moves and scales to where the effect ends (`'fadeOutUp'`, `'scaleOut'`, `'rise'`…) | No |\n| `hover`, `press`, `focus` | Usually `'rise'`, `'squish'`, `'tilt'`, `'glow'`; any effect, sequence or keyframes. Plays and reverses; interruptible. Hover ignores touch | Yes |\n| `text` | `'type'`, `'count'`, `'split'`, for plain-text content | Yes |\n| `duration`, `delay` | Seconds. `duration` applies to each effect and overrides an effect's own. Defaults: 0.5 for entrances, 0.2 for interactions | |\n| `ease` | Any greese.js ease. `linear`, `in`, `out`, `inOut`, the CSS keywords and bézier arrays stay CSS-only; others (`elastic.out`…) switch the entrance to JavaScript | |\n| `distance` | How far the travelling effects go (`fadeUp`, `fadeDown`, `fadeStart`, `fadeEnd`, `fadeOutUp`, `fadeOutDown`; default `'1rem'`). A call's own `distance` argument wins | |\n| `stagger` | Seconds between children: animates the children instead of the element | |\n| `scope` | `true` or `{ stagger, delay, inView, replay }`: orders every `enter` inside this element, at any depth (see Scopes) | No (a small lazy chunk) |\n| `timeline` | `(tl, el) => void`: fill a greese.js timeline yourself. It plays on enter, or on reveal with `inView` | Yes |\n\n### Scopes: ordering the entrances inside a parent\n\n`stagger` animates a parent's direct children. A **scope** orders every entrance\ninside it, however deep, as one sequence:\n\n```tsx\n<Stack greese={{ scope: { stagger: 0.1, delay: 0.2 } }}>\n <Heading greese={{ enter: 'fadeUp' }}>Title</Heading>\n <Text greese={{ enter: 'fadeUp' }}>Intro</Text>\n <Grid greese={{ scope: { stagger: 0.05 } }}>\n {cards.map((c) => (\n <Card greese={{ enter: 'scaleIn' }}>…</Card>\n ))}\n </Grid>\n</Stack>\n```\n\nEach member declares only its own entrance; the scope gives it a start time:\n`delay + position × stagger`, in document order. A scope inside a scope takes\none position in the outer one and its members start from there, so a section's\ncontents play as a block in the page's sequence. `inView: true` holds the whole\nscope until it scrolls into view. `replay` plays the scope again in place, without remounting: change it (a counter a Replay button bumps) and every entrance restarts. Members still use their own `duration`,\n`ease` and `delay` (which adds to the start time).\n\nIt's opt-in on purpose. A scope is a client component that loads a small lazy\nchunk (under 1 kB), and nothing else changes: components without one pay\nnothing, and the entrances are the same CSS animations, so reduced motion and\nserver components behave as before. Things to know:\n\n- Members are the entrances present when the page renders; children added\n later play as they appear, unordered.\n- With server rendering, entrances begin at first paint, before the page is\n interactive; a scope sets their start times when it hydrates. Use `inView`\n for sections below the fold, or the `@greese/react/greese` import so start\n times are set before the first frame.\n- Scroll reveals (`inView` on a member) keep their own trigger and aren't\n ordered by a scope.\n\n### Effects\n\nEffect names are camelCase. Every effect is defined once, in `@greese/ui`\n(`src/effects/definitions.ts`), in two groups:\n\n- **Base effects** animate one property each, and take optional parameters. Every\n parameter has a default, so you name only what you change.\n- **Combo effects** are made of base effects, each placed in time as a share of\n the combo (`popIn` is `pop` plus a `fadeIn` over its first 60%).\n\n| Group | Effect | Animates | Parameters (defaults) |\n| ----- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |\n| Base | `fadeIn`, `fadeOut` | opacity | `start`, `end` (`0`→`1`, `1`→`0`) |\n| Base | `scaleIn`, `scaleOut` | scale | `start`, `end` (`0`→`1`, `1`→`0`) |\n| Base | `blurIn`, `blurOut` | blur, in px | `start`, `end` (`8`→`0`, `0`→`8`) |\n| Base | `slideUp`, `slideDown`, `slideRight`, `slideLeft` | translation (physical directions) | `start`, `end` (`'100%'`→`'0%'`, `'-100%'`→`'0%'`, `'-100%'`→`'0%'`, `'100%'`→`'0%'`) |\n| Base | `pop` | a springy scale | `start` `1`, `end` `1`, `peak` `1.075`, `peakAt` `0.6` |\n| Base | `squish`, `tilt`, `glow` | scale, rotation, brightness | `start`, `end` (`1`→`0.96`, `0`→`-2`, `1`→`1.12`) |\n| Base | `wipe<Dir>`: `Right`, `Left`, `Up`, `Down`, `DownRight`, `DownLeft`, `UpRight`, `UpLeft` | a mask: the edge sweeps that way, revealing the element | `start`, `end` (the mask's sizes) |\n| Base | `wipeOut<Dir>`, the same eight | a mask: the edge sweeps that way, covering it (leaves) | `start`, `end` |\n| Base | `wipeOpenX`, `wipeOpenY`, `wipeCloseX`, `wipeCloseY` | a mask from or to the middle, across or down | `start`, `end` |\n| Base | `irisIn`, `irisOut` | an opening in the element's proportions, from or to the middle | `start`, `end` (the mask's sizes: `0% 0%`→`142% 142%`, just past the corners) |\n| Base | `iris<Dir>`, `irisOut<Dir>`, the same eight | an opening that closes toward that side or corner; arriving, it opens from there: its exit reversed | `start`, `end` |\n| Combo | `fadeUp`, `fadeDown`, `fadeStart`, `fadeEnd` | fade + a slide of `distance` (`fadeStart`/`fadeEnd` follow the writing direction) | `distance` (`1rem`) |\n| Combo | `fadeOutUp`, `fadeOutDown` | fade out + a slide of `distance` | `distance` (`1rem`) |\n| Combo | `popIn`, `popOut` | pop + a fade | `start`/`end`, `peak`, `peakAt` |\n| Combo | `pocket<Dir>`, `pocketOut<Dir>`, the same eight | rises out of (or sinks into) a slot at its own edge: a slide and a wipe in step | `distance` (`'100%'`: its whole size, so it starts or ends out of sight) |\n| Combo | `rise`, `fall` | a lift or drop + a scale | `lift` `-4` / `drop` `4` (px), `scale` `1.02` / `0.98` |\n| Base | `turnX`, `turnY`, `hinge`, `depth` | a turn about the horizontal or vertical axis (`hinge`: about the top edge), or a move along the line of sight, as `transform` with its own perspective | `start`, `end` (degrees; px for `depth`) |\n| Combo | `flipUp`, `flipDown`, `flipLeft`, `flipRight`, and `flipOut<Dir>` | turns into place from 75° toward the way it arrives (and back out the same way), with a fade | `angle` (`75`) |\n| Base | `flipOver<Dir>`, `flipOverOut<Dir>`, the same four | half a turn, a panel's two faces: arriving from its back, leaving to it, the same way, its back face hidden (a pair is a card turning over) | `start`, `end` (degrees: `±180`→`0`, `0`→`±180`) |\n| Combo | `depthIn`, `depthOut` | rises out of the page from behind it, or sinks back in, with a fade | `depth` (`-240`, px) |\n| Combo | `swingIn`, `swingOut` | swings down from its top edge like a sign, or back up | `angle` (`-80`) |\n| Yours | Anything defined with [`defineGreeseEffect()`](#custom-effects) or in Theme Studio | | `duration`, `offset`, `ease` |\n\nWipes, irises and pockets animate a **mask**, never `clip-path`: the clip\nbelongs to an element's shape (ADR 0024), and a mask composes with it. The mask\nexists only while the effect plays. Each arrives and leaves (`wipeRight` and\n`wipeOutRight`, `irisUp` and `irisOutUp`, `pocketUp` and `pocketOutUp`), in eight\ndirections; wipes and irises also from or to the middle. Leaving ones are\noverlay exits too (`<Dialog greese={{ exit: 'pocketOutDown' }}>`): an exit sets\neverything an overlay moves to, so what it doesn't move stays put, and the\noverlay holds the mask as it closes, from the size the mask starts at.\n\nFlips, swings and depth are three-dimensional: they animate `transform`, with\nits own `perspective()`, so they foreshorten anywhere, need no `perspective` on\na parent, and compose with the `translate`, `rotate` and `scale` the other\neffects animate. An overlay can leave with one too: its exit carries the\n`transform` (and, for a swing, the pivot).\n\nA built-in always does what its name says. Motion themes don't change effects:\nthey choose which one plays where (the `'theme'` entrance, tab panels, table\nrows, overlays; see Theming, ADR 0025).\n\n`greese=\"theme\"` (or `{ enter: 'theme' }`, `{ inView: 'theme' }`) plays whatever\nentrance the theme assigns, `fadeUp` in the base theme. Use it for general\nreveals, so a page arrives the way its theme does; name an effect where the\nmotion means something.\n\nThere is no list of \"entrance\" or \"leaving\" effects, because the kind of an\neffect is where it ends:\n\n- an effect that ends at the element's resting state (opacity 1, no offset, no\n scale) is a **CSS preset** when played alone: `greese=\"fadeUp\"` is plain CSS;\n- one that ends away from it (`fadeOut`, `rise`, `scaleOut`…) runs in the\n runtime, and an overlay can **leave** with it: `exit` takes the `translate`\n and `scale` where the effect ends, and fades.\n\nAny effect works in any slot (`enter`, `inView`, `hover`, `press`, `focus`):\n`hover: 'pop'` is allowed, if unusual. An effect that ends hidden (`fadeOut`)\nstays hidden.\n\n### Composing effects\n\nA sequence is one string:\n\n- **`+`** plays effects at the same time;\n- **`,`** separates groups, and each group starts when the previous one ends;\n- **a number** (`2`, `+2`, `0.5`) is a pause, in seconds; a **negative** one (`-0.2`) backs the next step up, so it overlaps the one before: `slideUp,-0.2,popIn`.\n\n```tsx\n<Card greese=\"fadeIn+scaleIn,+2,fadeOut\" /> // in together, wait 2 s, fade out\n<Card greese={{ enter: 'fadeUp,pop', duration: 0.3 }} /> // each effect 0.3 s\n<Stack greese={{ inView: 'fadeStart+blurIn', stagger: 0.05 }}>…</Stack>\n<Button greese={{ hover: 'rise+glow' }} /> // interactions compose too\n```\n\n- Sequences run in greese.js, so they load the runtime. A preset on its own\n stays pure CSS.\n- `delay` comes before the first group; `stagger` offsets each child within\n every group, and a group ends when its last child finishes.\n- The first group's first frames show during `delay`, so nothing flashes.\n- Sequences are typed: a single name must be a known effect (typos fail to\n compile), and any string with `+`, `,` or parentheses is accepted as a\n sequence. Unknown names in a sequence are skipped with a console warning.\n\n### Effect arguments\n\nAn effect takes arguments in parentheses. Nothing is required: only what you\nwrite changes.\n\n```tsx\n<Card greese=\"fadeIn(0.25, 0.8)\" /> // by position: start, end\n<Card greese=\"fadeIn({ end: 0.8, duration: 1 })\" /> // an object: only these keys\n<Card greese=\"fadeIn(end: 0.8)\" /> // or key: value, key=value\n<Card greese=\"fadeUp(2rem)+scaleIn(offset: 0.2)\" /> // a combo's own parameter, a timing key\n<Card greese=\"slideUp(calc(1rem + 2px), 0)\" /> // commas and + inside parentheses are fine\n```\n\nPositional arguments fill the effect's parameters in the order of the table,\nthen the timing keys, so the signature is\n`someEffect(start, end, duration, offset, ease)`. Every effect, base, combo or\nyours, takes the timing keys:\n\n| Key | What |\n| ---------- | -------------------------------------------------------------------------------------------------------------------------------- |\n| `duration` | Seconds this effect takes. Wins over the instance's `duration`, which wins over the effect's own default |\n| `offset` | Seconds after its step starts. Inside a `+` group it staggers one effect from the others; a group ends when its last effect does |\n| `ease` | A greese.js ease for this effect. Wins over the instance's `ease` |\n\nArguments make the runtime play the effect, since CSS can't take them. Inside a\ncombo the base effects have their own timing, as shares of the combo (a\n`popIn`'s fade covers its first 60%); the combo's `duration` and `offset` move\nall of it.\n\n### Custom effects\n\nDefine an effect once, then use it by name anywhere, alone or in sequences:\n\n```ts\n// effects.ts: import it from your client entry (or a 'use client' module)\n\n// Keyframes\ndefineGreeseEffect('wobble', { rotate: [0, -6, 6, -3, 0] })\n\n// A function of { el, distance, rtl, args }, for effects that adapt;\n// `args` holds what the call wrote by name: drift({ amount: '2rem' })\ndefineGreeseEffect('drift', ({ distance }) => ({\n y: [`calc(${distance} * 3)`, '0rem'],\n opacity: [0, 1],\n}))\n\n// Keyframes with their own defaults (a prop's duration/ease still wins)\ndefineGreeseEffect('spin', {\n keyframes: { rotate: [0, 360] },\n duration: 0.8,\n ease: 'inOut',\n})\n\n// Make the names type-check and autocomplete\ndeclare module '@greese/react' {\n interface GreeseEffectRegistry {\n wobble: true\n drift: true\n spin: true\n }\n}\n```\n\nTo read the built-in effects as plain keyframes (to list or edit them, as Theme\nStudio's Motion tab does), `describeGreeseEffects(distance?)` resolves to every\nname's keyframes at that distance.\n\n```tsx\n<Card greese=\"fadeUp,wobble\" />\n<Card greese={{ inView: 'drift', distance: '2rem' }} />\n<Button greese={{ hover: 'wobble', duration: 0.4 }} />\n```\n\n- **Keyframes** are greese.js keyframes: every property greese.js animates\n (individual transforms, CSS, custom properties, colors), arrays per\n property or a list of keyframe objects with `offset` and `ease`.\n- **A built-in's name stays the built-in's.** An effect defined under it is never played, and the kit's `effect()` mixin refuses the name, so `fadeUp` fades up under every theme. Give yours a name of its own and assign it where it should play. The kit's `effect()` writes its CSS, for a preset played alone and for an overlay's `exit`: Theme Studio's Motion tab writes both (and copies a built-in to start from), so the kit's `motion(enter:)`, `motion(exit:)` and `motion-defaults()` accept it.\n- **Server Components** can use defined effects, because a name is just a\n string. The definition must run on the client before the element mounts:\n call `defineGreeseEffect()` from a module your client bundle imports at\n start-up, not from a Server Component.\n- **`exit` takes any effect**, yours too. A built-in's exit is CSS (a class sets\n what it changes). For one from `defineGreeseEffect()` there is no class, so\n the runtime sets the `translate` and `scale` where its keyframes end, on the\n overlay, from the same plan the build makes for the built-ins; it loads the\n runtime, like any effect of your own. Opacity is always faded.\n- **Positional arguments** of your own effect fill `duration`, `offset`, `ease`\n (`wobble(0.6)` is a 0.6 s wobble); its other arguments are by name.\n\n### How it stays light\n\n- **CSS presets have no JavaScript.** `greese=\"fadeUp\"` resolves to a class\n and a few custom properties during render. That works in Server\n Components, the first paint is already animating, and nothing flashes.\n- **The runtime loads only when needed.** Interactions, scroll reveals, text\n effects, keyframes and timelines need a small runtime plus greese.js\n (about 10.8 kB together). Components load it with a dynamic `import()`, so\n your bundler puts it in its own chunk, fetched the first time a prop needs\n it. A page with no such prop never downloads it.\n- **The cost to every component** is about 1.4 kB (brotli), paid once per\n app: the resolver, the client island that attaches the runtime, and the\n names of the effects CSS can play (so a preset never loads the runtime).\n\n### Loading the runtime up front\n\nA JavaScript entrance (keyframes, text effects, timelines) can't start until\nthe runtime arrives. If that's on the first screen, import it once at your\nentry point, so it's in the main bundle and attaches before the first paint:\n\n```ts\n// main.tsx, or app/layout.tsx\n```\n\nWithout it, everything still works; the runtime simply loads on first use.\n\n**Prefer CSS presets on the first screen instead.** Attaching the runtime\nbefore the first paint means the first full style calculation happens inside\na JavaScript task. On the greese ui homepage, with a few dozen animated\nelements above the fold, that was most of 650 ms of blocking time on a\nthrottled phone. With CSS presets (`fadeUp`, `scaleIn`, `pop` and so on, with\n`delay` and `stagger`) up top and the runtime left lazy, Total Blocking Time\nfell to 20 ms. Hover and press effects attaching a moment later are invisible.\n\n### Server Components and SSR\n\n- Presets and options render on the server: the classes and variables are in\n the HTML, and the animation starts with the first paint.\n- Interactions, reveals and text effects attach after hydration.\n- `timeline` takes a function, and functions can't cross from a Server\n Component to the client. Use it from a client component (`'use client'`).\n\n### Per-component CSS\n\nWith `@greese/react/styles.css`, the presets are included. If you import\nper-component stylesheets instead, add the presets once:\n\n```ts\n```\n\n### Reduced motion\n\nUnder `prefers-reduced-motion: reduce`:\n\n- CSS presets don't run, and nothing is ever hidden;\n- interactions don't move;\n- text stays as written;\n- scroll reveals show at once;\n- sequences cut from effect to effect with no delay, but pauses still wait,\n so `'fadeIn,+2,fadeOut'` is still readable for two seconds;\n- `timeline` jumps to its end (a sequence with a `timeline` too jumps with it).\n\nYou don't need to check the media query yourself.\n\n### Tuning motion globally\n\nThe presets read CSS custom properties. Override them in your CSS (for\nexample per brand) and every `greese` prop follows:\n\n```css\n:root {\n --greese-ease-out: cubic-bezier(0.2, 0.8, 0.2, 1); /* the default ease */\n}\n.calm {\n --greese-motion-duration: 0.8s;\n --greese-motion-distance: 0.5rem;\n}\n```\n\n| Variable | Default |\n| ------------------------------------- | --------------------------------------------- |\n| `--greese-motion-duration` | `0.5s` |\n| `--greese-motion-delay` | `0s` |\n| `--greese-motion-distance` | `1rem` |\n| `--greese-motion-ease` | `var(--greese-ease-out)` |\n| `--greese-ease-in`, `-out`, `-in-out` | The power2 curves behind `in`, `out`, `inOut` |\n\nA per-instance option (`greese={{ duration: 0.3 }}`) wins over these.\n\n## `<Motion>`: the prop for any element\n\n```tsx\n\n<Motion greese=\"fadeUp\"><img src={hero} alt=\"\" /></Motion> // wraps in a <div>\n<Motion asChild greese={{ hover: 'rise' }}><a href=\"/pricing\">Pricing</a></Motion>\n```\n\n## `useGreese()`: greese.js in a component\n\ngreese.js tied to a component's lifetime. It runs your build after mount (refs\nare set) and before paint, re-runs it when dependencies change, and reverts\neverything on unmount, including animations you start later in event\nhandlers. Selector strings only match inside `scope`, so two instances of a\ncomponent never animate each other.\n\n```tsx\n'use client'\n\n const root = useRef<HTMLDivElement>(null)\n const { animate } = useGreese(\n (g) => {\n g.timeline().from('.tile', { opacity: 0, y: 16, stagger: 0.05 })\n },\n { scope: root, dependencies: [items.length] }\n )\n return (\n <div ref={root}>\n {items.map((item) => (\n <div key={item} className=\"tile\">\n {item}\n </div>\n ))}\n <Button onClick={() => animate('.tile', { y: [0, -8, 0] }, { duration: 0.4 })}>\n Bounce\n </Button>\n </div>\n )\n}\n```\n\n`useGreese(build?, dependencies | config)`:\n\n| Config | What |\n| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |\n| `scope` | A ref. Selector strings passed to the context's methods, and to the timelines it makes, only match inside it |\n| `dependencies` | Re-run the build when these change (default `[]`). Pass the array instead of a config as a shorthand: `useGreese(build, [x])` |\n| `revertOnUpdate` | On a dependency change, revert the last build before re-running. Default `false`: it's paused where it is, so the new build continues smoothly |\n\n`build` gets a context, `g`, and may return a cleanup function. The hook\nreturns the same helpers, stable across renders, for use in handlers:\n\n| Helper | What |\n| -------------------------------- | -------------------------------------------------------------------------------------- |\n| `timeline(options?)` | A greese.js timeline: tracked, and its `to`/`from`/`fromTo`/`set`/`animate` are scoped |\n| `animate(targets, kf, opts?)` | Like greese.js `animate()`: plays at once, tracked and scoped |\n| `select(selector)` | The matching elements inside `scope` |\n| `contextSafe((g, ...args) => …)` | Wraps a handler so it receives `g` first; the same as using the helpers directly |\n\n- **Make animations through `g`** (or the returned helpers). A `timeline()`\n or `animate()` imported from greese.js directly isn't tracked, so it isn't\n reverted.\n- **Strict Mode** is fine: the first build is reverted before the second.\n- **Reverting** restores each property's original computed value as an\n inline style; it doesn't remove the inline style.\n- **Server rendering:** the build never runs on the server.\n\n### `useTimeline()`\n\nThe one-timeline shortcut, built on `useGreese` (with `revertOnUpdate`). It\nreturns the timeline, `undefined` until the first build:\n\n```tsx\nconst box = useRef<HTMLDivElement>(null)\nconst tl = useTimeline(\n (tl) => tl.animate(box.current, { x: [0, -8, 8, -4, 0] }, { duration: 0.4 }),\n [],\n { paused: true }\n)\n<Button onClick={() => tl?.restart()}>Try again</Button>\n```\n\n## Page transitions\n\nWhen the page changes, `PageTransition` plays the old page's exit and the new\npage's entrance with the same effects, paced by the motion theme. A page\nleaves as a snapshot, or live, its members' exits playing in turn. See\n[Page transitions](?path=/docs/guides-page-transitions--docs).\n\n## greese.js directly\n\nEverything in **Guides/greese.js** works with greese ui components and\ntokens. Animate a token and every component that reads it follows:\n\n```ts\n\ntimeline({ repeat: 1, yoyo: true }).to('.promo', {\n '--greese-color-primary': '#e11d48',\n duration: 1,\n})\n```"},{"name":"ComponentReference","title":"Component reference","text":"# Component reference\n\nEvery component's classes, generated from the library's stylesheets, as is the\nStyling section on each component's page. The same data ships as\n`@greese/ui/style-manifest.json`. **Guides/Styling components** explains the\nnames and how to override them.\n\n## Every component\n\n<ComponentReference />"},{"name":"GettingStarted","title":"Getting started","text":"# Getting started\n\n```bash\nnpm install @greese/react\n```\n\nThis also installs `@greese/ui`, the framework-free CSS and tokens it renders,\nand `@greese/js`, for the `greese` prop. Requires React 19.\n\nImport the stylesheet once, at your app root:\n\n```tsx\n```\n\nThen use components anywhere. Layout and display components are server-component\nsafe; interactive ones are marked `'use client'`.\n\nNo provider is needed to use greese ui: the styles load once and every component works. `ThemeProvider` is optional (see Guides/Theming). Reach for it only to apply a `createTheme()` theme, or to force a color scheme, on all or part of the page.\n\n```tsx\n\n <Stack gap={4} maxW=\"24rem\">\n <TextField label=\"Email\" type=\"email\" name=\"email\" required />\n <Button type=\"submit\" fullWidth={{ xs: true, sm: false }}>\n Sign in\n </Button>\n </Stack>\n)\n```\n\n## Without a framework\n\nThe CSS is its own package, `@greese/ui`, with no dependencies. Use it from\nplain HTML, or under a framework that has no greese ui package yet:\n\n```bash\nnpm install @greese/ui\n```\n\n```html\n<link rel=\"stylesheet\" href=\"node_modules/@greese/ui/dist/greese.css\" />\n\n<button class=\"greese-Button greese-Button--solid\">Save changes</button>\n```\n\nEvery component's classes, parts, modifiers and state attributes are listed\nin its Styling section, and they're a public contract: the React components\nrender exactly these. Native elements (`<dialog>`, `<details>`, form controls)\nwork as they are; widgets with keyboard behaviour (Tabs, Combobox, Menu…) also\nneed JavaScript, which comes with the framework packages. With a bundler,\n`import '@greese/ui/styles.css'` does the same as the link.\n\n## Only the CSS you use\n\n`styles.css` is about 23 kB brotli for everything. To ship less, import per-component\nstylesheets instead. Each one pulls in the shared core and the components it builds\non, and bundlers de-duplicate the shared imports:\n\n```tsx\n```\n\n## Dark mode without a flash\n\nThe scheme follows the OS by default. To let users choose, add the pre-paint script\nto `<head>` and call `useColorScheme()`:\n\n```tsx\n\n;<script dangerouslySetInnerHTML={{ __html: getSchemeScript() }} />\n\nconst { setScheme } = useColorScheme()\nsetScheme('dark') // 'light' | 'dark' | 'system'\n```"},{"name":"GreeseJs","title":"greese.js","text":"# greese.js\n\ngreese.js (`@greese/js`) is a small keyframe and timeline animation\nlibrary for the web. It's about 5.7 kB brotli (6.6 kB with every extra), has no\ndependencies and needs no framework. Timelines play, pause, seek, reverse,\nscale time, repeat, yoyo and nest. It animates:\n\n- CSS properties and individual transforms;\n- custom properties;\n- text;\n- SVG attributes;\n- plain objects.\n\nThis page covers greese.js **on its own, without greese ui**. For motion in\ngreese ui components (the `greese` prop), see **Guides/Animation**. Live demos\nare under **Motion/greese.js**.\n\n## Install and import: every supported form\n\n| Form | Use it when |\n| ----------------------------------------------------- | --------------------------------------------------------- |\n| [npm + a bundler (ESM)](#npm-and-a-bundler) | Most apps: Vite, webpack, Next.js, Remix, Astro… |\n| [Inside greese ui](#inside-greese-ui) | You already use `@greese/react` |\n| [CDN, as an ES module](#cdn-as-an-es-module) | A page or prototype with no build step |\n| [CDN, as a classic `<script>`](#a-classic-script-tag) | CMS templates and legacy pages; gives you `window.greese` |\n| [Node and server rendering](#node-and-servers) | Tests, server-side frame generation, SSR-safe imports |\n\n### npm and a bundler\n\n```sh\nnpm install @greese/js\n```\n\n```ts\n\nanimate('.card', { opacity: [0, 1], y: [16, 0] }, { duration: 0.4, stagger: 0.05 })\n```\n\n- It's ESM only, with `sideEffects: false`, so bundlers tree-shake what you\n don't import: `ease` alone is under 1 kB.\n- Types are included; there's no `@types` package.\n\n### Inside greese ui\n\n`@greese/react` depends on greese.js and re-exports `animate`,\n`timeline`, `Timeline`, `ease`, `cubicBezier`, `splitText` and their types:\n\n```ts\n```\n\ngreese ui also adds the `greese` prop and the `useGreese()` hook; see\n**Guides/Animation**.\n\n### CDN, as an ES module\n\nNo install and no build: import straight from a CDN in a module script. Pin\nthe version.\n\n```html\n<script type=\"module\">\n import { animate } from 'https://cdn.jsdelivr.net/npm/@greese/js@0.1/+esm'\n // or: 'https://unpkg.com/@greese/js@0.1/dist/index.js'\n\n animate('h1', { opacity: [0, 1], y: [20, 0] }, { duration: 0.6 })\n</script>\n```\n\n### A classic script tag\n\n`dist/greese.global.js` is a single minified file (about 7 kB brotli) that\ndefines `window.greese`. It's the package's default file on unpkg and\njsDelivr.\n\n```html\n<script src=\"https://unpkg.com/@greese/js@0.1/dist/greese.global.js\"></script>\n<script>\n const { timeline } = window.greese\n timeline({ repeat: -1, yoyo: true }).to('.logo', { rotate: 10, duration: 0.8 })\n</script>\n```\n\nWith a bundler, the same file is available as `@greese/js/global`.\n\n### Node and servers\n\nImporting greese.js never touches the DOM, so it's safe in server-rendered\ncode and Server Components. On a server there's no animation frame, so\ntimelines don't play by themselves; drive them with `seek()` or `progress()`.\nThat's useful for tests, or for rendering frames (canvas, video) offline:\n\n```ts\n\nconst state = { x: 0, opacity: 0 }\nconst tl = timeline({ paused: true })\n .to(state, { x: 300, duration: 1, ease: 'out' })\n .to(state, { opacity: 1, duration: 0.5 }, '<')\n\nfor (let frame = 0; frame <= 30; frame++) {\n tl.seek(frame / 30)\n drawFrame(state) // your renderer\n}\n```\n\n## In frameworks (without greese ui)\n\nThe rules are the same everywhere:\n\n- build a timeline once the elements exist;\n- `kill()` it when they go away, which also restores what it animated.\n\n### React\n\n```tsx\n\n const root = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const tl = timeline()\n .from(root.current!.querySelector('h1'), { opacity: 0, y: 24 })\n .from(\n root.current!.querySelectorAll('li'),\n { opacity: 0, x: -12, stagger: 0.05 },\n '-=0.2'\n )\n return () => {\n tl.kill()\n }\n }, [])\n return <div ref={root}>…</div>\n}\n```\n\nDon't return a timeline from an effect, or from anything React treats as a\npromise: a timeline is awaitable.\n\n### Vue\n\n```vue\n<script setup lang=\"ts\">\n\nconst card = ref<HTMLElement>()\nlet tl: Timeline | undefined\nonMounted(() => {\n tl = timeline().from(card.value!, { opacity: 0, scale: 0.95, duration: 0.4 })\n})\nonBeforeUnmount(() => tl?.kill())\n</script>\n\n<template><div ref=\"card\">…</div></template>\n```\n\n### Svelte\n\n```svelte\n<script lang=\"ts\">\n import { animate } from '@greese/js'\n // An action: runs when the element mounts, cleans up when it unmounts.\n const reveal = (node: HTMLElement) => {\n const tl = animate(node, { opacity: [0, 1], y: [16, 0] }, { duration: 0.5 })\n return { destroy: () => tl.kill() }\n }\n</script>\n\n<section use:reveal>…</section>\n```\n\n### Plain JavaScript\n\n```ts\n\nconst { elements } = splitText(document.querySelector('h1')!)\nconst intro = animate(elements, { opacity: [0, 1], y: [10, 0] }, { stagger: 0.03 })\ndocument.querySelector('#replay')!.addEventListener('click', () => intro.restart())\n```\n\n## TypeScript\n\nEverything is typed. The types you'll use most are:\n\n| Type | For |\n| -------------------------------------- | -------------------------------------------------------------- |\n| `Timeline`, `TimelineOptions` | The timeline class and `timeline()` options |\n| `Keyframes`, `Keyframe`, `Vars` | `animate()` keyframes; `to`/`from` property values and options |\n| `AnimateOptions`, `StaggerOptions` | `duration`, `ease`, `stagger` |\n| `PerTarget` | A value, or stagger, worked out per target |\n| `Position` | Where a child goes (`1.5`, `'<'`, `'label+=0.2'`) |\n| `Ease`, `EaseFn` | Ease names, bézier arrays or functions |\n| `Targets`, `Target` | What can be animated |\n| `PixelsAnimation`, `FromPixelsOptions` | Pixels documents for `fromPixels` |\n\n## The one-call API\n\n```ts\nanimate('.card', { opacity: [0, 1], y: [16, 0] }, { duration: 0.4, stagger: 0.05 })\n```\n\n`animate(targets, keyframes, options)` builds a timeline, plays it on the\nnext frame and returns it.\n\n- **Targets**: a selector, an element, a list of elements (NodeList, array),\n or any object.\n- **Times are seconds** (WAAPI uses milliseconds).\n- **Keyframes** come in two forms, as with `element.animate()`:\n - **Property lists**: `{ opacity: [0, 1], x: [0, 40, 20] }`. Values are\n spaced evenly; a single value animates from the current one.\n - **Frames**: `[{ scale: 1 }, { scale: 1.2, offset: 0.3, ease: 'in' }, { scale: 1 }]`.\n `offset` (0–1) places a frame (missing offsets are spaced evenly), and a\n frame's `ease` applies until the next frame.\n- **Per-target values**: any value can be a function of the target's index,\n the target and the list, worked out once as the animation is built, so one\n call gives each target its own: `{ y: (i) => -8 - i * 4 }`. In the\n property-list form a function goes in the list:\n `{ y: [0, (i) => -8 - i * 4] }`.\n- **Stagger** is seconds between neighbours, `{ each, from }` (`from`:\n `'start'`, `'end'`, `'center'` or an index), or a function giving each\n target its own offset, such as one ordered by position:\n `stagger: (i, el) => el.getBoundingClientRect().left / 1000`.\n\n## Timelines\n\n```ts\nconst intro = timeline()\n .to('.title', { opacity: 1, y: 0, duration: 0.6 })\n .from('.card', { opacity: 0, y: 24, stagger: 0.08 }, '-=0.3')\n .call(() => track('intro-done'))\n```\n\n| Method | Does |\n| --------------------------------------------------- | ------------------------------------------------------------------------------ |\n| `.to(targets, vars, position?)` | Animates from current values to `vars` |\n| `.from(targets, vars, position?)` | From `vars` to current values; `vars` show until it starts, so nothing flashes |\n| `.fromTo(targets, from, to, position?)` | Both ends explicit |\n| `.animate(targets, keyframes, options?, position?)` | Keyframes, as above |\n| `.set(targets, vars, position?)` | Sets values at a point in time |\n| `.add(timeline \\| fn, position?)` | Nests a timeline, or schedules a callback |\n| `.call(fn, position?)` | Runs `fn` when the playhead passes, in either direction |\n| `.label(name, position?)` | Names a time |\n\n`vars` holds property values plus `duration` (default `0.5`), `ease` (default\n`'out'`) and `stagger`.\n\n**Positions** place each child:\n\n| Position | Means |\n| -------------------------- | ---------------------------------------------------- |\n| omitted | At the end: calls run in sequence |\n| `1.5` | At 1.5 s |\n| `'+=0.2'` / `'-=0.2'` | 0.2 s after / before the current end |\n| `'<'` / `'<0.1'` | With / 0.1 s after the previous child's start |\n| `'>'` / `'>-0.2'` | At / 0.2 s before the previous child's end |\n| `'intro'` / `'intro+=0.5'` | At / after a label (labels can't contain `+` or `-`) |\n\n### Controls\n\n`play(from?)`, `pause()`, `resume()`, `reverse(from?)`, `restart()`,\n`seek(timeOrLabel)`, `progress(0–1)`, `time(s)`, `timeScale(n)`,\n`duration()`, `totalDuration()`, `isActive()`, `invalidate()`, and `kill()`,\nwhich stops and restores every animated property.\n\nOptions: `paused`, `repeat` (`-1` is forever), `yoyo`, `repeatDelay`,\n`timeScale`, `reducedMotion`, `scope` (selector strings match inside that element), `onUpdate`, `onComplete`.\n\nA timeline is awaitable: `await animate(el, …)` resolves when it completes. It\nresolves with no value, so returning a timeline from an `async` function or a\n`then` callback waits for it to finish. That's usually what you want, but\ndon't return a _paused_ timeline from one.\n\n### Nesting\n\n```ts\nconst spin = timeline({ repeat: 2 }).to(icon, { rotate: 360, ease: 'linear' })\nconst page = timeline().add(spin).add(slideIn.timeScale(2), '<0.3')\npage.reverse() // plays everything backwards, nested timelines included\n```\n\nA nested timeline stops running its own clock and is driven by its parent,\nthrough its own `repeat`, `yoyo` and `timeScale`.\n\n## What can be animated\n\n| Property | Notes |\n| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `x`, `y`, `z`, `rotate`, `scale`, `scaleX`, `scaleY` | Written to the individual `translate`, `rotate` and `scale` properties: they compose without a matrix and don't fight a `transform` from your CSS. Numbers mean px or deg |\n| CSS properties, camelCase | `opacity`, `width`, `backgroundColor`, `filter`, `clipPath`, `boxShadow`… Bare numbers mean px, except unitless properties such as `opacity` |\n| `'--custom-properties'` | Including greese ui tokens: animate `--greese-color-primary` and every component that reads it follows |\n| `text` | Counts between numbers (`'0'` → `'12480'`), types on or deletes, or retypes |\n| SVG attributes the element has | `r`, `cx`, `d` (when point counts match)… |\n| Numeric element properties | `scrollTop`, `scrollLeft` |\n| Any object property | Canvas, WebGL or game state your code reads each frame |\n\n**How values interpolate:**\n\n- **Numbers inside strings** interpolate when both ends have the same shape:\n `blur(0px)` → `blur(8px)`, `inset(0 0 0 0)` → `inset(0 50% 0 0)`.\n- **A bare `0`** takes the other end's unit.\n- **Different units blend exactly:** `16px` → `2rem`, `0px` → `50%`,\n `100px` → `50vw`, `200ms` → `1s`. Each number with a different unit\n becomes `calc(16px * 0.75 + 2rem * 0.25)` mid-way, which the browser\n resolves where the value is used, so percentages and viewport units are\n right for that element, with no measuring. The ends are written plainly.\n- **Colors** mix in OKLab, so midpoints stay vivid, not muddy.\n- **Anything else** switches halfway, except `none`/`hidden`, which give way\n to the shown value for the whole animation, as CSS does for `display`.\n\n### Text\n\n```ts\nconst { elements, revert } = splitText(heading) // or { by: 'words' }\ntimeline().from(elements, { opacity: 0, y: 12, stagger: 0.03 })\n```\n\nThe pieces are hidden from assistive technology, and the full sentence is\nkept once, visually hidden, so screen readers read words, not letters.\nCharacters stay grouped per word, so lines still wrap normally. Use it on\nplain text; markup inside is flattened. `revert()` restores the original.\n\n## Eases\n\n| Ease | Use |\n| --------------------------------------------------------------------------- | ------------------------------------------------ |\n| `'out'` (default), `'in'`, `'inOut'` | power2: a good general curve |\n| `'power1'`–`'power4'`, `'sine'`, `'expo'`, `'circ'` + `.in`/`.out`/`.inOut` | Gentler to sharper curves |\n| `'back.out(2)'` | Overshoots, then settles (the number is how far) |\n| `'elastic.out(1.2, 0.4)'` | Springs (amplitude, period) |\n| `'bounce.out'` | Bounces to rest |\n| `'linear'`, `'ease'`, `'ease-in-out'`, `'steps(4)'` | The CSS names |\n| `'cubic-bezier(0.2, 0, 0, 1)'` | CSS's form, as easing tokens and styles write it |\n| `[0.2, 0, 0, 1]` or a function | Any cubic-bézier, or your own curve |\n\nNamed eases use the common timeline names, so existing code ports directly.\n\n## Playing Pixels animations: `fromPixels`\n\nAnimation authored in the Pixels studio can play on DOM elements, or any\ntargets. `fromPixels` reads a symbol animation's layers:\n\n- keyframes and tweens become tracks on one timeline;\n- frame numbers become seconds at the document's fps.\n\n```ts\n\nconst tl = fromPixels(\n doc.symbols.hero.animations.idle,\n {\n body: '.hero', // layer id → targets\n shadow: '.hero-shadow',\n },\n { channels: { glow: '--glow' } }\n)\ntl.play()\n```\n\n| Pixels | greese.js |\n| ---------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| Channels `x`, `y`, `scaleX`, `scaleY` | The same transform properties |\n| `rotation` (shortest arc, unless the tween disables it) | `rotate` |\n| `alpha` | `opacity` |\n| Any other channel | The same name: map it with `channels` (e.g. to a CSS variable) |\n| Frame index at `fps` | Seconds = frame ÷ fps |\n| `linear`, `easeIn`/`easeOut`/`easeInOut`, `bezier`, `step` | `linear`, the CSS `ease-*` curves, the bézier, `steps(1)` |\n| `elastic`, `bounce`, `back` | `elastic.out`, `bounce.out`, `back.out` (Pixels' own renderer plays these as linear) |\n| Keys with no tween between them | A hold until the next key |\n| `loop` | `repeat: -1` |\n\nSpans (nested animations) aren't read; nest timelines with `add()` instead.\n\n## Accessibility: reduced motion\n\nWhen the user asks for reduced motion (`prefers-reduced-motion: reduce`), a\ntimeline jumps straight to its end when played. The final state still applies;\nonly the movement is skipped. For motion that carries meaning, such as a\nprogress indicator, opt out per timeline:\n\n```ts\ntimeline({ reducedMotion: 'ignore' })\n```\n\n## Performance\n\ngreese.js samples values on the main thread, once per frame, through a single\nshared `requestAnimationFrame` loop that runs only while something plays. It\nbatches each element's writes, so a frame does one style write per property.\nIt reads computed styles only once per property, for the starting value, and\nnever during playback.\n\n- Prefer `x`/`y`/`scale`/`rotate` and `opacity` over `width`, `top` or\n `margin`: the browser can then skip layout.\n- For long-running decorative loops, CSS `@keyframes` costs less: it runs off\n the main thread.\n- Starting values are read once, the first time a property is sampled. After\n the page changes underneath (a resize), call `invalidate()`.\n- Every write waits until its timeline has finished reading, and each frame\n renders all playing timelines in one batch, so reads never interleave with\n writes. When you start many animations at once outside a frame, wrap them\n in `batch()` for the same effect:\n\n```ts\n\nbatch(() => {\n for (const card of cards) animate(card, { opacity: [0, 1], y: [16, 0] })\n})\n```\n\n## Porting timeline code\n\nTimeline code ports directly: `to`, `from`, `fromTo`, `set`, `add`,\n`call` and labels, the position syntax, `stagger` (a number,\n`{ each, from }` or a function), function-based values and the named eases\nare all the same. Keep a timeline and\ncall `kill()` to stop and restore what it animated. Plugins, scroll-driven\ntriggers, path motion and morphing aren't included.\n\nThe model follows the Pixels timeline: per-property keyframe tracks\nsampled purely by time, nested timelines mapped through repeat and time scale\n(Pixels' spans), and OKLab color mixing (Pixels mixes in OKLCH)."},{"name":"Introduction","title":"greese ui","text":"# greese ui\n\nMobile-first, TypeScript-first React components with **zero-runtime styling**.\nAll CSS is compiled at build time and themed with CSS custom properties; at runtime\ncomponents only toggle class names and set a few inline variables. No CSS-in-JS, no\nstyle injection, no runtime dependencies beyond React.\n\n- **Fast.** Styles are static CSS and components only toggle classes, so there is\n nothing to compute at run time. The homepage has the measurements.\n- **Responsive.** `direction={{ xs: 'column', md: 'row' }}` on any layout\n prop, resolved by static CSS.\n- **Native first.** Real `<button>`, `<input>`, `<select>`, `<dialog>`, `<details>` and\n the Popover API: keyboard, forms, autofill and phone pickers work out of the box.\n- **Accessible by default.** WAI-ARIA patterns, tested with axe and in Chromium,\n Firefox, WebKit and an emulated iPhone.\n\nStart with [Getting started](?path=/docs/guides-getting-started--docs), then browse\n**Layout**, **Forms**, **Content** and **Overlays**. Use the toolbar's **Scheme**\nswitch to see everything in light and dark."},{"name":"PageTransitions","title":"Page transitions","text":"# Page transitions\n\nWhen the page changes, the old page leaves and the new one arrives, with\ngreese's effects, paced and themed like everything else that moves. greese\nbuilds on React's own transition layer (`<ViewTransition>` and\n`addTransitionType`, stable since React 19.3), so it works with any router\nwhose navigations are React transitions. The decisions behind it are ADR 0029.\n\n| Piece | What it does | Where it runs |\n| ------------------------------- | -------------------------------------------------------------------- | ---------------- |\n| `PageTransition` | Wraps your router's outlet; says how a page change plays | Server or client |\n| `usePageNavigate` | Wraps your router's navigate; says which way each navigation went | Client |\n| `PageShare` | An element that morphs into its twin on the next page | Server or client |\n| The page roles | How the motion theme changes pages: `page`, `page-exit` and the rest | CSS |\n| `page-transitions()` (SCSS kit) | Parts of a page with motion of their own, by selector, in a theme | CSS |\n\nThe live demos are **Motion/PageTransition** and **Motion/PageShare**.\n\n## Quick start\n\nWith React Router (the web app you're reading uses exactly this):\n\n```tsx\n\n const page = usePageNavigate(useNavigate())\n return (\n <>\n <header>\n <Link to=\"/docs\" onClick={page.onLinkClick('/docs')}>\n Docs\n </Link>\n </header>\n <PageTransition>\n <Outlet />\n </PageTransition>\n </>\n )\n}\n```\n\nThat's a cross-fade, or whatever the motion theme you wear says. Without\nview transitions in the browser, before React 19.3, and for visitors who\nreduce motion, the page simply changes.\n\n## How a page change plays\n\nThere are two ways, and `mode` picks one:\n\n- **`snapshot`:** the browser takes a picture of the old page and of the new\n one and animates the pictures: the old one plays an exit, the new one an\n entrance. Nothing on the page moves while it happens, and it costs almost\n no script.\n- **`live`:** the old page's **members**, its elements with greese entrances,\n play their exits on the real page, one after another (the last first, so\n the page empties back towards its top), while your router loads the next\n page. Then the page changes: the new page plays its entrance, what the\n exit left of the old one fades beneath it, and the new page's members\n play their own entrances. The exit's styles come off once the new page\n has committed, so nothing it hid shows again on the old page.\n- **`auto`** (the default) leaves live when the page has members on screen,\n and as a snapshot otherwise. The motion theme's `page-mode` decides when\n `PageTransition` doesn't.\n\n```tsx\n<PageTransition exit=\"scaleOut\" back={{ enter: 'slideRight' }}>…</PageTransition>\n<PageTransition mode=\"live\" order=\"document\" stagger={0.06}>…</PageTransition>\n```\n\nPick live for pages whose arrival is choreographed (a hero of entrances) and\nsnapshots elsewhere.\n\nA page taller than the screen is snapshotted whole, so its snapshots show\nonly the screenful in view: the new page's from its top, the old page's\nfrom where the screen was on it. Effects sized by the element (a pocket's\nslot, a pop's middle, a flip's axis) play where you can see them.\n\nA page change commits when the next page has rendered. A page that loads\nlazily (a route's chunk, a `use` of its data) and commits still loading\nshows its fallback, and that's what the snapshot plays: give your router's\nnavigate a promise for what the next page needs, and the change waits for\nit (the web app fetches the next page's chunk and content in its navigate). The web app's homepage leaves live; its other pages,\nwhere the only members on screen are a footer's, change as snapshots.\n\n## Which way it went: transition types\n\n`usePageNavigate` adds React transition types to each navigation, and\n`PageTransition` plays by them:\n\n| Type | When |\n| ----------------------------------------------------- | ------------------------------------------------------------------ |\n| `greese-page` | Every page change it makes |\n| `greese-forward`, `greese-back` | Its direction: back is going back in the history, or up the URL |\n| `greese-replace` | A replace: the page changes in place |\n| `greese-deeper`, `greese-shallower`, `greese-sibling` | How it moved in the URL |\n| `greese-live` | The page left live: the new page arrives, the old one's rest fades |\n\nA change of hash or query alone isn't a page change and gets none of them:\na tab kept in the URL, or a filter, changes the page in place. Add your own\ntypes with `types`, and say how they play in `PageTransition`'s `types`:\n\n```tsx\npage.navigate('/checkout', { types: ['checkout'] })\n\n<PageTransition types={{ checkout: { enter: 'pocketUp', exit: 'fadeOut' } }}>…</PageTransition>\n```\n\n## Effects, sequences and timelines\n\n`enter` and `exit` take any built-in effect by name, `'theme'` (the motion\ntheme's choice, the default) or `'none'`. In a snapshot, the new page plays\nthe entrance and the old page the exit, as CSS.\n\nA live page's `exit` also takes what greese.js plays: a sequence, in the\n`greese` prop's own syntax, or a **timeline map** of selector to sequence,\nwhose entries start together and each keep their own pauses and overlaps:\n\n```tsx\n <PageTransition\n exit={{\n '.hero': 'fadeOut(duration: 0.3)',\n '.card': 'scaleOut(0.2),+0.1,fadeOut',\n 'nav a': 'fadeOutUp',\n }}\n >\n …\n </PageTransition>\n)\n```\n\ngreese.js loads the first time a page leaves with one, as its own chunk.\n\n## Parts of a page\n\n`rules` gives parts of the page motion of their own while it changes: kept\n`'still'` (a sidebar the change leaves alone), or their own `enter`, `exit`,\n`duration`, `delay` and `ease`:\n\n```tsx\n <PageTransition\n rules={{\n aside: 'still',\n '.greese-Card': { exit: 'scaleOut', duration: 'fast', delay: 0.05 },\n }}\n >\n …\n </PageTransition>\n)\n```\n\nThe matched elements are named only while a greese page change runs, so\nother view transitions never capture them. **Each one is a snapshot of its\nown:** name sections, not every item of a long list. **What's still stays on\ntop:** the page moves beneath it, as a page scrolls beneath a sticky header,\nso a header outside the page is worth a rule of its own\n(`rules={{ header: 'still' }}`); without one, it's part of the root snapshot\nand the page moves over it. A theme sets rules too,\nwith the kit's `page-transitions()`, or under Pages in Theme Studio's Motion\ntab.\n\n## Page by page: route rules\n\nA page can decide how a change plays by where it goes or where it came from:\n\"wipe out when leaving for `/settings/*`\", \"turn in like Depth when arriving\nfrom `/user/*`\". Declare them as data on the route (React Router's\n`handle.greese`), and hand `usePageNavigate` a function that finds a path's\nconfig. It is called at the click, for both pages, so it answers\nsynchronously:\n\n```tsx\n\n {\n path: 'user/:id',\n Component: User,\n handle: {\n greese: {\n to: { '/settings/*': { exit: 'wipeOutLeft', mode: 'snapshot' } },\n } satisfies PageRoute,\n },\n },\n {\n path: 'settings/*',\n Component: Settings,\n handle: {\n greese: {\n from: { '/user/*': { enter: 'flipOverRight', duration: 0.8 } },\n } satisfies PageRoute,\n },\n },\n]\n\n// Module level, as the routes are.\nconst route = (path: string) => matchRoutes(routes, path)?.at(-1)?.route.handle?.greese\n\nconst page = usePageNavigate(useNavigate(), { route })\n```\n\nA rule takes `enter`, `exit`, `duration`, `ease`, `mode` and `back` (what\nchanges going back). `to` rules match the path the page is leaving for,\n`from` rules the one it came from, by a pattern:\n\n| Pattern | Matches |\n| -------------- | ----------------------------------------------------- |\n| `/settings` | That path only (a trailing slash is ignored) |\n| `/user/:id` | One segment of any value |\n| `/docs/*/edit` | A `*` in the middle: exactly one segment |\n| `/settings/*` | A trailing `/*`: the page itself and everything below |\n| `*` | Any path |\n\nThe most specific pattern wins, then source order. A pattern with a `?` or a\n`#` is refused: a change of query or hash isn't a page change. With a\n`basename`, pass `{ route, base }` so patterns see paths without it.\n\nEach side has an owner. The exit and `mode` come from the leaving page's\n`to` rule first, then the arriving page's `from` rule; the entrance from the\narriving page's rule first; `duration` and `ease` from either, the entrance's\nowner first. A route's effects beat the theme's and the app's\n(`PageTransition`'s own `enter` and `exit`), but not a live member's own\n`greese={{ exit }}`. Rules in `rules` (parts of a page) are more specific and\nkeep their own motion.\n\nGive the route its `handle` up front: a route whose `handle` arrives with a\nlazy chunk is unknown at the click, so its rules don't apply to the first\nnavigation. History steps (`navigate(-1)`) use the entry they land on where\nthe Navigation API can say; elsewhere they skip `to` rules.\n\n## One navigation\n\nA single navigation can name its own effects, over every route and the theme:\n\n```tsx\npage.navigate('/settings/billing', { exit: 'wipeOutLeft', enter: 'wipeLeft' })\n\nconst link = (\n <a\n href=\"/compare\"\n onClick={page.onLinkClick('/compare', { enter: 'pocketUp', duration: 'fast' })}\n >\n Compare\n </a>\n)\n```\n\nBeside `mode`, `replace`, `direction` and `types`, it takes `enter`, `exit`,\n`duration` and `ease`. On a live page its `exit` also beats the members' own.\n\nEverything, from last to first to win:\n\n| Level | Where | Plays |\n| ---------- | ---------------------------------- | ---------------------------------------------- |\n| Navigation | `navigate` / `onLinkClick` options | Over every other level; forced on live members |\n| Element | `greese={{ exit }}` | A live member's own exit (live only) |\n| Route | `handle.greese` through `route` | Owner per side; the rule's `mode` |\n| App | `PageTransition` props | Effects and timelines; `mode` |\n| Theme | the motion theme's page roles | `page-mode` |\n\n## Shared elements\n\n`PageShare` pairs an element with its twin on the next page, by an `id` that\nmeans the same thing on both, and the browser morphs one into the other: a\ncard into a page's hero, a thumbnail into a photo.\n\n```tsx\n<PageShare id={['template', template.id]}>\n <Card>…</Card>\n</PageShare>\n```\n\nAn id is unique on each page. Its group (`template`, above) is a\nview-transition class, `greese-share-template`, so CSS can style every\ntemplate's morph at once. React warns, in development, when two elements\nshare an id.\n\nFor a list and its items' pages there's no need for ids: **`link` pairs by\nthe link followed.** Mark each item and the item page's hero:\n\n```tsx\n templates.map((t) => (\n <PageShare key={t.id} link>\n <Card>\n <a href={`/templates/${t.id}`} onClick={page.onLinkClick(`/templates/${t.id}`)}>\n {t.name}\n </a>\n </Card>\n </PageShare>\n ))\n\n <PageShare link>\n <Heading level={1}>{template.name}</Heading>\n </PageShare>\n)\n```\n\nThe item whose link was clicked morphs into the hero, the page's one `link`\nelement with no link inside it. Going back, the hero morphs into the item\nlinking to the page left. The navigation has to go through\n`usePageNavigate`, which names both ends while the page changes, so this is\nthe client's work. An end it can't find (an item the list hasn't rendered)\nleaves the page's own exit and entrance. Its class is `greese-share-link`.\n\n## Themes\n\nA motion theme sets how pages change with the page roles of\n`motion-defaults()`, each a custom property, `--greese-motion-<role>`:\n\n| Role | Sets | Base theme |\n| --------------------------------- | ----------------------------------------- | -------------------------------- |\n| `page`, `page-back` | The new page's entrance, forward and back | A fade in |\n| `page-exit`, `page-back-exit` | How the old page leaves | A fade out |\n| `page-duration`, `page-ease` | The page change's pace | `normal`, the library's ease out |\n| `page-stagger`, `page-exit-order` | A live page's members' spacing and order | The entrance stagger, `reverse` |\n| `page-mode` | `auto`, `snapshot` or `live` | `auto` |\n| `share-duration`, `share-ease` | A shared element's morph | The page's |\n\n```scss\n@include greese.motion-defaults(\n (\n page: pocket-up,\n page-exit: pocket-out-down,\n page-back: pocket-down,\n page-back-exit: pocket-out-up,\n page-duration: 0.55s,\n )\n);\n```\n\nEvery motion theme has its own: Snappy pops pages away and in, Gentle fades\nthe old page while the new one comes into focus, Wipe wipes the next page\nover the last, Pocket sinks pages into a slot and raises the next out of it,\nand Depth turns them like a cube's faces. A theme scoped to an element\n(`ThemeProvider`, `theme(name)`) reaches the page change too.\n\n## Back and forward\n\n`page.navigate(-1)`, and links that go back up the URL, play as back: the\n`greese-back` type, and the theme's `page-back` roles.\n\nThe browser's own back and forward buttons are another matter, because your\nrouter, not greese, makes that change:\n\n- **A page that leaves live** plays its exit before the page changes, where\n the browser can hold a history traversal (the Navigation API's precommit\n handler). Routers that follow `popstate` need nothing more.\n- **A snapshot doesn't play.** The router's update carries no greese types,\n so the page changes at once, as it does in browsers that can't hold a\n traversal.\n- **A router that starts view transitions itself,** such as TanStack Router\n (below), plays them for back and forward too.\n\n## Server Components\n\n`PageTransition` and `PageShare` take only data, so a Server Component, such\nas a layout, can render them around its children. `usePageNavigate` is the\nclient part: use it in the client component that renders your links.\n\n## Recipes\n\nThe web app uses React Router, so that recipe is tested on every change. The\nNext.js (16.4) and TanStack Router (1.170) recipes were run in apps of their\nown, in Chromium, Firefox and WebKit, but greese's tests don't run them, so\nthey're as good as those versions. Pages without a router follow the\nplatform's own API.\n\n### React Router\n\nAs in the quick start. Hand it the router's `useNavigate()`, and give every\n`Link` the hook's `onLinkClick(to)`, or make a link component of your own that\ndoes. With a `basename`, give `usePageNavigate` app hrefs and strip the base\nwhen you call React Router, so the URL's depth stays right. For route rules,\n`matchRoutes(routes, path, basename)` finds a route's `handle`, as above.\n\n### Next.js (App Router)\n\nIts navigations are React transitions, so the same pattern applies:\n`PageTransition` around `children` in a layout, and a client link that goes\nthrough `usePageNavigate` with the router's `push`:\n\n```tsx\n'use client'\n\n const router = useRouter()\n const page = usePageNavigate((to, options) =>\n options?.replace ? router.replace(to) : router.push(to)\n )\n return (\n <NextLink href={href} onClick={page.onLinkClick(href)}>\n {children}\n </NextLink>\n )\n}\n```\n\nFor route rules, Next.js has no route `handle`: key a module-level table by\napp path (`matchPagePath(pattern, path)` is exported for it) and hand\n`usePageNavigate` `{ route: (path) => table.find((r) => matchPagePath(r.path, path))?.greese }`.\n\n### TanStack Router\n\nWith route rules, `router.matchRoutes(path)` finds a route, and a route's\n`staticData` can carry the `PageRoute`. TanStack Router can start view transitions itself (`viewTransition`), which\ngreese's CSS plays without `PageTransition`: name the page's element and give\nit greese's classes, by type.\n\n```css\nmain {\n view-transition-name: page;\n view-transition-class: greese-PageTransition greese-PageTransition--theme;\n}\n\n:root:active-view-transition-type(greese-back) main {\n view-transition-class: greese-PageTransition greese-PageTransition--theme-back;\n}\n```\n\nThen give the router its types: `greese-page` on every page change, and\n`greese-back` when the history index went down. The first load has no\n`fromLocation`; `false` keeps it from fading in.\n\n```tsx\n\nconst index = (state: unknown) => (state as { __TSR_index?: number }).__TSR_index ?? 0\n\n routeTree,\n defaultViewTransition: {\n types: ({ fromLocation, toLocation }) =>\n !fromLocation\n ? false\n : index(toLocation.state) < index(fromLocation.state)\n ? ['greese-page', 'greese-back']\n : ['greese-page'],\n },\n})\n```\n\nBecause the router starts the transition itself, the browser's back and\nforward buttons play it too.\n\n### Pages without a router\n\nBetween real page loads, the browser plays the same CSS when both pages opt\nin with `@view-transition { navigation: auto; }` and name the page as above.\ngreese's stylesheet is all it needs."},{"name":"ResponsiveProps","title":"Responsive props","text":"# Responsive props\n\nLayout and visual props take one value, or a value per breakpoint. Mobile-first: each\nvalue applies from its breakpoint upward until a larger one overrides it.\n\n```tsx\n<Stack direction={{ xs: 'column', md: 'row' }} gap={{ xs: 2, lg: '2.5rem' }} />\n<Grid container columns={{ xs: 1, sm: 2, lg: 4 }} gap={4} />\n<Box p={{ xs: 4, md: 6 }} display={{ xs: 'none', md: 'block' }} />\n<Button fullWidth={{ xs: true, md: false }}>Save</Button>\n```\n\n| Breakpoint | `xs` | `sm` | `md` | `lg` | `xl` |\n| ---------- | ---- | ----- | ----- | ------ | ------ |\n| min-width | 0 | 600px | 900px | 1200px | 1536px |\n\n## How it stays fast\n\nNo CSS is generated at runtime. Each breakpoint's value becomes one **class**:\na pre-generated one for scale tokens and enums, or a value class that reads an\n**inline custom property** for any other length. Each class sets the property\ndirectly, inside its breakpoint's media query:\n\n```css\n.greese-Stack--xs-gap-2 {\n gap: var(--greese-space-2);\n}\n@media (width >= 900px) {\n .greese-Stack--md-gap-4 {\n gap: var(--greese-space-4);\n }\n .greese-Stack--md-gap {\n gap: var(--greese-stack-gap-md);\n } /* gap={{ md: '13px' }} */\n}\n```\n\nLarger breakpoints come later in the stylesheet, so they win where they apply,\nand a smaller breakpoint's value carries on above it until one does. A prop\nyou don't set adds nothing to the element at all.\n\n## Beyond the viewport\n\n- **Container queries**: `<Grid container containerQueries>` makes its cells' `size`s respond to the grid's\n own width, so the same grid adapts in a sidebar and on a full page.\n- **Intrinsic layout**: `<Grid container minChildWidth=\"14rem\">` fits as many columns as there is\n room for, with no breakpoints at all.\n- **Show / Hide**: `<Show above=\"md\">` toggles with CSS, so no hydration mismatch.\n- **When the tree must change** (not just its styles), use `useBreakpoint()`,\n `useBreakpointValue()` or `useMediaQuery()`."},{"name":"Styling","title":"Styling components","text":"# Styling components\n\n**Guides/Theming** changes the design tokens every component reads. This guide\ncovers everything past tokens: a component's classes, parts and variables;\noverriding them in CSS; the **SCSS kit**, which writes those overrides for you\nat build time; theme-wide motion; and **Theme Studio**, which edits all of it\nvisually and saves it to your project.\n\n1. [Choosing a level](#choosing-a-level)\n2. [Class names](#class-names)\n3. [Where overrides land: cascade layers](#where-overrides-land-cascade-layers)\n4. [Overriding in plain CSS](#overriding-in-plain-css)\n5. [The SCSS kit](#the-scss-kit)\n6. [Theme-wide motion](#theme-wide-motion)\n7. [Theme Studio](#theme-studio)\n\nEvery component's docs page, parts like AccordionItem and TableRow included,\nalso ends with a **Styling** section: the classes it renders (root, parts,\nmodifiers, states, responsive props, variables), its items, the components\nit's built on (an AccordionItem is a Collapsible), and override examples\nwritten for it.\n\n## Choosing a level\n\nUse the first level that does the job:\n\n| Level | For | Example |\n| -------------------------- | ------------------------------------------------- | ------------------------------------------------------ |\n| Props | What the API offers | `<Button variant=\"outline\" tone=\"negative\">` |\n| `className`, `style` | One instance | `<Card className=\"pricing-card\">` |\n| Component variables | A component's knobs, anywhere in the tree | `.sidebar { --greese-button-height: 2rem }` |\n| Tokens | The whole design (see Guides/Theming) | `createTheme({ radius: { md: '12px' } })` |\n| CSS overrides | Anything else, in your own stylesheet | `.greese-Card { box-shadow: var(--greese-shadow-lg) }` |\n| The SCSS kit, Theme Studio | A whole theme of overrides, checked at build time | `@include greese.component(Card) { … }` |\n\n## Class names\n\nEvery class is prefixed and never hashed, so it's safe to target:\n\n| Kind | Pattern | Example |\n| -------- | --------------------------- | ----------------------------------------------------- |\n| Root | `greese-<Name>` | `.greese-Button` |\n| Part | `greese-<Name>-<part>` | `.greese-Button-icon`, `.greese-Dialog-title` |\n| Modifier | `greese-<Name>--<modifier>` | `.greese-Button--outline`, `.greese-Button--size-sm` |\n| State | an attribute | `.greese-Button[data-loading]`, `[aria-invalid=true]` |\n\nResponsive props also add classes (`.greese-Stack--md-gap-2`). They're\ngenerated per breakpoint and token, so don't target them; set the prop.\n\n**Stability.** Root classes and documented variables are stable. Parts and\nmodifiers can change in a minor release, as markup does. If you target them\nthrough the SCSS kit, a renamed part stops your build with an error instead\nof silently not matching.\n\n## Where overrides land: cascade layers\n\nAll greese ui CSS lives in cascade layers, in this order (later wins):\n\n```css\n@layer greese.reset, greese.tokens, greese.theme, greese.base,\n greese.components, greese.overrides, greese.utilities;\n```\n\n| Layer | Holds |\n| ------------------- | ---------------------------------------------------- |\n| `greese.theme` | Token overrides: `createTheme`, the kit's `tokens()` |\n| `greese.components` | The library's component styles |\n| `greese.overrides` | The kit's `component()` and `motion()` overrides |\n| `greese.utilities` | Style props (`p={4}`) and the `greese` prop |\n| (unlayered) | Your own CSS |\n\nSo a kit override beats the component's own styles whatever their\nspecificity, but a style prop or a `greese` prop on one instance still beats\nthe override. Your unlayered CSS beats everything, without `!important`.\n\n## Overriding in plain CSS\n\nWrite normal CSS against the classes. It's unlayered, so it wins:\n\n```css\n.greese-Card {\n box-shadow: var(--greese-shadow-lg);\n}\n\n.greese-Button--outline {\n border-width: 2px;\n}\n\n/* Variables restyle every variant at once: the soft, outline and ghost\n backgrounds are all mixed from the tone. */\n.danger-zone .greese-Button {\n --greese-button-tone: var(--greese-color-negative);\n --greese-button-on-tone: var(--greese-color-negative-content);\n}\n```\n\nPrefer variables to properties where a component has them: they survive\nmarkup changes, and they cover states (hover, active) the component derives\nfrom them.\n\n## The SCSS kit\n\nThe kit is a Sass module for writing a theme as overrides that compile in\nyour build. You write names; it adds the `greese-` prefix and separators,\nputs each override in the right layer, and **stops the build on a name the\nlibrary doesn't have**, listing the ones it does.\n\n### Setup\n\nCompile with Sass's `NodePackageImporter`, which resolves `pkg:` URLs. In\nVite:\n\n```ts\n\n css: { preprocessorOptions: { scss: { importers: [new NodePackageImporter()] } } },\n})\n```\n\nThen, in a stylesheet imported **after** greese ui's styles:\n\n```scss\n// theme.scss\n@use 'pkg:@greese/ui/scss/kit' as greese;\n```\n\nUsing the module emits nothing. Its mixins emit the CSS, plus the layer order\nonce, so the order holds whichever stylesheet loads first.\n\n### Tokens\n\n`tokens()` is the build-time `createTheme`. Groups and keys are kebab-case (or\ncamelCase); a color takes one value or a light/dark pair:\n\n```scss\n@include greese.tokens(\n (\n color: (\n primary: (\n light: #7c3aed,\n dark: #c4b5fd,\n ),\n primary-content: #fff,\n ),\n radius: (\n md: 12px,\n ),\n font: (\n body: (\n 'Inter',\n system-ui,\n sans-serif,\n ),\n ),\n )\n);\n```\n\nTo add tokens the system doesn't have, name them in `$extend`, in the same\nshape. Each becomes `--greese-<group>-<name>`, and `token()` and component\nvariables accept it from then on. A name that already exists, or a group\nthat doesn't, still stops the build:\n\n```scss\n@include greese.tokens(\n (),\n $extend: (\n color: (\n brand-ink: (\n light: #1b1340,\n dark: #e5defc,\n ),\n ),\n space: (\n 9: 4rem,\n ),\n shadow: (\n glow: 0 0 12px rgb(124 58 237 / 0.4),\n )\n )\n);\n\n.my-banner {\n color: var(--greese-color-brand-ink); // from any CSS, after the built stylesheet\n margin-block: var(--greese-space-9);\n}\n```\n\nA new `space` token is a variable only: the responsive prop classes\n(`gap={9}`) come with the stylesheet's build, which knows `0`–`8`.\n\nAt the top level it overrides only what you pass, on the page, mirroring the\ndefault selectors, so light, dark and nested schemes all work. Duration\noverrides still collapse under reduced motion.\n\n### Components\n\n```scss\n@include greese.component(Button) {\n font-weight: 700; // .greese-Button\n\n @include greese.vars(\n (\n tone: greese.token(color, positive),\n )\n ); // --greese-button-tone\n\n @include greese.modifier(outline) {\n // .greese-Button--outline\n border-width: 2px;\n }\n\n @include greese.part(icon) {\n // .greese-Button .greese-Button-icon\n opacity: 0.8;\n }\n\n @include greese.hover {\n // only where hover exists\n translate: 0 -1px;\n }\n}\n```\n\n| Kit API | Gives |\n| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `component(Name) { … }` | `.greese-Name { … }` in `greese.overrides` |\n| `part(name) { … }` | `& .greese-Name-name` |\n| `modifier(name) { … }` | `&.greese-Name--name`, or the enclosing part's modifier |\n| `vars((name: value, …))` | Custom properties. Short names (`tone`), full names (`button-tone`) or tokens (`radius-md`, rescoped to the component). A `(light: …, dark: …)` value becomes `light-dark()` |\n| `motion((…))` | Theme-wide motion for the component: see [below](#theme-wide-motion) |\n| `class(Name, $part, $modifier)` | The selector string, for your own rules: `#{greese.class(Card)} > p` |\n| `token(group, key)` | `var(--greese-<group>-<key>)`, checked |\n| `variable(name)` | `var(--greese-<name>)` for a component variable, checked |\n| `tokens((…))`, `motion-defaults((…))`, `theme(name) { … }` | Token overrides, entrance tuning, a named theme |\n| `keyframes(greese-float-up, (from: (…), to: (…)))` | Adds `@keyframes` of your own (utilities layer); a built-in effect's name is refused |\n| `page-transitions(('.greese-Card': (exit: scale-out), 'header': still))` | Selector rules for page transitions: those elements get their own effects (or none) while a greese page change runs |\n| `up`, `down`, `hover`, `focus-ring`, `touch-target`, `motion-safe` | The library's own mixins |\n\nCall the mixins at the top level of a stylesheet (or inside `theme()`), not\ninside your own selectors.\n\n`light-dark()` follows the nearest color scheme natively. If your build\ntargets browsers without it, Lightning CSS and others polyfill it in a way\nthat breaks nested schemes (ADR 0002); use a token there instead.\n\n### Named themes\n\nInside `theme(name)`, `tokens()` declares a **complete** theme for\n`data-greese-theme=\"name\"`, exactly as `createTheme` does, and component and\nmotion overrides apply only inside it:\n\n```scss\n@include greese.theme(brand) {\n @include greese.tokens(\n (\n color: (\n primary: (\n light: #0f766e,\n dark: #5eead4,\n ),\n ),\n )\n );\n\n @include greese.component(Card) {\n border-radius: 0;\n }\n}\n```\n\nScope it with `ThemeProvider` by name. Its CSS is already in your bundle, so\nthe provider only stamps the attributes (and keeps nested schemes working):\n\n```tsx\n<ThemeProvider theme=\"brand\">…</ThemeProvider>\n```\n\nComponent overrides are descendant selectors, so a theme nested inside\n`brand` still gets `brand`'s component overrides (tokens replace; overrides\nadd up).\n\n### Strict names\n\nUnknown names are build errors:\n\n```\nError: greese ui kit: `Button` has no part `icn`. Parts: icon.\n```\n\nTo target a class this version doesn't know (a part from a newer release, say),\nturn the check off: `@use 'pkg:@greese/ui/scss/kit' as greese with ($strict: false);`.\n\n### The library's own mixins\n\nThe components are written with a handful of partials, and a theme can `@use`\nthem too, so styles copied from a component's source compile in your theme:\n\n| Entry point | What's in it |\n| ------------------------------ | ------------------------------------------------------------------------------------ |\n| `pkg:@greese/ui/scss/mixins` | `up`, `down`, `hover`, `focus-ring`, `touch-target`, `motion-safe`, `component-root` |\n| `pkg:@greese/ui/scss/tones` | `$tones` (each tone's color and content color) and `$brand` |\n| `pkg:@greese/ui/scss/floating` | `surface`, `anchored`, `enter-exit`: what the overlays share |\n| `pkg:@greese/ui/scss/controls` | `$sizes`, `frame`, `focused`, `no-zoom-font`: what the form controls share |\n| `pkg:@greese/ui/scss/maps` | the token maps (`$color`, `$scalars`, `$breakpoints`, `$typography`…) |\n\n```scss\n@use 'pkg:@greese/ui/scss/kit' as greese;\n@use 'pkg:@greese/ui/scss/mixins';\n@use 'pkg:@greese/ui/scss/floating';\n\n@include greese.component(Popover) {\n @include floating.surface;\n\n @include mixins.up(md) {\n padding: greese.token(space, 6);\n }\n}\n```\n\nThey are the modules the library itself loads, so a build with its own\nbreakpoints (`@use 'pkg:@greese/ui/scss' with ($breakpoints: …)`) reaches\n`mixins.up()` too. What writes a component's own class names (the\nresponsive-prop machinery, `tones.classes`) stays private.\n\n## Theme-wide motion\n\n`motion()` gives every instance of a component a default, in pure CSS: what\nthe `greese` prop does per instance, for all of them. It plays behind\n`prefers-reduced-motion: no-preference`.\n\n```scss\n@include greese.component(Card) {\n @include greese.motion(\n (\n enter: fade-up,\n duration: 0.4s,\n distance: 1.5rem,\n )\n );\n}\n\n@include greese.component(Dialog) {\n @include greese.motion(\n (\n exit: scale-out,\n )\n );\n}\n\n@include greese.component(Switch) {\n // The component's own transitions: its duration and easing tokens.\n @include greese.motion(\n (\n durations: (\n fast: 80ms,\n ),\n easings: (\n standard: linear,\n ),\n )\n );\n}\n\n// Tunes every greese prop entrance, and the defaults above.\n@include greese.motion-defaults(\n (\n duration: 0.3s,\n ease: out,\n )\n);\n```\n\n| Option | Does |\n| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |\n| `enter` | A preset played when it appears: `fade-in`, `fade-up`, `fade-down`, `fade-start`, `fade-end`, `scale-in`, `blur-in`, `slide-up`, `pop` |\n| `keyframes` | Your own `@keyframes` name instead |\n| `exit` | How an overlay leaves: `fade-out`, `fade-out-up`, `fade-out-down`, `scale-out` |\n| `duration`, `delay`, `ease`, `distance` | Tune the entrance. `ease` is a name (`out`, `in-out`, …) or a `cubic-bezier()` |\n| `durations`, `easings` | The component's transition speeds and curves, rescoping the tokens to it |\n\nPer instance:\n\n- an instance's own `greese` entrance **replaces** the default (it's in a later\n layer);\n- its `duration`, `delay` and `ease` options **tune** the default;\n- `style={{ animation: 'none' }}` turns it off for that instance.\n\nEntrance presets need the Motion styles: they're in `styles.css`; with\nper-component CSS, also import `@greese/react/css/Motion.css`.\n\nScroll reveals and hover, press and focus effects need the JavaScript\nruntime, so they stay per instance, on the `greese` prop.\n\n## Theme Studio\n\nTheme Studio is a local web app for building a theme visually. It reads and\nwrites a theme file in your project, previews every change live on real\ncomponents, and generates the kit SCSS and the compiled CSS.\n\n```sh\nnpm run studio # the example theme\nGREESE_THEME=src/styles/greese-theme.json npm run studio # yours\nnpm run studio -- --host # also on your phone\n```\n\nOn another device, open the studio link it prints (with a token): until a\ndevice has, its pages load but it can't load, save or import a theme.\n\nIt edits `greese-theme.json` (the source of truth, which you commit) and\nwrites two files next to it on save:\n\n| File | Use it if |\n| ------------------- | ---------------------------------------------------------- |\n| `greese-theme.scss` | Your app compiles Sass: `@use` it after the library styles |\n| `greese-theme.css` | It doesn't: import it after `@greese/react/styles.css` |\n\nBoth are generated; edit the JSON, or use the studio. Put hand-written\noverrides in a stylesheet of your own beside them.\n\nIn the studio:\n\n- **Tokens:** every token, with light and dark colors. Name the theme to\n scope it to `data-greese-theme`.\n- **Component preview:** above the gallery, the component you've picked,\n shown through every story from its docs page, live as you edit it.\n- **Components:** pick one, or switch on **Inspect** and click any element in\n the preview. You get its classes, parts, modifiers and states, its variables\n with their current values, and its motion defaults. Its styles, and those of\n what it contains, are one **SCSS** box that starts as the library's own source\n for them and takes the same imports the components use\n (`@use 'pkg:@greese/ui/scss/mixins'`…, ticked in an **Imports** menu). Once\n you edit it, it applies inside that component only; the same components used\n elsewhere keep their styles.\n- **Motion:** entrance tuning for the whole theme, its motion roles (which\n effect plays where, which timing it takes), and its **Effects**: every\n built-in's keyframes to read or copy, effects of your own, and a stage to\n play sequences on.\n- **Code:** the generated SCSS and CSS, highlighted.\n- **Import:** bring in a theme you already have, then edit it. See below.\n\nThe preview runs in a frame, so the theme never restyles the editor. It\ncompiles through the same kit you'd use by hand, so a theme that previews\ncompiles. If the JSON changes on disk (a pull, another editor), the studio\nreloads it, or asks first when you have unsaved changes.\n\n### Importing an existing theme\n\n**Import** reads a theme you already have into the editor. Paste it, upload\nit, or give a path in your project:\n\n| Source | Read as |\n| --------------------------------------------------------------- | ---------------------------------------------------- |\n| A studio `.json` file | As it is |\n| `createTheme()` options (JSON, or a module exporting them) | Token overrides |\n| A `.ts`/`.js` module exporting `createTheme()` results | Their CSS (the module runs in the studio's server) |\n| SCSS, the kit's or your own | Compiled first; a project file keeps its own `@use`s |\n| CSS: `createTheme()` output, kit output, hand-written overrides | Tokens, component rules and motion |\n\nEverything becomes CSS and is read back:\n\n- **Tokens:** light and dark values come from the scheme selectors and\n media queries. Values equal to the defaults are left out, so a complete\n `createTheme()` theme imports as just its overrides.\n- **Components:** `.greese-<Name>` rules, their parts and modifiers, become\n component styles and variables.\n- **Motion:** the kit's motion output becomes motion settings.\n\nWhat the studio can't hold is listed with its CSS, never dropped silently:\nresponsive or hover rules, other selectors, page CSS, custom keyframes. Copy\nit into a stylesheet of your own.\n\nYou can replace the current theme or merge into it, the import winning.\nNothing changes until you choose, and nothing is written until you save, to\nthe studio's theme file (`GREESE_THEME`). So importing never overwrites your\noriginal. If the CSS holds several named themes, pick which one to edit.\n\nFor safety, paths must be inside the folder you ran npm from.\n\nTheme Studio runs from this repository for now; publishing it as a package\ncomes with the rest of the release work.\n\n## Reference: every component\n\nEvery component's classes, generated from the library's stylesheets, are on\ntheir own page: [Component reference](?path=/docs/guides-component-reference--docs),\nfilterable by name."},{"name":"Svg","title":"SVG drawing and animation","text":"# SVG drawing and animation\n\n`@greese/svg` is a type-safe toolkit for drawing and animating SVG. It has no\ndependencies and needs no framework. It covers:\n\n- building paths and shapes;\n- converting shapes to paths and back;\n- morphing one shape into another;\n- drawing, filling, draining and running strokes as marquees;\n- moving things along a path;\n- gradients, filters, clip paths and masks.\n\n`@greese/react/svg` puts React components on top of it. Live demos are under\n**SVG** in the sidebar.\n\n## Install and import\n\n```sh\nnpm install @greese/svg # plain JavaScript, any framework\n```\n\n```ts\n```\n\nWith React, `@greese/react` already depends on it. Its `svg` entry has the\ncomponents and re-exports every `@greese/svg` function, so one import covers\nboth:\n\n```tsx\n```\n\nEverything is tree-shaken. Approximate sizes, brotli:\n\n| Import | Size |\n| -------------------------------------- | ------ |\n| `dashes` (stroke slices, no measuring) | 0.5 kB |\n| gradients and filters | 1 kB |\n| `path` builder | 1.7 kB |\n| `morph` | 2.8 kB |\n| all of `@greese/svg` | 9.2 kB |\n| `@greese/react/svg`, `Path` alone | 1.9 kB |\n| `@greese/react/svg`, `Morph` alone | 3.7 kB |\n\n## Paths and shapes\n\nAnything that takes a path takes a **`PathInput`**, which is one of:\n\n- path data (`'M0 0H10'`);\n- an array of typed segments (`[['M', 0, 0], ['H', 10]]`);\n- a builder;\n- a **shape spec**: `circle`, `ellipse`, `rect` (with `rx`/`ry`), `line`,\n `polyline`, `polygon`, `regularPolygon`, `star`, `arc` or `path`.\n\n```ts\n\ntoPath({ type: 'star', cx: 50, cy: 50, r: 40, innerRadius: 18, points: 5 })\n\nconst d = path()\n .moveTo(10, 80)\n .curveTo(30, 10, 70, 10, 90, 80)\n .arc({ cx: 50, cy: 80, r: 40, start: 90, length: 180 })\n .close()\n .toString()\n```\n\nTwo conventions apply to every shape:\n\n- **Angles are degrees, clockwise from the top** (12 o'clock). A star's first\n point is at the top, and an `arc` with `start: 0, length: 90` runs from 12\n to 3 o'clock.\n- **Circles and ellipses start at the top and run clockwise**, so strokes on\n them draw the way a clock hand moves.\n\nThe builder has SVG's commands under readable names (`moveTo`, `lineTo`,\n`curveTo`, `smoothCurveTo`, `quadTo`, `arcTo`, `close`) and the shapes\n(`circle`, `rect`, `star`…). Pass `{ relative: true }` to write relative\ncommands.\n\n### Path data in, path data out\n\n| Function | Does |\n| -------------------------------- | ----------------------------------------------------------------------- |\n| `parsePath(d)` | Typed segments, following SVG's grammar (`1.5.5`, packed arc flags…) |\n| `serializePath(segments)` | Path data, rounded (3 decimals by default) |\n| `absolutize(d)` | Every command absolute |\n| `toCubics(d)` | Every subpath as cubic Béziers only: what morphing and measuring use |\n| `reversePath(d)` | The same path, drawn the other way |\n| `transformPath(d, { … })` | Scaled, rotated, translated or `matrix`-ed geometry (arcs stay exact) |\n| `pathLength(d)`, `pointAt(d, %)` | Length, and a point with its direction, with no DOM (in Node, in tests) |\n| `pathSampler(d)` | `pointAt` measured once, for every frame of an animation |\n| `bounds(d)` | The bounding box |\n\n### Shapes to paths, and back\n\n- **Shape to path:** `toPath(spec)` gives path data. `elementToPath(el)`\n reads a `<circle>`, `<rect>`, `<polygon>` or other shape element's geometry\n into path data.\n- **Path to shape:** `pathToShape(d)` gives the simple shape a path draws\n _exactly_ (a `rect`, `circle`, `polygon`…), or `undefined`.\n `pathToPolygons(d, { tolerance })` approximates any path with straight\n lines.\n- **In the DOM:** `convertElement(el, 'path')` swaps an element for a\n `<path>`, and `convertElement(el, 'shape')` swaps it back. Its other\n attributes (class, fill, stroke) come along.\n\n## Morphing\n\n`morph(from, to)` returns a function from progress to path data: 0 gives the\nsource, 1 the target. Values past either end extrapolate, for eases that\novershoot.\n\n```ts\n\nconst mixer = morph({ type: 'star', r: 40 }, { type: 'circle', r: 40 })\npathEl.setAttribute('d', mixer(0.5))\n```\n\nThe shapes don't need the same points first. The morph matches them up:\n\n- **Parts:** a shape with fewer subpaths grows the missing ones from the\n center of their partners.\n- **Points:** curves are split until both sides have as many. Splitting\n leaves a shape exactly as it was.\n- **Alignment:** a closed target is turned, and reversed if that's closer, to\n the starting point where the points travel least, so the shape doesn't\n twist. Turn this off with `{ align: false }`.\n\n`morphSequence([a, b, c])` runs through a list: progress 1.5 is halfway from\n`b` to `c`.\n\nTo morph with an animation library that tweens numbers inside strings,\n`matchPaths(a, b)` returns both shapes with the same commands. With\ngreese.js:\n\n```ts\n\nanimate(pathEl, { d: matchPaths(star, circle) }, { duration: 0.6 })\n```\n\n## Strokes: draw, fill, drain, marquee\n\nA **slice** is the part of a stroke that's drawn, in percent of its length:\n\n| Slice | Draws |\n| ------------------------- | -------------------------------------------- |\n| `{ end: 60 }` | the first 60% |\n| `{ start: 30, end: 70 }` | the middle 40% |\n| `{ end: 20, offset: 90 }` | 90% to 100%, then 0% to 10%: it wraps around |\n| `{ end: 5, repeat: 8 }` | eight 5% dashes, evenly spaced |\n\n`dashes(slice, length)` turns a slice into `stroke-dasharray` and\n`stroke-dashoffset`. Measuring is optional: with `pathLength=\"100\"` on the\nelement and the default `length` of 100, the result works in CSS and on the\nserver.\n\nA simple slice is written as one dash and one gap, so a CSS `transition` on\nthose two properties, or Web Animations, interpolates between slices\nexactly. A slice that wraps or repeats can't be written that way, so\n`strokeKeyframes(from, to)` samples it.\n\nZero-length dashes still draw a dot under round or square caps. An empty\nslice at either end is therefore moved just off the path.\n\n**Animating.** A control is an object whose properties write to the element:\n\n```ts\n\nconst stroke = strokeControl(pathEl, { end: 0 })\nanimate(stroke, { end: 100 }, { duration: 1 }) // fill\nanimate(stroke, { start: 100 }, { duration: 1 }) // then drain\nstroke.set({ end: 8, repeat: 6 })\nanimate(stroke, { offset: [0, 100 / 6] }, { repeat: -1, ease: 'linear' }) // marquee\n```\n\nAny library that tweens plain object properties drives controls the same way.\nThere's one for each kind of motion:\n\n| Control | Its properties |\n| ------------------------------------- | ---------------------------------------------------- |\n| `strokeControl(el, slice)` | `start`, `end`, `offset`, `repeat` |\n| `morphControl(el, from, to)` | `progress` (0–1) |\n| `followControl(el, path, { rotate })` | `progress` (0–100); moves the element along the path |\n| `gradientControl(el)` | `angle`; each stop's `offset`, `color`, `opacity` |\n\n**Without an animation library**, `tween(update, options)` calls `update`\neach frame with eased progress. It respects `prefers-reduced-motion`, and you\ncan await it. These helpers are built on it:\n\n- `drawStroke(el, from, to)`;\n- `fillStroke(el, { start, end })`;\n- `drainStroke(el, { start, end })`;\n- `marqueeStroke(el, { count, size })`;\n- `morphPath(el, to)`.\n\n## Gradients, filters, clip paths and masks\n\nThe builders return elements as data (`SvgNode`). From there:\n\n- `toMarkup(node)` writes SVG markup (servers, `innerHTML`);\n- `toElement(node)` builds DOM;\n- `define(svg, ...nodes)` adds them to an `<svg>`'s `<defs>`, replacing any\n with the same id;\n- the React components render the same nodes.\n\n```ts\n\ndefine(\n svgEl,\n linearGradient({\n id: 'sky',\n angle: 135,\n stops: ['#38bdf8', { color: '#6366f1', offset: 80 }],\n }),\n filter({\n id: 'glow',\n effects: glow({ color: 'gold', blur: 6 }),\n x: '-50%',\n y: '-50%',\n width: '200%',\n height: '200%',\n })\n)\nshapeEl.setAttribute('fill', url('sky'))\n```\n\n- **Gradients:** `linearGradient` takes a CSS-style `angle` (180 runs top to\n bottom) or its points. `radialGradient` takes a circle and a focal point.\n Stops without an `offset` are spaced evenly.\n- **Filter primitives:** `blur`, `offset`, `flood`, `dropShadow`,\n `composite`, `blend`, `merge`, `colorMatrix`, `turbulence`,\n `displacementMap` and `morphology`, each typed.\n- **Filter presets:** `glow`, `goo` (shapes that merge like liquid), `grain`\n and `distort`.\n- **Clip paths and masks:** `clipPath` and `mask` take shapes as their\n content. A mask fills its shapes white, so they reveal.\n\n## React: `@greese/react/svg`\n\n| Component | Renders on the server | What it does |\n| ---------------------------------- | :-------------------: | ---------------------------------------------------------------------------------------------- |\n| `Drawing` | yes | The `<svg>`: an image named by `label`, or hidden from screen readers; takes the `greese` prop |\n| `Path` | yes | `d` is path data or a shape spec; `slice` draws part of the stroke |\n| `DrawPath` | client | Draws its stroke from `from` to `to`, and on to each new `to`, from where it is |\n| `MarqueePath` | client | Dashes running along the path without end |\n| `Morph` | client | Morphs to `shapes[index]`, in from `from` on mount; or follow `progress` (server-safe) |\n| `LinearGradient`, `RadialGradient` | yes | Gradients by angle or points |\n| `Filter` | yes | `effects` from the primitives and presets |\n| `ClipPath`, `Mask` | yes | `content` shapes, plus any children |\n\n```tsx\n<Drawing viewBox=\"0 0 100 100\" label=\"Saved\">\n <defs>\n <LinearGradient id=\"ok\" angle={135} stops={['#22c55e', '#16a34a']} />\n </defs>\n <Path d={{ type: 'circle', cx: 50, cy: 50, r: 44 }} fill={url('ok')} />\n <DrawPath\n d=\"M30 52l14 14 26-30\"\n to={{ end: 100 }}\n duration={0.5}\n delay={0.2}\n fill=\"none\"\n stroke=\"white\"\n strokeWidth={8}\n strokeLinecap=\"round\"\n />\n</Drawing>\n```\n\n`DrawPath` and `MarqueePath` run on Web Animations with `pathLength=\"100\"`,\nso nothing is measured.\n\n`DrawPath` renders its `to` slice. Before JavaScript runs, and under reduced\nmotion, it shows its final state; it then plays from `from` before the first\npaint.\n\n`Morph` animates with `tween()` and writes `d` directly: no React render per\nframe.\n\n## Accessibility and motion\n\n- Give a meaningful drawing a `label` (on `Drawing`). One without a label is\n decorative and hidden from screen readers.\n- Every animation here respects `prefers-reduced-motion`:\n - `tween()`, and the helpers on it, skip to the end;\n - `DrawPath` shows its target;\n - `MarqueePath` holds still;\n - `Morph` jumps to its shape.\n\n `tween()`'s `reducedMotion: 'ignore'` opts out, for motion that carries\n meaning.\n\nDesign decisions: [ADR 0031](https://github.com/chris-moody/greese/blob/main/docs/adr/0031-svg-package.md)."},{"name":"Theming","title":"Theming","text":"# Theming\n\ngreese ui's look is a set of design tokens. Each one is a CSS custom property\n(`--greese-color-primary`, `--greese-space-4`, `--greese-radius-md`, …), and every\ncomponent reads them. To theme the library, you change token values. There's\nno theme object in React state, no re-render when the theme changes, and no\nCSS-in-JS runtime.\n\nThis guide covers, in order:\n\n1. [Setup](#setup): the steps every app needs, and the optional ones.\n2. [Light and dark](#light-and-dark): following the OS, a user toggle, and no\n flash on load.\n3. [Brand themes](#brand-themes-createtheme): `createTheme` and `ThemeProvider`.\n4. [Overriding in plain CSS](#overriding-in-plain-css), for one-off changes.\n5. [Per-component variables](#per-component-variables).\n6. [Server rendering and frameworks](#server-rendering-and-frameworks).\n7. [Adding tokens](#adding-your-own-tokens), [custom breakpoints](#custom-breakpoints) and [without React](#without-react).\n8. [Token reference](#token-reference) and [troubleshooting](#troubleshooting).\n\n## How it fits together\n\n| Layer | What it holds | Set by |\n| ------------------- | ------------------------------------ | ---------------------------------------- |\n| `greese.tokens` | Default token values, light and dark | `styles.css` |\n| `greese.theme` | Your themes' token values | `createTheme` + `ThemeProvider` |\n| `greese.components` | Component styles, which read tokens | `styles.css` or `css/<Name>.css` |\n| `greese.overrides` | Your component overrides | The SCSS kit (Guides/Styling components) |\n| `greese.utilities` | Style props and the `greese` prop | Props, per instance |\n| (unlayered) | Your own CSS | You |\n\nAll library CSS lives in [cascade layers](https://developer.mozilla.org/docs/Web/CSS/@layer).\nUnlayered CSS always beats layered CSS whatever the specificity, so your\nstylesheet wins without `!important`.\n\nTwo attributes drive everything, and they work on any element, `<html>`\nincluded:\n\n- `data-greese-scheme=\"light\" | \"dark\" | \"system\"` forces a color scheme for\n that subtree. With no attribute anywhere, the page follows the OS.\n- `data-greese-theme=\"<name>\"` applies a theme from `createTheme`.\n\n## Setup\n\nNo provider is needed to use greese ui: the styles load once and every component works. `ThemeProvider` is optional. Reach for it only to apply a `createTheme()` theme, or to force a color scheme, on all or part of the page. The steps below say which are required.\n\n### 1. Install (required)\n\n```sh\nnpm install @greese/react\n```\n\n`@greese/ui` comes with it. React 19 is a peer dependency.\n\n### 2. Load the styles (required)\n\nPick **one** of these:\n\n```ts\n// Everything (about 23 kB brotli). Simplest.\n```\n\n```ts\n// Only what you use: each file @imports the tokens and the components it\n// builds on, and bundlers de-duplicate shared imports.\n```\n\nOptionally, also load the reset and page defaults (box-sizing, body font and\ncolors, `canvas` background):\n\n```ts\n```\n\nWithout `base.css`, components are still fully styled. Your page background\njust won't switch with the color scheme unless you set it yourself, for\nexample with `body { background: var(--greese-color-canvas); color: var(--greese-color-fg) }`.\n\nAt this point everything follows the OS light/dark setting. **No provider is\nrequired.** The remaining steps are optional.\n\n### 3. Stop the dark-mode flash (recommended if users can choose a scheme)\n\nIf you let users pick a scheme, their saved choice must apply before the\nfirst paint. Put this inline script in `<head>`, before your stylesheets:\n\n```tsx\n\n;<head>\n <script dangerouslySetInnerHTML={{ __html: getSchemeScript() }} />\n</head>\n```\n\nIt reads `localStorage` and sets `data-greese-scheme` on `<html>`. It's a few\nhundred bytes, and it never throws, even when storage is blocked. If your CSP\nblocks inline scripts, add a nonce or hash for it.\n\nBecause the script changes `<html>` before React hydrates, add\n`suppressHydrationWarning` to your `<html>` element in server-rendered apps.\n\n### 4. Add a scheme toggle (optional)\n\n```tsx\n'use client'\n SegmentedControl,\n Segment,\n useColorScheme,\n type ColorScheme,\n} from '@greese/react'\n\n const { scheme, setScheme } = useColorScheme()\n return (\n <SegmentedControl\n label=\"Theme\"\n value={scheme}\n onValueChange={(value) => setScheme(value as ColorScheme)}\n >\n <Segment value=\"system\">System</Segment>\n <Segment value=\"light\">Light</Segment>\n <Segment value=\"dark\">Dark</Segment>\n </SegmentedControl>\n )\n}\n```\n\n`setScheme` writes one attribute and saves the choice. `resolvedScheme` tells\nyou what's actually showing (`system` resolved against the OS). If you pass a\ncustom `storageKey` to `useColorScheme`, pass the same one to\n`getSchemeScript`.\n\n### 5. Add a brand theme (optional)\n\nSee [Brand themes](#brand-themes-createtheme). To theme the whole app, wrap\nthe root:\n\n```tsx\n<ThemeProvider theme={brand} asChild>\n <body>…</body>\n</ThemeProvider>\n```\n\n## Light and dark\n\nEvery color token has a light and a dark value. Which one applies is decided\nper element:\n\n| Situation | Result |\n| ----------------------------------------------------------------- | --------------------------------------- |\n| No `data-greese-scheme` anywhere | Follows the OS (`prefers-color-scheme`) |\n| `data-greese-scheme=\"dark\"` on `<html>` (set by `useColorScheme`) | Whole page dark |\n| `<ThemeProvider scheme=\"dark\">` around a section | That section dark, whatever the page is |\n| `scheme=\"system\"` on a provider inside a forced-dark page | That section follows the OS again |\n\nSchemes nest, so a light card inside a dark hero is just a nested provider:\n\n```tsx\n<ThemeProvider scheme=\"dark\">\n <Hero>\n <ThemeProvider scheme=\"light\">\n <Card>…</Card>\n </ThemeProvider>\n </Hero>\n</ThemeProvider>\n```\n\nThe scheme also sets CSS `color-scheme`, so native scrollbars, form controls\nand date pickers match.\n\n## Brand themes: `createTheme`\n\n```tsx\n\n// At module scope: it builds a static CSS string once.\n name: 'brand',\n color: {\n // A light/dark pair, from the palette (Foundations/Color)…\n primary: { light: palette.lavender[600], dark: palette.lavender[300] },\n // primaryContent and primaryStrong follow: readable ink (WCAG AA) and a\n // hover shade, derived for you. Set them to choose your own, in any CSS\n // color, one value or a pair.\n secondary: '#0f766e',\n },\n radius: { sm: '6px', md: '12px', lg: '20px' },\n font: { body: \"'Inter', system-ui, sans-serif\" },\n})\n\n<ThemeProvider theme={brand}>…</ThemeProvider>\n```\n\nWhat to know:\n\n- **Any token can be overridden.** Colors take a string or a\n `{ light, dark }` pair. Every other group (`space`, `radius`, `font`,\n `fontWeight`, `lineHeight`, `shadow`, `zIndex`, `duration`,\n `easing`) takes strings. Values can be any CSS: `oklch(…)`, `var(--x)`,\n `clamp(…)`. Characters that could break out of a declaration (`;`, `{`,\n `}`, `<`, `>`) throw.\n- **Themes replace, they don't stack.** A theme is the defaults plus its\n overrides, and it declares every token. Nesting `ThemeProvider theme={a}`\n inside `theme={b}` gives you exactly `a`. To extend a theme, spread your\n options: `createTheme({ ...brandOptions, name: 'brand-compact', space: { … } })`.\n- **Theme and scheme are independent.** A scheme-only provider inside a theme\n keeps the theme, and vice versa.\n- **Four brand colors, in order: `primary`, `secondary`, `tertiary`,\n `accent`.** Components use `primary` for interactive emphasis (solid\n buttons, links, focus, selection), and every `tone` prop takes all four.\n Set `primary` to rebrand; the focus ring follows it.\n- **Derived states follow.** Hover, active, soft and outline variants are\n computed from the tone with `color-mix()`. Change `primary`, and every\n button, link, focus ring and selected state updates, in both schemes.\n- **Content colors are derived and WCAG-safe.** Each brand color (and\n `negative`) has a `…Content` color for text and icons on it\n (`--greese-color-primary-content`). When you set the main color,\n `createTheme` picks the more readable of white and near-black, at least\n 4.5:1, separately for light and dark, and mixes a `…Strong` shade from it.\n Anything you set yourself wins. Colors it can't measure (`var()`,\n `oklch()`) keep the default content color, so check those. The SCSS kit's\n `tokens()` does the same at build time.\n- **No cost per render.** `ThemeProvider` renders a `<style href precedence>`\n that React 19 hoists into `<head>` and de-duplicates, plus two attributes.\n The wrapper is `display: contents`; use `asChild` to put the attributes on\n your own element instead.\n- `name` scopes the CSS (`[data-greese-theme=\"brand\"]`). Use letters, digits\n and `-`, and give each theme a unique name.\n\nRead the nearest provider's theme and scheme with `useThemeScope()`, for\nexample to pick a matching chart palette.\n\n**At build time instead.** The SCSS kit compiles the same theme into your\nCSS, with no theme object in JavaScript, and **Theme Studio** builds one\nvisually. Pass the name to the provider; it stamps the attributes and\ninjects nothing:\n\n```scss\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.theme(brand) {\n @include greese.tokens(\n (\n color: (\n primary: (\n light: #7c3aed,\n dark: #c4b5fd,\n ),\n ),\n )\n );\n}\n```\n\n```tsx\n<ThemeProvider theme=\"brand\">…</ThemeProvider>\n```\n\nSee **Guides/Styling components**.\n\n### Several themes on one page\n\n```tsx\nconst ocean = createTheme({ name: 'ocean', color: { primary: '#0891b2' } })\nconst sunset = createTheme({ name: 'sunset', color: { primary: '#ea580c' } })\n\n<ThemeProvider theme={ocean}><Pricing plan=\"pro\" /></ThemeProvider>\n<ThemeProvider theme={sunset}><Pricing plan=\"team\" /></ThemeProvider>\n```\n\nEach theme's CSS is injected once, however many providers use it.\n\n## Shapes\n\nA shape outlines an element with one clip and a border that follows it, and\nanimates by its parameters. A 12px corner stays 12px at any size, and the\nborder never comes apart from the shape, mid-animation included.\n\n### Color, shape and motion themes\n\nA theme composes three layers: colors, shapes and motion (ADR 0025). Each\nlayer's themes change only that layer, so they mix freely.\n\n**Themes reassign; they never overwrite.** A color theme points the color roles\n(`primary`, `surface`…) at colors, a shape theme points the radius roles at the\nradius scale, and a motion theme points the motion roles at effects and timing\ntokens. The palette, the radius scale, the duration and easing tokens and every\neffect keep their own values under every theme: `--greese-radius-md` is 8px and\n`fadeUp` fades up, whatever the page wears.\n\n**Color themes** set the brand colors and the neutrals (canvas, surfaces,\ntext, borders), tinted from one hue, in both schemes. Content and strong\nshades are derived from each color, so text stays readable (WCAG AA). They set\nno shapes and no motion.\n\n| Theme | Colors |\n| -------- | ----------------------------------------------------------------------------- |\n| `greese` | The official theme: a warm orange primary on the library's own neutrals |\n| `ocean` | Deep azure, royal blue, turquoise and a gold accent, on azure-tinted neutrals |\n| `sunset` | Burnt orange, ruby, gold and a magenta accent, on orange-tinted neutrals |\n| `forest` | Jade, lime, aqua and an orange accent, on jade-tinted neutrals |\n| `grape` | Lavender, magenta, royal blue and a jade accent, on lavender-tinted neutrals |\n| `mono` | Near-black and grays, taupe and a single red accent |\n| `candy` | Pink, azure, lavender and a yellow accent, on pink-tinted neutrals |\n\n```ts\n```\n\n**Shape themes** reassign the radius roles and outline every kind of component\n(controls, fields, containers, indicators, avatars, tabs), with smaller\nfeatures on smaller controls. They set no colors and no motion.\n\n| Theme | Shapes |\n| --------- | ------------------------------------------------------------------------------------------------------- |\n| `bevel` | Chamfered corners that slide to the other diagonal on hover; hexagon indicators, trapezoid tabs |\n| `ticket` | Round side notches on containers, fields and tabs; tag-shaped controls and badges |\n| `ridge` | Zigzag hems on containers, zigzag ends on controls, zigzag-topped tabs, diamond knobs |\n| `folio` | Dog-eared containers, leaning controls; tab panels are folders the current tab opens into |\n| `soft` | Every corner rounded, a step rounder than the library; accordion items as rounded panels |\n| `pebble` | Controls, fields, tabs and badges as pills, so square ones are circles; containers extra-rounded |\n| `extrude` | Keycap depth drawn inside each box: raised controls that sink when pressed, recessed fields |\n| `tilt` | Real perspective on hover and press: controls lean back, cards turn and lift, the current tab stands up |\n\nThe first four outline components with a clip and a ring (ADR 0024). Soft and\nPebble only reassign radius roles; Extrude and Tilt add depth, Extrude with\ninset shadows (inside the box, so a motion theme's mask never cuts them off)\nand Tilt with `transform` on hover and press only, so nothing rests turned\nand a motion theme's three-dimensional entrances start and end where the\nelement sits.\n\n**Motion themes** pace every entrance and assign which built-in effect plays\nwhere: the `'theme'` entrance (`greese=\"theme\"`, so a page's reveals follow the\ntheme), tab panels and an accordion's content, table rows, toasts and overlays,\neach with the duration and easing it takes. They set no colors and no shapes.\n\n| Theme | Motion |\n| -------- | ------------------------------------------------------------------------------------------------------------- |\n| `snappy` | Short and sharp: reveals pop in, overlays scale in and away |\n| `gentle` | Long and soft: content comes into focus out of a blur, overlays sink away |\n| `wipe` | Revealed, not moved: reveals wipe up, menus wipe down, dialogs open and close as a circle |\n| `pocket` | Everything rises out of an invisible slot at one of its own edges, and sinks back in |\n| `depth` | In three dimensions: reveals flip up, menus swing down from their top edge, dialogs rise from behind the page |\n\n**Color variants** say how a color theme's colors are worn, so any color\ntheme takes any variant. `outline` draws what is usually filled (solid and\nsoft buttons and badges, soft alerts, filled and elevated cards and tiles,\navatars, the current tab and segment, toasts, tooltips) as an outline in its color, with text to match,\nand fills what was outlined. A variant reassigns the colors each component\nvariant draws with (`modifiers` in the kit), never the color tokens or\ncomponent SCSS, so it goes with every shape theme.\n\n```ts\n```\n\nLoad one of each after greese ui's styles:\n\n```ts\n```\n\nWipes, irises and pockets are masks, so they compose with a shape's clip; no\neffect touches `clip-path`. Every motion theme's entrances are off for visitors\nwho reduce motion.\n\n#### Motion roles\n\nComponents have no motion of their own: each says what it is (a dialog, a\npopover) and where it opens from (`--greese-overlay-origin`), and reads its\nmotion from a role. Assign roles with the kit's `motion-defaults()`; effects by\nname, durations and easings by token name or as values:\n\n```scss\n@include greese.motion-defaults(\n (\n theme: pocket-up,\n // greese=\"theme\"\n content: wipe-open-x,\n // tab panels', an opening accordion's children\n rows: fade-up,\n // a table's rows, one after another\n dialog: iris-in,\n dialog-exit: iris-out,\n popover: wipe-down,\n // menus and speed-dial actions too\n popover-exit: wipe-out-up,\n content-duration: slow,\n // var(--greese-duration-slow)\n enter-ease: enter,\n // var(--greese-easing-enter)\n )\n);\n```\n\n| Role | Plays | Base theme |\n| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------- |\n| `theme` | `greese=\"theme\"` | `fadeUp` |\n| `content` | tab panels' and an opening accordion's children | a short rise |\n| `rows` | table rows | none |\n| `toast`, `backdrop` | toasts, a dialog's scrim | a short rise, a fade |\n| `overlay` | every overlay but a drawer | a fade from its origin |\n| `dialog`, `popover`, `tooltip` | one kind (falls back to `overlay`) | `overlay`'s |\n| `drawer` | drawers and the off-canvas sidebar | a slide from its edge |\n| `overlay-exit`, `dialog-exit`, `popover-exit`, `tooltip-exit`, `drawer-exit` | how they leave | a fade toward the origin |\n| `content-duration`, `rows-duration`, `overlay-duration`, `toast-duration`, `backdrop-duration`, `exit-duration` | how long | `normal`, `slow`, `fast`, `normal`, `normal`, `fast` |\n| `enter-ease`, `exit-ease` | the curves | `enter`, `exit` |\n| `page`, `page-back` | a page transition's new page, forward and back | a fade in |\n| `page-exit`, `page-back-exit` | how the old page leaves | a fade out |\n| `page-duration`, `share-duration`, `page-ease`, `share-ease` | a page change's pace, a shared element's morph | `normal`, the library's ease out |\n| `page-stagger`, `page-exit-order`, `page-mode` | a live exit's spacing and order, the mode | the entrance stagger, `reverse`, `auto` |\n\nEach is a custom property, `--greese-motion-<role>` (an exit role's are\n`--greese-motion-<role>-<property>`), so plain CSS can assign one too. The\npage roles drive page transitions (ADR 0029): a page role's value is the\n`@keyframes` its snapshot plays, and the kit's `page-transitions()` gives parts\nof a page effects of their own. A\ncomponent's `motion()` in the kit, or an instance's `greese` prop, overrides\nits role.\n\n#### Radius roles\n\nComponents read the radius roles, never the radius scale directly:\n\n| Role | Parts | Base theme |\n| ------------------------- | --------------------------------------------------------- | ---------- |\n| `--greese-corner-control` | buttons, segmented controls, file pickers | `md` |\n| `--greese-corner-field` | text fields and selects, OTP cells | `md` |\n| `--greese-corner-surface` | cards, dialogs, fieldsets, lists, stats, chat bubbles | `lg` |\n| `--greese-corner-panel` | alerts, tiles, tables, code, media, popovers and menus | `md` |\n| `--greese-corner-inset` | tabs, menu items, tooltips, keys, checkboxes | `sm` |\n| `--greese-corner-pill` | badges, chips, tracks, progress bars | `pill` |\n| `--greese-corner-round` | knobs, thumbs, radios, step markers, avatars, status dots | `round` |\n\nA shape theme points them at `none` (`createTheme({ corner: { control:\n'var(--greese-radius-none)' } })`, or `tokens.corner` in the kit), and Bevel and\nRidge also turn round parts to diamonds. Your own CSS can use a role to follow\nthe theme, or the scale to stay as it is.\n\n### Any element\n\nEvery shape is also a class. A shape theme's `bevel-card`, for example:\n\n```html\n<section class=\"greese-shape-bevel-card\">…</section>\n```\n\nIts parameters are custom properties, so one element can differ:\n`style=\"--greese-shape-a: 32px\"`. So is its border color:\n`--greese-shape-ring`.\n\n### Making your own\n\nIn Theme Studio's **Shapes** tab:\n\n- start from a preset (bevel, notch, tag, hexagon, slant, dog-ear, ticket,\n zigzag, shield);\n- drag its points;\n- set its parameters for rest, hover, pressed and entrance;\n- choose which components take it.\n\nThe theme's SCSS and CSS include it. From code, `shapesCss()` in\n`@greese/ui/shapes` writes the same CSS (a build-time module, not a runtime\none).\n\nEvery shape:\n\n- keeps keyboard focus visible: it opens to its box for the focus ring, or\n draws a ring inside;\n- moves only for visitors who allow motion;\n- keeps shaped buttons 44px on touch screens;\n- steps aside in forced-colors mode.\n\nA clip also cuts anything painted outside the box, so shaped elements don't\ncast shadows. ADR 0024 has the details.\n\n## Overriding in plain CSS\n\nFor a quick change, set tokens in your own (unlayered) stylesheet.\nScheme-independent tokens are simple:\n\n```css\n:root {\n --greese-radius-md: 12px;\n --greese-font-body: 'Inter', system-ui, sans-serif;\n}\n```\n\n**Colors need care.** The default dark values are declared on\n`[data-greese-scheme]` elements and under `prefers-color-scheme: dark`. A plain\n`:root { --greese-color-primary: … }` would therefore apply in dark mode too,\nand be ignored inside any `<ThemeProvider scheme>`. Mirror the library's\nselectors:\n\n```css\n:root,\n[data-greese-scheme='light'],\n[data-greese-scheme='system'] {\n --greese-color-primary: #7c3aed;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme='light']),\n [data-greese-scheme='system'] {\n --greese-color-primary: #c4b5fd;\n }\n}\n\n[data-greese-scheme='dark'] {\n --greese-color-primary: #c4b5fd;\n}\n```\n\n`createTheme` generates exactly this for you, so prefer it for colors.\n\nAlso note that a `ThemeProvider` theme declares every token on its own\nelement, so `:root` overrides don't reach inside one. Put the override in the\ntheme instead.\n\n## Per-component variables\n\nSome components expose variables for things a token can't express. Set them\non the component, a class, or any ancestor:\n\n```css\n/* Every button in this area uses the negative tone. */\n.danger-zone .greese-Button {\n --greese-button-tone: var(--greese-color-negative);\n --greese-button-on-tone: var(--greese-color-negative-content);\n}\n\n/* A wider sidebar and roomier cards. */\n.app {\n --greese-sidebar-width: 18rem;\n}\n.greese-Card {\n --greese-card-padding: var(--greese-space-6);\n}\n```\n\n| Component | Variables |\n| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Button, IconButton | `--greese-button-tone`, `--greese-button-on-tone` (variants derive from these), `--greese-button-height`, `--greese-button-padding` |\n| Input, Select, Textarea, FileInput | `--greese-input-height`, `--greese-input-padding`, `--greese-select-height`, `--greese-select-padding`, `--greese-textarea-padding`, `--greese-file-font` |\n| Card | `--greese-card-padding` |\n| Dialog | `--greese-dialog-width` |\n| Sidebar | `--greese-sidebar-width` |\n| Avatar, Spinner, Progress | `--greese-avatar-size`, `--greese-spinner-size`, `--greese-progress-height` |\n| Slider, ColorPicker | `--greese-slider-thumb`, `--greese-colorpicker-thumb` |\n| SegmentedControl, Table | `--greese-segment-height`, `--greese-table-cell-padding` |\n| Rating, Status, Stat, List | `--greese-rating-size`, `--greese-rating-on`, `--greese-rating-off`, `--greese-status-size`, `--greese-stat-padding`, `--greese-list-padding` |\n| Carousel, Diff, Steps, RadialProgress | `--greese-carousel-gap`, `--greese-diff-thumb`, `--greese-steps-marker`, `--greese-steps-prefix` (the before-column), `--greese-chat-tail`, `--greese-tile-padding`, `--greese-radialprogress-size`, `--greese-radialprogress-thickness` |\n| Motion (the `greese` prop) | `--greese-motion-duration`, `--greese-motion-delay`, `--greese-motion-distance`, `--greese-motion-ease`, and the named curves `--greese-ease-in`, `-out`, `-in-out`. Set on `:root` or any ancestor (see **Guides/Animation**) |\n\nThis table is the short list. Every component's docs page ends with a\n**Styling** section listing all its classes and variables, and\n**Guides/Styling components** covers overriding them, the SCSS kit,\ntheme-wide motion and Theme Studio.\n\nClass names (`greese-Button`, `greese-Card`, …) are stable, prefixed and never\nhashed, so they're safe to target. Internal parts (`greese-Dialog-title`) may\nchange in a minor release; through the SCSS kit, a renamed part fails your\nbuild instead of silently not matching.\n\n## Server rendering and frameworks\n\nTheming is plain CSS plus attributes, so it renders on the server with no\nextra setup. Two things to get right:\n\n- Put `getSchemeScript()` in `<head>` and add `suppressHydrationWarning` to\n `<html>` (see [step 3](#3-stop-the-dark-mode-flash-recommended-if-users-can-choose-a-scheme)).\n- Call `createTheme` at module scope, never during render.\n\n**Next.js (App Router)**, `app/layout.tsx`:\n\n```tsx\n\n return (\n <html lang=\"en\" suppressHydrationWarning>\n <head>\n <script dangerouslySetInnerHTML={{ __html: getSchemeScript() }} />\n </head>\n <ThemeProvider theme={brand} asChild>\n <body>{children}</body>\n </ThemeProvider>\n </html>\n )\n}\n```\n\n`ThemeProvider` is a client component; a server-component layout can render\nit as shown. A component that calls `useColorScheme` needs `'use client'`.\n\n**Vite / single-page apps**: put the script tag in `index.html`, inline:\n\n```html\n<script>\n /* paste the output of getSchemeScript() here, or inject it at build time */\n</script>\n```\n\n## Typography\n\nThe type system, named text styles that change across breakpoints, is set in\na theme with `typography` (see Foundations/Typography):\n\n```ts\ncreateTheme({\n name: 'brand',\n typography: { h1: { base: { fontSize: '2rem' }, lg: { fontSize: '4rem' } } },\n})\n```\n\n## Adding your own tokens\n\n`createTheme` takes `extend` for tokens the system doesn't have. Each is\ndeclared as `--greese-<group>-<name>` in that theme (a color in both schemes),\nfor your CSS and component overrides to read:\n\n```ts\n name: 'brand',\n extend: {\n color: { 'brand-ink': { light: '#1b1340', dark: '#e5defc' } },\n lineHeight: { loose: '2' },\n space: { 9: '4rem' },\n },\n})\n```\n\nAn existing name, or a group that doesn't exist, throws; set built-in tokens\nthrough their own group. The SCSS kit has the same option (`$extend`: see\nGuides/Styling components), and Theme Studio adds them with the \"Add a\n… token\" row in each token section.\n\n## Custom breakpoints\n\nBreakpoint values compile into media queries, so they're fixed when the\nstylesheet is built, not in a theme and not at runtime. You can change the\nvalues and **add keys**. The five built-in keys (`xs`–`xl`) stay, because\ncomponents use them; list the keys smallest first, with `xs` at `0px`, and\nwrite each as one word (quote one that starts with a digit: `'2xl'`):\n\n```scss\n// your-styles.scss, instead of importing styles.css\n@use 'pkg:@greese/ui/scss' with (\n $breakpoints: (\n xs: 0px,\n sm: 480px,\n tablet: 700px,\n md: 768px,\n lg: 1024px,\n xl: 1440px,\n )\n);\n```\n\nEvery key, added ones included, gets responsive classes\n(`greese-Stack--tablet-gap-3`, so `gap={{ tablet: 3 }}` works) and a custom\nproperty in the built CSS, **`--greese-breakpoint-tablet: 700px`**, which\nyour own CSS and JavaScript can read, for example\n`max-inline-size: var(--greese-breakpoint-md)`. (A custom property can't go\ninside a `@media` condition; that's why the values are fixed at build time.)\n\n```ts\n// Before the first render: hooks and Sidebar read these in JS.\nconfigureBreakpoints({ sm: 480, tablet: 700, md: 768, lg: 1024, xl: 1440 })\n\n// For TypeScript, tell it about an added key (once, in any .d.ts):\ndeclare module '@greese/ui' {\n interface BreakpointKeys {\n tablet: true\n }\n}\n```\n\nCompile with Sass's `NodePackageImporter`, which resolves `pkg:` URLs. In Vite:\n\n```ts\n\n css: { preprocessorOptions: { scss: { importers: [new NodePackageImporter()] } } },\n})\n```\n\n## Without React\n\nA theme is just a string. Serve `brand.css` yourself (write it at build time,\nor inline it from the server) and set the attribute:\n\n```ts\n\nwriteFileSync('public/brand.css', brand.css)\n```\n\n```html\n<link rel=\"stylesheet\" href=\"/brand.css\" />\n<html data-greese-theme=\"brand\">\n …\n</html>\n```\n\n`@greese/ui/tokens.css` has the default tokens on their own, for\nnon-React code that should match.\n\n## Token reference\n\nThe live values, with swatches, are under **Foundations/Tokens**, and the\ncolor roles and palette under **Foundations/Color**. The property name is\n`--greese-<group>-<key>`, with camelCase keys in kebab case.\n\n| Group | `createTheme` key | Keys |\n| ------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Color | `color` | `canvas`, `surface`, `surfaceOverlay`, `fg`, `fgMuted`, `border`, `borderStrong`, `track`, `primary`, `secondary`, `tertiary`, `accent` (each with `…Strong` and `…Content`), `focusRing`, `positive`, `negative`, `negativeContent`, `warning`, `info`, `scrim` |\n| Spacing | `space` | `0`–`8` (`0`, `0.25rem`, `0.5rem`, `0.75rem`, `1rem`, `1.5rem`, `2rem`, `3rem`, `4rem`) |\n| Radius | `radius` | `none`, `sm`, `md`, `lg`, `xl`, `pill`, `round` |\n| Radius roles | `corner` | `control`, `field`, `surface`, `panel`, `inset`, `pill`, `round`: which step of `radius` each kind of part takes |\n| Font family | `font` | `body`, `mono` |\n| Type system | `typography` | variants `p1`–`p3`, `h1`–`h6`, `s1`, `s2`, `caption`, `button`: font size, weight, letter spacing, line height (see Typography) |\n| Font weight | `fontWeight` | `regular`, `medium`, `semibold`, `bold` |\n| Line height | `lineHeight` | `tight`, `snug`, `normal` |\n| Shadow | `shadow` | `sm`, `md`, `lg` |\n| Stacking | `zIndex` | `dropdown`, `sticky`, `overlay`, `modal`, `popover`, `toast`, `tooltip` |\n| Motion | `duration`, `easing` | `fast`, `normal`, `slow`; `standard`, `enter`, `exit` |\n\nDurations collapse to near zero under `prefers-reduced-motion: reduce`, in\nthemes too.\n\n## Troubleshooting\n\n| Symptom | Cause and fix |\n| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |\n| Dark-mode users see a white flash on load | Add `getSchemeScript()` to `<head>`, before stylesheets |\n| Hydration warning about `data-greese-scheme` | Add `suppressHydrationWarning` to `<html>` |\n| My `:root` color override is ignored in dark mode or in a scheme section | Use `createTheme`, or mirror the scheme selectors ([plain CSS](#overriding-in-plain-css)) |\n| My `:root` override is ignored inside a `ThemeProvider` | Themes declare every token; put the override in the theme |\n| A nested theme lost the outer theme's overrides | Themes replace, not stack; spread the outer theme's options into the inner one |\n| The page background doesn't change with the scheme | Import `base.css`, or set `background: var(--greese-color-canvas)` yourself |\n| The saved choice isn't restored | `useColorScheme` and `getSchemeScript` must use the same `storageKey` |\n| Breakpoint changes have no effect on components | Recompile the SCSS with `$breakpoints`; `configureBreakpoints` only affects JS |"},{"name":"Utilities","title":"Utility classes","text":"# Utility classes\n\nSingle-purpose classes for markup, and for anything a greese ui component doesn't\nrender: `<div class=\"display-flex justify-content-between p-4\">`. Each class sets\none property (a few set a small, named group, like `truncate`), and every value\ncomes from the tokens, so themes and dark mode apply to them.\n\nThey are opt-in: `greese.css` doesn't include them. Add the ones you use (see\n[Loading them](#loading-them)).\n\n```html\n<article class=\"p-4 radius-md shadow-md bg-surface\">\n <h2 class=\"font-weight-semibold mb-2\">Plan</h2>\n <p class=\"color-fg-muted line-clamp-2\">\n A long description that stops after two lines…\n </p>\n <div class=\"display-flex justify-content-between align-items-center mt-4\">\n <span class=\"font-weight-bold\">$12</span>\n <button class=\"greese-Button\">Choose</button>\n </div>\n</article>\n```\n\nWith React, they go in `className` on any element or component, alongside the\ncomponent's own classes: `<Card className=\"p-0 md-p-6\">`.\n\n## Names\n\nA class is named for the **property and the value**, the CSS's own words:\n`display-flex`, `text-center`, `flex-dir-col`, `overflow-hidden`,\n`cursor-pointer`.\n\n| Pattern | Examples |\n| ---------------------------- | ------------------------------------------------------------------- |\n| Spacing, with a side | `p-4`, `pt-3`, `mx-auto`, `ms-2`, `gap-x-4` |\n| Tokens, by name | `bg-primary`, `color-fg-muted`, `radius-md`, `shadow-lg`, `z-modal` |\n| A breakpoint, then the class | `md-display-flex`, `lg-p-6`: from that breakpoint up, mobile first |\n| `hover`, then the class | `hover-opacity-75`, `hover-bg-primary`: only where hover exists |\n| Several declarations | `truncate`, `line-clamp-3`, `border`, `transition` |\n\nThe abbreviations are `m` margin, `p` padding, `w` width, `h` height, `z`\nz-index, `bg` background-color, `pos` position, `vis` visibility, `flex-dir`\nflex-direction, `text` for text-align (`text-center`), `upper` and `lower` for\nuppercase and lowercase (`text-transform-upper`), and `col`/`cols` wherever the\nword is column(s): `flex-dir-col`, `grid-template-cols-3`, `grid-col-span-2`. Spacing values are the scale\n(`0`–`8`, and `auto` for margins): `p-4` is `padding: var(--greese-space-4)`.\n\n### Spacing sides\n\n| Suffix | Sets | Follows the writing direction? |\n| ------- | ------------------------------------ | --------------------------------------------------------------------------- |\n| (none) | all sides: `p-4` | |\n| `t` `b` | top, bottom: `pt-4` | no |\n| `l` `r` | left, right: `pl-4` | no |\n| `x` `y` | the inline and block axes: `px-4` | yes |\n| `s` `e` | inline **s**tart and **e**nd: `ps-4` | yes: `ms-2` is the margin on the left in English and on the right in Arabic |\n\nSizing is logical too: `w-*` sets `inline-size` and `h-*` sets `block-size`.\n\n### With the breakpoints\n\n```html\n<!-- a column on phones, a row from md up -->\n<div class=\"display-flex flex-dir-col md-flex-dir-row gap-3 md-gap-6\">…</div>\n\n<!-- hidden on phones, shown from lg -->\n<aside class=\"display-none lg-display-block\">…</aside>\n```\n\nThe breakpoints are the build's (`xs`–`xl`, or your own keys). Only groups where\nit makes sense have them: spacing, width and height, display, position,\noverflow, flex and grid, `text-align`, `order`.\n\n## Loading them\n\nThe whole set is about 2,300 classes (7 kB brotli): `@greese/ui/utilities.css`.\nMost projects want **only the classes their source uses**, and get them one of\nthree ways, all the same code.\n\n```bash\n# A command: scan the files, write the CSS\nnpx greese-utilities --content \"index.html\" --content \"src/**/*.{ts,tsx}\" --out public/utilities.css\n```\n\n```ts\n// Vite: served as a virtual module, refreshed when a scanned file changes\n plugins: [greeseUtilities({ content: ['index.html', 'src/**/*.{ts,tsx}'] })],\n}\n// main.tsx: import 'virtual:greese-utilities.css'\n```\n\n```ts\n// The API\nconst css = purgeUtilities({ content: [html, source], safelist: [/^p-[0-3]$/] })\n```\n\nOr skip purging and import the whole set: `import '@greese/ui/utilities.css'`.\n\n### What counts as used\n\nA class is used when its name appears **anywhere in the content as a whole\nword**: in markup, in a component, in a data file. So `border` in a sentence\nkeeps the `border` class; that is the price of not parsing your code, and a\n`groups` limit narrows it.\n\nA class **built from pieces** (`` `p-${n}` ``) can't be seen. Write the names\nout, or add them to `safelist` (strings or patterns).\n\n### Options\n\n| Option | What |\n| ------------- | ------------------------------------------------------------------------------------------------------------ |\n| `content` | Globs (command, Vite) or source text (API) to scan |\n| `safelist` | Class names or patterns to keep whether or not they're found |\n| `groups` | Only these groups: `spacing`, `sizing`, `layout`, `flex`, `grid`, `typography`, `border`, `color`, `effects` |\n| `prefix` | A prefix for every class (`g` gives `g-p-4`) |\n| `breakpoints` | Breakpoint keys and their widths in px: the build's, when it adds keys |\n\nOn the command: `--content`, `--out`, `--all` (every class, no scan),\n`--safelist`, `--groups a,b`, `--prefix`.\n\n## How they relate to the rest\n\n- They live in `@layer greese.utilities`, the layer style props and the `greese`\n prop use, so they beat a component's own styles without `!important`. Your own\n unlayered CSS still beats them.\n- **Style props** (`<Box p={4}>`, `<Stack gap={{ md: 6 }}>`) and utilities\n overlap on purpose. Props are typed and live inline on React components;\n utilities are plain classes, for markup and for anything greese ui doesn't\n render.\n- Colors are the theme's: `bg-primary` follows a `ThemeProvider` theme\n or `data-greese-theme`, and dark mode, like a component does.\n\n## All the classes\n\n<UtilityClasses />"}],"themes":[{"id":"bevel","description":"Bevel: chamfered corners on two diagonals. Hovered, a control’s cuts slide to the other diagonal; pressed, all four close in. Avatars are squares with every corner cut, status dots diamonds, indicators hexagons, tabs trapezoids, and chat bubbles cut at every corner but their tail’s. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled bevel.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Bevel: chamfered corners on two diagonals. Hovered, a control’s cuts slide to the other diagonal; pressed, all four close in. Avatars are squares with every corner cut, status dots diamonds, indicators hexagons, tabs trapezoids, and chat bubbles cut at every corner but their tail’s.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled bevel.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-none)\",\n field: \"var(--greese-radius-none)\",\n surface: \"var(--greese-radius-none)\",\n panel: \"var(--greese-radius-none)\",\n inset: \"var(--greese-radius-none)\",\n pill: \"var(--greese-radius-none)\",\n round: \"var(--greese-radius-none)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Radio) {\n .greese-Radio-input {\n rotate: 45deg;\n scale: 0.7;\n }\n}\n\n@include greese.component(Slider) {\n &::-webkit-slider-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n\n &::-moz-range-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n}\n\n@include greese.component(Switch) {\n .greese-Switch-track::before {\n position: absolute;\n inset: 0;\n content: '';\n background-color: var(--greese-color-border-strong);\n clip-path: polygon(0 50%, 0.625rem 0, calc(100% - 0.625rem) 0, 100% 50%, calc(100% - 0.625rem) 100%, 0.625rem 100%);\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n .greese-Switch-track:has(.greese-Switch-input:checked)::before {\n background-color: var(--greese-color-primary);\n }\n\n .greese-Switch-input,\n .greese-Switch-input:checked {\n background-color: transparent;\n }\n\n .greese-Switch-thumb {\n rotate: 45deg;\n scale: 0.8;\n }\n}\n\n// Shapes (ADR 0024)\n@property --greese-shape-bleed {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-a {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-b {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-c {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-h {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: '<color>';\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-control::after,\n .greese-shape-bevel-field::after,\n .greese-shape-bevel-container::after,\n .greese-shape-bevel-small::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-control::after,\n .greese-shape-bevel-field::after,\n .greese-shape-bevel-container::after,\n .greese-shape-bevel-small::after {\n display: none;\n }\n }\n .greese-shape-bevel-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-indicator {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-indicator::after {\n display: none;\n }\n }\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-mark::after,\n .greese-shape-bevel-avatar::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n transition: --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-mark::after,\n .greese-shape-bevel-avatar::after {\n display: none;\n }\n }\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-tab::after,\n .greese-shape-bevel-bubble::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n transition: --greese-shape-c var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-tab::after,\n .greese-shape-bevel-bubble::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear,\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n border-color var(--greese-duration-normal) var(--greese-easing-standard),\n translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected='true'] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-c var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-bevel-control,\n .greese-Button {\n --greese-shape-a: 8px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-a: 5.6px;\n --greese-shape-b: 0px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-a: 4px;\n --greese-shape-b: 0px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-a: 4px;\n --greese-shape-b: 0px;\n }\n @media (hover: hover) {\n .greese-shape-bevel-control:hover,\n .greese-Button:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 8px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 5.6px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 4px;\n }\n }\n .greese-shape-bevel-control:active,\n .greese-Button:active {\n --greese-shape-a: 4px;\n --greese-shape-b: 4px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-a: 2.8px;\n --greese-shape-b: 2.8px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-a: 2px;\n --greese-shape-b: 2px;\n }\n .greese-shape-bevel-control:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-a: 6px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - var(--greese-shape-border)), calc(var(--greese-shape-b) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-field:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-a: 16px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-bevel-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 16px;\n }\n }\n .greese-shape-bevel-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-bevel-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-a: 8px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - var(--greese-shape-border)), calc(var(--greese-shape-b) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-bevel-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-h: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-h) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-h) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-h) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-h) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-h)) 0, calc(100% - var(--greese-shape-h)) 0, 100% 50%, calc(100% - var(--greese-shape-h)) 100%, calc(var(--greese-shape-h)) 100%, 0 50%, calc(var(--greese-shape-h)) 0, calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-h) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-h) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-h: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-h: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-mark,\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(50% calc(-1 * 1.147 * var(--greese-shape-bleed)), calc(100% + 2.04 * var(--greese-shape-bleed)) 50%, 50% calc(100% + 1.147 * var(--greese-shape-bleed)), calc(-1 * 2.04 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, 50% 0, 100% 50%, 50% 100%, 0 50%, 50% 0, 50% calc(1.147 * var(--greese-shape-border)), calc(2.04 * var(--greese-shape-border)) 50%, 50% calc(100% - 1.147 * var(--greese-shape-border)), calc(100% - 2.04 * var(--greese-shape-border)) 50%, 50% calc(1.147 * var(--greese-shape-border)));\n }\n .greese-shape-bevel-mark:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-tab,\n .greese-Tab {\n --greese-shape-c: 7px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% 100%, 0 100%, 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-tab:focus-visible {\n --greese-shape-c: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-avatar,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(22% - 0.262 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(78% + 0.262 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(22% - 0.585 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(78% + 0.585 * var(--greese-shape-bleed)), calc(78% + 0.262 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(22% - 0.262 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(78% + 0.585 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(22% - 0.585 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 22% 0, 78% 0, 100% 22%, 100% 78%, 78% 100%, 22% 100%, 0 78%, 0 22%, 22% 0, calc(22% + 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(22% + 0.585 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(78% - 0.585 * var(--greese-shape-border)), calc(22% + 0.262 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(78% - 0.262 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(78% - 0.585 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(22% + 0.585 * var(--greese-shape-border)), calc(78% - 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(22% + 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-avatar:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-bubble,\n .greese-ChatBubble-bubble {\n --greese-shape-c: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% calc(100% - var(--greese-shape-c)), calc(100% - var(--greese-shape-c)) 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-bubble:dir(rtl),\n .greese-ChatBubble-bubble:dir(rtl),\n .greese-ChatBubble--end .greese-ChatBubble-bubble {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(100% + 11px + 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% calc(var(--greese-shape-c)), 100% calc(100% - 11px), calc(100% + 11px) 100%, calc(var(--greese-shape-c)) 100%, 0 calc(100% - var(--greese-shape-c)), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% + 11px - 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)));\n }\n .greese-ChatBubble--end .greese-ChatBubble-bubble:dir(rtl) {\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% calc(100% - var(--greese-shape-c)), calc(100% - var(--greese-shape-c)) 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-bubble:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n}\n","css":"/**\n * Bevel: chamfered corners on two diagonals. Hovered, a control’s cuts slide to the other diagonal; pressed, all four close in. Avatars are squares with every corner cut, status dots diamonds, indicators hexagons, tabs trapezoids, and chat bubbles cut at every corner but their tail’s.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/bevel.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-none);\n --greese-corner-field: var(--greese-radius-none);\n --greese-corner-surface: var(--greese-radius-none);\n --greese-corner-panel: var(--greese-radius-none);\n --greese-corner-inset: var(--greese-radius-none);\n --greese-corner-pill: var(--greese-radius-none);\n --greese-corner-round: var(--greese-radius-none);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Radio .greese-Radio-input {\n rotate: 45deg;\n scale: 0.7;\n }\n}\n@layer greese.overrides {\n .greese-Slider::-webkit-slider-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n .greese-Slider::-moz-range-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n}\n@layer greese.overrides {\n .greese-Switch .greese-Switch-track::before {\n position: absolute;\n inset: 0;\n content: \"\";\n background-color: var(--greese-color-border-strong);\n clip-path: polygon(0 50%, 0.625rem 0, calc(100% - 0.625rem) 0, 100% 50%, calc(100% - 0.625rem) 100%, 0.625rem 100%);\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n .greese-Switch .greese-Switch-track:has(.greese-Switch-input:checked)::before {\n background-color: var(--greese-color-primary);\n }\n .greese-Switch .greese-Switch-input,\n .greese-Switch .greese-Switch-input:checked {\n background-color: transparent;\n }\n .greese-Switch .greese-Switch-thumb {\n rotate: 45deg;\n scale: 0.8;\n }\n}\n@property --greese-shape-bleed {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-a {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-b {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-c {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-h {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: \"<color>\";\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-control::after,\n .greese-shape-bevel-field::after,\n .greese-shape-bevel-container::after,\n .greese-shape-bevel-small::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-control,\n .greese-shape-bevel-field,\n .greese-shape-bevel-container,\n .greese-shape-bevel-small {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-control::after,\n .greese-shape-bevel-field::after,\n .greese-shape-bevel-container::after,\n .greese-shape-bevel-small::after {\n display: none;\n }\n }\n .greese-shape-bevel-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-indicator {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-indicator::after {\n display: none;\n }\n }\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-mark::after,\n .greese-shape-bevel-avatar::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n transition: --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-mark,\n .greese-shape-bevel-avatar {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-mark::after,\n .greese-shape-bevel-avatar::after {\n display: none;\n }\n }\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-bevel-tab::after,\n .greese-shape-bevel-bubble::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n transition: --greese-shape-c var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-bevel-tab,\n .greese-shape-bevel-bubble {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-bevel-tab::after,\n .greese-shape-bevel-bubble::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear, box-shadow var(--greese-duration-normal) var(--greese-easing-standard), border-color var(--greese-duration-normal) var(--greese-easing-standard), translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-a var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-b var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-h var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected=true] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-c var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-bevel-control,\n .greese-Button {\n --greese-shape-a: 8px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-a: 5.6px;\n --greese-shape-b: 0px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-a: 4px;\n --greese-shape-b: 0px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-a: 4px;\n --greese-shape-b: 0px;\n }\n @media (hover: hover) {\n .greese-shape-bevel-control:hover,\n .greese-Button:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 8px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 5.6px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 4px;\n }\n }\n .greese-shape-bevel-control:active,\n .greese-Button:active {\n --greese-shape-a: 4px;\n --greese-shape-b: 4px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-a: 2.8px;\n --greese-shape-b: 2.8px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-a: 2px;\n --greese-shape-b: 2px;\n }\n .greese-shape-bevel-control:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-a: 6px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - var(--greese-shape-border)), calc(var(--greese-shape-b) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-field:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-a: 16px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-bevel-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-a: 0px;\n --greese-shape-b: 16px;\n }\n }\n .greese-shape-bevel-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-bevel-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-a: 8px;\n --greese-shape-b: 0px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-b) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-a) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-b) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-b) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-a) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-a)) 0, calc(100% - var(--greese-shape-b)) 0, 100% calc(var(--greese-shape-b)), 100% calc(100% - var(--greese-shape-a)), calc(100% - var(--greese-shape-a)) 100%, calc(var(--greese-shape-b)) 100%, 0 calc(100% - var(--greese-shape-b)), 0 calc(var(--greese-shape-a)), calc(var(--greese-shape-a)) 0, calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-b) - var(--greese-shape-border)), calc(var(--greese-shape-b) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-a) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-b) + var(--greese-shape-border)), calc(100% - var(--greese-shape-b) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-a) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-a: 0px;\n --greese-shape-b: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-bevel-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-h: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-h) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-h) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-h) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-h) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-h)) 0, calc(100% - var(--greese-shape-h)) 0, 100% 50%, calc(100% - var(--greese-shape-h)) 100%, calc(var(--greese-shape-h)) 100%, 0 50%, calc(var(--greese-shape-h)) 0, calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-h) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-h) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-h) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-h: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-h: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-mark,\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(50% calc(-1 * 1.147 * var(--greese-shape-bleed)), calc(100% + 2.04 * var(--greese-shape-bleed)) 50%, 50% calc(100% + 1.147 * var(--greese-shape-bleed)), calc(-1 * 2.04 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, 50% 0, 100% 50%, 50% 100%, 0 50%, 50% 0, 50% calc(1.147 * var(--greese-shape-border)), calc(2.04 * var(--greese-shape-border)) 50%, 50% calc(100% - 1.147 * var(--greese-shape-border)), calc(100% - 2.04 * var(--greese-shape-border)) 50%, 50% calc(1.147 * var(--greese-shape-border)));\n }\n .greese-shape-bevel-mark:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-tab,\n .greese-Tab {\n --greese-shape-c: 7px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% 100%, 0 100%, 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-tab:focus-visible {\n --greese-shape-c: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-bevel-avatar,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(22% - 0.262 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(78% + 0.262 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(22% - 0.585 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(78% + 0.585 * var(--greese-shape-bleed)), calc(78% + 0.262 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(22% - 0.262 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(78% + 0.585 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(22% - 0.585 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 22% 0, 78% 0, 100% 22%, 100% 78%, 78% 100%, 22% 100%, 0 78%, 0 22%, 22% 0, calc(22% + 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(22% + 0.585 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(78% - 0.585 * var(--greese-shape-border)), calc(22% + 0.262 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(78% - 0.262 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(78% - 0.585 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(22% + 0.585 * var(--greese-shape-border)), calc(78% - 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(22% + 0.262 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-avatar:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-bevel-bubble,\n .greese-ChatBubble-bubble {\n --greese-shape-c: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% calc(100% - var(--greese-shape-c)), calc(100% - var(--greese-shape-c)) 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-bubble:dir(rtl),\n .greese-ChatBubble-bubble:dir(rtl),\n .greese-ChatBubble--end .greese-ChatBubble-bubble {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(100% + 11px + 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% calc(var(--greese-shape-c)), 100% calc(100% - 11px), calc(100% + 11px) 100%, calc(var(--greese-shape-c)) 100%, 0 calc(100% - var(--greese-shape-c)), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% + 11px - 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)));\n }\n .greese-ChatBubble--end .greese-ChatBubble-bubble:dir(rtl) {\n --greese-shape-clip: polygon(calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-c) + 0.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-c) - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-c)) 0, calc(100% - var(--greese-shape-c)) 0, 100% calc(var(--greese-shape-c)), 100% calc(100% - var(--greese-shape-c)), calc(100% - var(--greese-shape-c)) 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 calc(var(--greese-shape-c)), calc(var(--greese-shape-c)) 0, calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-c) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-c) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-bevel-bubble:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n}"},{"id":"candy","description":"Candy: a pink primary with azure, lavender and a yellow accent, on neutrals tinted pink. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled candy.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Candy: a pink primary with azure, lavender and a yellow accent, on neutrals tinted pink.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled candy.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"pink-600\", dark: \"pink-400\"),\n secondary: (light: \"azure-700\", dark: \"azure-400\"),\n tertiary: (light: \"lavender-500\", dark: \"lavender-300\"),\n accent: (light: \"yellow-400\", dark: \"yellow-300\"),\n canvas: (light: \"pink-50\", dark: \"pink-999\"),\n surface: (light: \"pink-100\", dark: \"pink-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"pink-800\"),\n fg: (light: \"pink-999\", dark: \"pink-100\"),\n fg-muted: (light: \"pink-700\", dark: \"pink-300\"),\n border: (light: \"pink-200\", dark: \"pink-800\"),\n border-strong: (light: \"pink-400\", dark: \"pink-700\"),\n track: (light: \"pink-200\", dark: \"pink-600\"),\n ),\n));\n","css":"/**\n * Candy: a pink primary with azure, lavender and a yellow accent, on neutrals tinted pink.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/candy.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #fff3f7;\n --greese-color-surface: #ffe5ee;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #2d0318;\n --greese-color-fg-muted: #9c2661;\n --greese-color-border: #ffcfe0;\n --greese-color-border-strong: #ff81b6;\n --greese-color-track: #ffcfe0;\n --greese-color-primary: #c13b7b;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #00668f;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #9d79f6;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #f4d90b;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #11171c;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #2d0318;\n --greese-color-surface: #581235;\n --greese-color-surface-overlay: #7a1a4a;\n --greese-color-fg: #ffe5ee;\n --greese-color-fg-muted: #ffaecd;\n --greese-color-border: #7a1a4a;\n --greese-color-border-strong: #9c2661;\n --greese-color-track: #c13b7b;\n --greese-color-primary: #ff81b6;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #5ac0f7;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #cdbfff;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #fbe136;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #2d0318;\n --greese-color-surface: #581235;\n --greese-color-surface-overlay: #7a1a4a;\n --greese-color-fg: #ffe5ee;\n --greese-color-fg-muted: #ffaecd;\n --greese-color-border: #7a1a4a;\n --greese-color-border-strong: #9c2661;\n --greese-color-track: #c13b7b;\n --greese-color-primary: #ff81b6;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #5ac0f7;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #cdbfff;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #fbe136;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"depth","description":"Depth: things turn into place in three dimensions. Reveals, panels, table rows and toasts flip up into place, menus swing down from their top edge like a sign and back up, tooltips flip up and back, and dialogs rise out of the page from behind it and sink back in. Pages are the two faces of a panel that turns half over, the whole page at once: one way going forward and the other going back. A greese ui motion theme (ADR 0025): it assigns the motion roles (which built-in effect plays where, and which duration and easing it takes) and paces every entrance. It redefines no effect and no token, and sets no colors and no shapes, so it goes with any of those. Compile it with Sass's package importer, after greese ui's styles, or use the compiled depth.css. Generated from apps/site/src/studio/motions.ts (npm run themes -w site).","scss":"/**\n * Depth: things turn into place in three dimensions. Reveals, panels, table rows and toasts flip up into place, menus swing down from their top edge like a sign and back up, tooltips flip up and back, and dialogs rise out of the page from behind it and sink back in. Pages are the two faces of a panel that turns half over, the whole page at once: one way going forward and the other going back.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled depth.css.\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.motion-defaults((\n duration: \"0.6s\",\n distance: \"1rem\",\n stagger: \"0.06s\",\n theme: \"flip-up\",\n content: \"flip-up\",\n rows: \"flip-up\",\n toast: \"flip-up\",\n dialog: \"depth-in\",\n dialog-exit: \"depth-out\",\n popover: \"swing-in\",\n popover-exit: \"swing-out\",\n tooltip: \"flip-up\",\n tooltip-exit: \"flip-out-up\",\n content-duration: \"slow\",\n rows-duration: \"slow\",\n overlay-duration: \"normal\",\n toast-duration: \"slow\",\n exit-duration: \"normal\",\n enter-ease: \"cubic-bezier(0.2, 0.8, 0.2, 1)\",\n exit-ease: \"exit\",\n page: \"flip-over-right\",\n page-exit: \"flip-over-out-left\",\n page-back: \"flip-over-left\",\n page-back-exit: \"flip-over-out-right\",\n page-mode: \"snapshot\",\n page-duration: \"0.8s\",\n page-ease: \"cubic-bezier(0.65, 0, 0.35, 1)\",\n page-stagger: \"0.06s\",\n));\n","css":"/**\n * Depth: things turn into place in three dimensions. Reveals, panels, table rows and toasts flip up into place, menus swing down from their top edge like a sign and back up, tooltips flip up and back, and dialogs rise out of the page from behind it and sink back in. Pages are the two faces of a panel that turns half over, the whole page at once: one way going forward and the other going back.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/depth.css'\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n :root {\n --greese-motion-duration: 0.6s;\n --greese-motion-distance: 1rem;\n --greese-motion-stagger: 0.06s;\n --greese-motion-theme: greese-flip-up;\n --greese-motion-content: greese-flip-up;\n --greese-motion-rows: greese-flip-up;\n --greese-motion-toast: greese-flip-up;\n --greese-motion-dialog: greese-depth-in;\n --greese-motion-dialog-exit-translate: 0px 0px;\n --greese-motion-dialog-exit-scale: 1;\n --greese-motion-dialog-exit-opacity: 0;\n --greese-motion-dialog-exit-mask-image: none;\n --greese-motion-dialog-exit-transform: perspective(800px) translateZ(-240px);\n --greese-motion-popover: greese-swing-in;\n --greese-motion-popover-exit-translate: 0px 0px;\n --greese-motion-popover-exit-scale: 1;\n --greese-motion-popover-exit-opacity: 0;\n --greese-motion-popover-exit-mask-image: none;\n --greese-motion-popover-exit-transform: perspective(800px) rotateX(-80deg);\n --greese-motion-popover-exit-transform-origin: 50% 0%;\n --greese-motion-tooltip: greese-flip-up;\n --greese-motion-tooltip-exit-translate: 0px 0px;\n --greese-motion-tooltip-exit-scale: 1;\n --greese-motion-tooltip-exit-opacity: 0;\n --greese-motion-tooltip-exit-mask-image: none;\n --greese-motion-tooltip-exit-transform: perspective(800px) rotateX(75deg);\n --greese-motion-content-duration: var(--greese-duration-slow);\n --greese-motion-rows-duration: var(--greese-duration-slow);\n --greese-motion-overlay-duration: var(--greese-duration-normal);\n --greese-motion-toast-duration: var(--greese-duration-slow);\n --greese-motion-exit-duration: var(--greese-duration-normal);\n --greese-motion-enter-ease: cubic-bezier(0.2, 0.8, 0.2, 1);\n --greese-motion-exit-ease: var(--greese-easing-exit);\n --greese-motion-page: greese-flip-over-right;\n --greese-motion-page-exit: greese-flip-over-out-left;\n --greese-motion-page-back: greese-flip-over-left;\n --greese-motion-page-back-exit: greese-flip-over-out-right;\n --greese-motion-page-mode: snapshot;\n --greese-motion-page-duration: 0.8s;\n --greese-motion-page-ease: cubic-bezier(0.65, 0, 0.35, 1);\n --greese-motion-page-stagger: 0.06s;\n }\n}\n@layer greese.utilities {\n @media (prefers-reduced-motion: no-preference) {\n @keyframes greese-flip-up {\n from {\n opacity: 0;\n transform: perspective(800px) rotateX(75deg);\n }\n 50% {\n opacity: 1;\n }\n }\n @keyframes greese-depth-in {\n from {\n opacity: 0;\n transform: perspective(800px) translateZ(-240px);\n }\n 60% {\n opacity: 1;\n }\n }\n @keyframes greese-swing-in {\n from {\n opacity: 0;\n transform: perspective(800px) rotateX(-80deg);\n transform-origin: 50% 0%;\n }\n 50% {\n opacity: 1;\n }\n }\n @keyframes greese-flip-over-right {\n from {\n transform: perspective(2000px) rotateY(-180deg);\n backface-visibility: hidden;\n }\n }\n @keyframes greese-flip-over-out-left {\n from {\n transform: perspective(2000px) rotateY(0deg);\n backface-visibility: hidden;\n }\n to {\n transform: perspective(2000px) rotateY(180deg);\n backface-visibility: hidden;\n }\n }\n @keyframes greese-flip-over-left {\n from {\n transform: perspective(2000px) rotateY(180deg);\n backface-visibility: hidden;\n }\n }\n @keyframes greese-flip-over-out-right {\n from {\n transform: perspective(2000px) rotateY(0deg);\n backface-visibility: hidden;\n }\n to {\n transform: perspective(2000px) rotateY(-180deg);\n backface-visibility: hidden;\n }\n }\n }\n}"},{"id":"extrude","description":"Extrude: solid, like keycaps. Buttons, chips, badges, keys, avatars, collapsible headers and the chosen segment stand out of the page on a thick lower edge and sink into it when pressed; tabs stand up on a thick top edge and the current one is pressed in; cards, tiles and alerts are blocks with a deep lower edge, an alert’s in its tone; fields, code boxes, tracks and the segmented control are pressed into the page, and a progress bar’s fill stands up out of its track. All of it drawn inside each box, so it survives every motion theme’s masks. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled extrude.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Extrude: solid, like keycaps. Buttons, chips, badges, keys, avatars, collapsible headers and the chosen segment stand out of the page on a thick lower edge and sink into it when pressed; tabs stand up on a thick top edge and the current one is pressed in; cards, tiles and alerts are blocks with a deep lower edge, an alert’s in its tone; fields, code boxes, tracks and the segmented control are pressed into the page, and a progress bar’s fill stands up out of its track. All of it drawn inside each box, so it survives every motion theme’s masks.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled extrude.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-md)\",\n field: \"var(--greese-radius-sm)\",\n surface: \"var(--greese-radius-md)\",\n panel: \"var(--greese-radius-md)\",\n inset: \"var(--greese-radius-sm)\",\n pill: \"var(--greese-radius-pill)\",\n round: \"var(--greese-radius-round)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n}\n\n@include greese.component(Alert) {\n box-shadow:\n inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent),\n inset 0 -0.25rem 0 0 color-mix(in oklab, var(--greese-alert-tone) 40%, transparent);\n padding-block-end: calc(var(--greese-space-3) + 0.25rem);\n}\n\n@include greese.component(Avatar) {\n border-radius: var(--greese-radius-md);\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.1875rem) 0 0 color-mix(in oklab, black 24%, transparent);\n}\n\n@include greese.component(Badge) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.125rem) 0 0 color-mix(in oklab, black 24%, transparent);\n}\n\n@include greese.component(Button) {\n &:not(.greese-Button--ghost) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.25rem) 0 0 color-mix(in oklab, black 24%, transparent);\n\n &:active:not(:disabled, [aria-disabled='true']) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.0625rem) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n\n @supports (color: color(from red srgb-linear calc(r * 1) g b / calc(alpha * 1))) {\n --greese-button-edge: color(from var(--greese-button-bg) srgb-linear calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * r * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (r + (1 - r) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * g * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (g + (1 - g) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * b * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (b + (1 - b) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) / calc(0.24 + clamp(0, (alpha - 0.98) * 100, 1) * 0.76));\n\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.25rem) 0 0 var(--greese-button-edge);\n\n &:active:not(:disabled, [aria-disabled='true']) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.0625rem) 0 0 var(--greese-button-edge);\n }\n }\n }\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: translateY(0.1875rem);\n }\n}\n\n@include greese.component(Card) {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.375rem) 0 0 color-mix(in oklab, black 24%, transparent);\n}\n\n@include greese.component(Chip) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.1875rem) 0 0 color-mix(in oklab, black 24%, transparent);\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: translateY(0.125rem);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n\n > .greese-Collapsible-trigger {\n border-color: transparent;\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.25rem) 0 0 color-mix(in oklab, black 24%, transparent);\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n \n &:active:not(:disabled, [aria-disabled='true']) {\n transform: translateY(0.1875rem);\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.0625rem) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n\n@include greese.component(Input) {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n}\n\n@include greese.component(Key) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.1875rem) 0 0 color-mix(in oklab, black 24%, transparent);\n}\n\n@include greese.component(OtpField) {\n .greese-OtpField-slot {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n\n@include greese.component(Progress) {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n\n &::-webkit-progress-value {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * max(1px, var(--greese-progress-height) / 3)) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n\n &::-moz-progress-bar {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * max(1px, var(--greese-progress-height) / 3)) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n\n@include greese.component(Segment) {\n &:has(:checked) {\n box-shadow:\n inset 0 0 0 1.5px var(--greese-segment-current-ring, transparent),\n inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.1875rem) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: translateY(0.125rem);\n }\n}\n\n@include greese.component(SegmentedControl) {\n .greese-SegmentedControl-track {\n padding: 0.25rem;\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n\n@include greese.component(Select) {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n}\n\n@include greese.component(SpeedDial) {\n .greese-SpeedDial-trigger {\n border-radius: var(--greese-radius-lg);\n }\n\n .greese-SpeedDialAction-icon {\n border-radius: var(--greese-radius-md);\n }\n}\n\n@include greese.component(Tab) {\n background-color: var(--greese-color-surface);\n border-radius: var(--greese-corner-control) var(--greese-corner-control) 0 0;\n box-shadow: inset 0 -1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 0.25rem 0 0 color-mix(in oklab, black 22%, transparent);\n padding-block-start: 0.25rem;\n\n &[aria-selected='true'] {\n background-color: var(--greese-tab-current-bg, color-mix(in oklab, var(--greese-color-primary) 12%, var(--greese-color-canvas)));\n box-shadow:\n inset 0 0 0 1.5px var(--greese-tab-current-ring, transparent),\n inset 0 -2px 0 var(--greese-color-primary),\n inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n transform: translateY(0.125rem);\n }\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: translateY(0.125rem);\n }\n}\n\n@include greese.component(Textarea) {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n}\n\n@include greese.component(Tile) {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * 0.375rem) 0 0 color-mix(in oklab, black 24%, transparent);\n}\n","css":"/**\n * Extrude: solid, like keycaps. Buttons, chips, badges, keys, avatars, collapsible headers and the chosen segment stand out of the page on a thick lower edge and sink into it when pressed; tabs stand up on a thick top edge and the current one is pressed in; cards, tiles and alerts are blocks with a deep lower edge, an alert’s in its tone; fields, code boxes, tracks and the segmented control are pressed into the page, and a progress bar’s fill stands up out of its track. All of it drawn inside each box, so it survives every motion theme’s masks.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/extrude.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-md);\n --greese-corner-field: var(--greese-radius-sm);\n --greese-corner-surface: var(--greese-radius-md);\n --greese-corner-panel: var(--greese-radius-md);\n --greese-corner-inset: var(--greese-radius-sm);\n --greese-corner-pill: var(--greese-radius-pill);\n --greese-corner-round: var(--greese-radius-round);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n}\n@layer greese.overrides {\n .greese-Alert {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.25rem 0 0 color-mix(in oklab, var(--greese-alert-tone) 40%, transparent);\n padding-block-end: calc(var(--greese-space-3) + 0.25rem);\n }\n}\n@layer greese.overrides {\n .greese-Avatar {\n border-radius: var(--greese-radius-md);\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.1875rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Badge {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.125rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Button:not(.greese-Button--ghost) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.25rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n .greese-Button:not(.greese-Button--ghost):active:not(:disabled, [aria-disabled=true]) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.0625rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n @supports (color: color(from red srgb-linear calc(r * 1) g b/calc(alpha * 1))) {\n .greese-Button:not(.greese-Button--ghost) {\n --greese-button-edge: color(from var(--greese-button-bg) srgb-linear calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * r * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (r + (1 - r) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * g * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (g + (1 - g) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) calc(clamp(0, (alpha - 0.98) * 100, 1) * (clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1) * b * max(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05)) / max(0.0001, (0.2126 * r + 0.7152 * g + 0.0722 * b)) + (1 - clamp(0, (((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) / 3.1 - 0.05) * 1000000, 1)) * (b + (1 - b) * (min(1, 3.1 * ((0.2126 * r + 0.7152 * g + 0.0722 * b) + 0.05) - 0.05) - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.0001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b))))) / calc(0.24 + clamp(0, (alpha - 0.98) * 100, 1) * 0.76));\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.25rem 0 0 var(--greese-button-edge);\n }\n .greese-Button:not(.greese-Button--ghost):active:not(:disabled, [aria-disabled=true]) {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.0625rem 0 0 var(--greese-button-edge);\n }\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: transform var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n .greese-Button:active:not(:disabled, [aria-disabled=true]) {\n transform: translateY(0.1875rem);\n }\n}\n@layer greese.overrides {\n .greese-Card {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.375rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Chip {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.1875rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: transform var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n .greese-Chip:active:not(:disabled, [aria-disabled=true]) {\n transform: translateY(0.125rem);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n .greese-Collapsible > .greese-Collapsible-trigger {\n border-color: transparent;\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.25rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible > .greese-Collapsible-trigger {\n transition: transform var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n .greese-Collapsible > .greese-Collapsible-trigger:active:not(:disabled, [aria-disabled=true]) {\n transform: translateY(0.1875rem);\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.0625rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Input {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Key {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.1875rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-OtpField .greese-OtpField-slot {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Progress {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n .greese-Progress::-webkit-progress-value {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * max(1px, var(--greese-progress-height) / 3)) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n .greese-Progress::-moz-progress-bar {\n box-shadow: inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 calc(-1 * max(1px, var(--greese-progress-height) / 3)) 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Segment:has(:checked) {\n box-shadow: inset 0 0 0 1.5px var(--greese-segment-current-ring, transparent), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.1875rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: transform var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n .greese-Segment:active:not(:disabled, [aria-disabled=true]) {\n transform: translateY(0.125rem);\n }\n}\n@layer greese.overrides {\n .greese-SegmentedControl .greese-SegmentedControl-track {\n padding: 0.25rem;\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Select {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-SpeedDial .greese-SpeedDial-trigger {\n border-radius: var(--greese-radius-lg);\n }\n .greese-SpeedDial .greese-SpeedDialAction-icon {\n border-radius: var(--greese-radius-md);\n }\n}\n@layer greese.overrides {\n .greese-Tab {\n background-color: var(--greese-color-surface);\n border-radius: var(--greese-corner-control) var(--greese-corner-control) 0 0;\n box-shadow: inset 0 -1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 0.25rem 0 0 color-mix(in oklab, black 22%, transparent);\n padding-block-start: 0.25rem;\n }\n .greese-Tab[aria-selected=true] {\n background-color: var(--greese-tab-current-bg, color-mix(in oklab, var(--greese-color-primary) 12%, var(--greese-color-canvas)));\n box-shadow: inset 0 0 0 1.5px var(--greese-tab-current-ring, transparent), inset 0 -2px 0 var(--greese-color-primary), inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n transform: translateY(0.125rem);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: transform var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n .greese-Tab:active:not(:disabled, [aria-disabled=true]) {\n transform: translateY(0.125rem);\n }\n}\n@layer greese.overrides {\n .greese-Textarea {\n box-shadow: inset 0 0.1875rem 0 0 color-mix(in oklab, var(--greese-color-fg) 10%, transparent);\n }\n}\n@layer greese.overrides {\n .greese-Tile {\n box-shadow: inset 0 0 0 1px var(--greese-color-border), inset 0 1px 0 0 color-mix(in oklab, white 22%, transparent), inset 0 -0.375rem 0 0 color-mix(in oklab, black 24%, transparent);\n }\n}"},{"id":"folio","description":"Folio: paper, with square corners. Containers and fields have a dog-eared corner that folds further when a card is hovered; controls and indicators lean like italic type and straighten when hovered. Status dots have a fold to their size, chat bubbles a dog-ear opposite their tail. Tab panels are folders, and the current tab opens into its folder. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled folio.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Folio: paper, with square corners. Containers and fields have a dog-eared corner that folds further when a card is hovered; controls and indicators lean like italic type and straighten when hovered. Status dots have a fold to their size, chat bubbles a dog-ear opposite their tail. Tab panels are folders, and the current tab opens into its folder.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled folio.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-none)\",\n field: \"var(--greese-radius-none)\",\n surface: \"var(--greese-radius-none)\",\n panel: \"var(--greese-radius-none)\",\n inset: \"var(--greese-radius-none)\",\n pill: \"var(--greese-radius-none)\",\n round: \"var(--greese-radius-none)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Tab) {\n border: 1px solid transparent;\n border-block-end: 0;\n border-radius: 0;\n\n &[aria-selected='true'] {\n background-color: var(--greese-color-canvas);\n border-color: var(--greese-color-border);\n box-shadow: none;\n }\n}\n\n@include greese.component(TabList) {\n border-block-end: 0;\n box-shadow: inset 0 -1px 0 var(--greese-color-border);\n}\n\n@include greese.component(Tabs) {\n gap: 0;\n\n > .greese-TabPanel {\n padding: var(--greese-space-4);\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-color-border);\n border-block-start: 0;\n }\n}\n\n// Shapes (ADR 0024)\n@property --greese-shape-bleed {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-f {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-s {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: '<color>';\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-folio-control::after,\n .greese-shape-folio-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-folio-control::after,\n .greese-shape-folio-indicator::after {\n display: none;\n }\n }\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-folio-field::after,\n .greese-shape-folio-container::after,\n .greese-shape-folio-small::after,\n .greese-shape-folio-mark::after,\n .greese-shape-folio-dot::after,\n .greese-shape-folio-bubble::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-folio-field::after,\n .greese-shape-folio-container::after,\n .greese-shape-folio-small::after,\n .greese-shape-folio-mark::after,\n .greese-shape-folio-dot::after,\n .greese-shape-folio-bubble::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear,\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n border-color var(--greese-duration-normal) var(--greese-easing-standard),\n translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-folio-control,\n .greese-Button {\n --greese-shape-s: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-s) - 0.967 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.034 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.967 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.034 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-s)) 0, 100% 0, calc(100% - var(--greese-shape-s)) 100%, 0 100%, calc(var(--greese-shape-s)) 0, calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.967 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.034 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-control:dir(rtl),\n .greese-Button:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.034 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-s) - 0.967 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.034 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.967 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-s)) 100%, 0 0, calc(100% - var(--greese-shape-s)) 0, 100% 100%, calc(100% - 1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.034 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-s: 4.2px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-s: 3px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-s: 3px;\n }\n @media (hover: hover) {\n .greese-shape-folio-control:hover,\n .greese-Button:hover {\n --greese-shape-s: 2px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-s: 1.4px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-s: 1px;\n }\n }\n .greese-shape-folio-control:active,\n .greese-Button:active {\n --greese-shape-s: 0px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-s: 0px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-s: 0px;\n }\n .greese-shape-folio-control:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-f: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-field:dir(rtl),\n .greese-Input:dir(rtl),\n .greese-OtpField-slot:dir(rtl),\n .greese-Select:dir(rtl),\n .greese-Textarea:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-folio-field:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-f: 18px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-container:dir(rtl),\n .greese-AccordionItem > .greese-Collapsible-content:dir(rtl),\n .greese-Card:dir(rtl),\n .greese-Dialog:dir(rtl),\n .greese-Menu:dir(rtl),\n .greese-Popover:dir(rtl),\n .greese-Tile:dir(rtl),\n .greese-Toast:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-folio-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-f: 28px;\n }\n }\n .greese-shape-folio-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-f: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-small:dir(rtl),\n .greese-Alert:dir(rtl),\n .greese-Collapsible-trigger:dir(rtl),\n .greese-Tooltip:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-s: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-s) - 0.978 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.022 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.978 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.022 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-s)) 0, 100% 0, calc(100% - var(--greese-shape-s)) 100%, 0 100%, calc(var(--greese-shape-s)) 0, calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.978 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.022 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-indicator:dir(rtl),\n .greese-Badge:dir(rtl),\n .greese-Chip:dir(rtl),\n .greese-Segment:dir(rtl),\n .greese-SegmentedControl-track:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.022 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-s) - 0.978 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.022 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.978 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-s)) 100%, 0 0, calc(100% - var(--greese-shape-s)) 0, 100% 100%, calc(100% - 1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.022 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-folio-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar) {\n --greese-shape-f: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-mark:dir(rtl),\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-mark:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-dot,\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-f: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-dot:dir(rtl),\n .greese-Status:not(.greese-Status--pulse):dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-dot:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Status:not(.greese-Status--pulse):focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-bubble,\n .greese-ChatBubble-bubble {\n --greese-shape-f: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-bubble:dir(rtl),\n .greese-ChatBubble-bubble:dir(rtl),\n .greese-ChatBubble--end .greese-ChatBubble-bubble {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(100% + 11px + 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% calc(100% - 11px), calc(100% + 11px) 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% calc(100% - 11px), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% + 11px - 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)));\n }\n .greese-ChatBubble--end .greese-ChatBubble-bubble:dir(rtl) {\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-bubble:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n}\n","css":"/**\n * Folio: paper, with square corners. Containers and fields have a dog-eared corner that folds further when a card is hovered; controls and indicators lean like italic type and straighten when hovered. Status dots have a fold to their size, chat bubbles a dog-ear opposite their tail. Tab panels are folders, and the current tab opens into its folder.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/folio.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-none);\n --greese-corner-field: var(--greese-radius-none);\n --greese-corner-surface: var(--greese-radius-none);\n --greese-corner-panel: var(--greese-radius-none);\n --greese-corner-inset: var(--greese-radius-none);\n --greese-corner-pill: var(--greese-radius-none);\n --greese-corner-round: var(--greese-radius-none);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Tab {\n border: 1px solid transparent;\n border-block-end: 0;\n border-radius: 0;\n }\n .greese-Tab[aria-selected=true] {\n background-color: var(--greese-color-canvas);\n border-color: var(--greese-color-border);\n box-shadow: none;\n }\n}\n@layer greese.overrides {\n .greese-TabList {\n border-block-end: 0;\n box-shadow: inset 0 -1px 0 var(--greese-color-border);\n }\n}\n@layer greese.overrides {\n .greese-Tabs {\n gap: 0;\n }\n .greese-Tabs > .greese-TabPanel {\n padding: var(--greese-space-4);\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-color-border);\n border-block-start: 0;\n }\n}\n@property --greese-shape-bleed {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-f {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-s {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: \"<color>\";\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-folio-control::after,\n .greese-shape-folio-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-folio-control,\n .greese-shape-folio-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-folio-control::after,\n .greese-shape-folio-indicator::after {\n display: none;\n }\n }\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-folio-field::after,\n .greese-shape-folio-container::after,\n .greese-shape-folio-small::after,\n .greese-shape-folio-mark::after,\n .greese-shape-folio-dot::after,\n .greese-shape-folio-bubble::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-folio-field,\n .greese-shape-folio-container,\n .greese-shape-folio-small,\n .greese-shape-folio-mark,\n .greese-shape-folio-dot,\n .greese-shape-folio-bubble {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-folio-field::after,\n .greese-shape-folio-container::after,\n .greese-shape-folio-small::after,\n .greese-shape-folio-mark::after,\n .greese-shape-folio-dot::after,\n .greese-shape-folio-bubble::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-ChatBubble-bubble,\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear, box-shadow var(--greese-duration-normal) var(--greese-easing-standard), border-color var(--greese-duration-normal) var(--greese-easing-standard), translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-f var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-s var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-folio-control,\n .greese-Button {\n --greese-shape-s: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-s) - 0.967 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.034 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.967 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.034 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-s)) 0, 100% 0, calc(100% - var(--greese-shape-s)) 100%, 0 100%, calc(var(--greese-shape-s)) 0, calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.967 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.034 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-control:dir(rtl),\n .greese-Button:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.034 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-s) - 0.967 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.034 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.967 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-s)) 100%, 0 0, calc(100% - var(--greese-shape-s)) 0, 100% 100%, calc(100% - 1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.967 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.034 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.967 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.034 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-s: 4.2px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-s: 3px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-s: 3px;\n }\n @media (hover: hover) {\n .greese-shape-folio-control:hover,\n .greese-Button:hover {\n --greese-shape-s: 2px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-s: 1.4px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-s: 1px;\n }\n }\n .greese-shape-folio-control:active,\n .greese-Button:active {\n --greese-shape-s: 0px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-s: 0px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-s: 0px;\n }\n .greese-shape-folio-control:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-f: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-field:dir(rtl),\n .greese-Input:dir(rtl),\n .greese-OtpField-slot:dir(rtl),\n .greese-Select:dir(rtl),\n .greese-Textarea:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-folio-field:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-f: 18px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-container:dir(rtl),\n .greese-AccordionItem > .greese-Collapsible-content:dir(rtl),\n .greese-Card:dir(rtl),\n .greese-Dialog:dir(rtl),\n .greese-Menu:dir(rtl),\n .greese-Popover:dir(rtl),\n .greese-Tile:dir(rtl),\n .greese-Toast:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-folio-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-f: 28px;\n }\n }\n .greese-shape-folio-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-f: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-small:dir(rtl),\n .greese-Alert:dir(rtl),\n .greese-Collapsible-trigger:dir(rtl),\n .greese-Tooltip:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-s: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-s) - 0.978 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.022 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.978 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.022 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-s)) 0, 100% 0, calc(100% - var(--greese-shape-s)) 100%, 0 100%, calc(var(--greese-shape-s)) 0, calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.978 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.022 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-indicator:dir(rtl),\n .greese-Badge:dir(rtl),\n .greese-Chip:dir(rtl),\n .greese-Segment:dir(rtl),\n .greese-SegmentedControl-track:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.022 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-s) - 0.978 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.022 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-s) + 0.978 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-s)) 100%, 0 0, calc(100% - var(--greese-shape-s)) 0, 100% 100%, calc(100% - 1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-s) - 0.978 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.022 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-s) + 0.978 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.022 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-folio-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-s: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-folio-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar) {\n --greese-shape-f: 8px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-mark:dir(rtl),\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-mark:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-dot,\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-f: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-dot:dir(rtl),\n .greese-Status:not(.greese-Status--pulse):dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-shape-folio-dot:focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Status:not(.greese-Status--pulse):focus-visible {\n --greese-shape-f: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-folio-bubble,\n .greese-ChatBubble-bubble {\n --greese-shape-f: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-bubble:dir(rtl),\n .greese-ChatBubble-bubble:dir(rtl),\n .greese-ChatBubble--end .greese-ChatBubble-bubble {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)), calc(100% + 11px + 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% calc(100% - 11px), calc(100% + 11px) 100%, 0 100%, 0 calc(var(--greese-shape-f)), calc(var(--greese-shape-f)) 0, 100% 0, 100% calc(100% - 11px), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% + 11px - 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)));\n }\n .greese-ChatBubble--end .greese-ChatBubble-bubble:dir(rtl) {\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-f) + 0.414 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-f) - 0.414 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 11px - 2.414 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - 11px - 0.414 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-f)) 0, 100% calc(var(--greese-shape-f)), 100% 100%, calc(-1 * 11px) 100%, 0 calc(100% - 11px), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - 11px + 0.414 * var(--greese-shape-border)), calc(-1 * 11px + 2.414 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-f) + 0.414 * var(--greese-shape-border)), calc(100% - var(--greese-shape-f) - 0.414 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-folio-bubble:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n}"},{"id":"forest","description":"Forest: a jade primary with lime, aqua and an orange accent, on neutrals tinted jade. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled forest.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Forest: a jade primary with lime, aqua and an orange accent, on neutrals tinted jade.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled forest.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"jade-700\", dark: \"jade-400\"),\n secondary: (light: \"lime-700\", dark: \"lime-400\"),\n tertiary: (light: \"aqua-700\", dark: \"aqua-400\"),\n accent: (light: \"orange-600\", dark: \"orange-400\"),\n canvas: (light: \"jade-50\", dark: \"jade-999\"),\n surface: (light: \"jade-100\", dark: \"jade-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"jade-800\"),\n fg: (light: \"jade-999\", dark: \"jade-100\"),\n fg-muted: (light: \"jade-700\", dark: \"jade-300\"),\n border: (light: \"jade-200\", dark: \"jade-800\"),\n border-strong: (light: \"jade-400\", dark: \"jade-700\"),\n track: (light: \"jade-200\", dark: \"jade-600\"),\n ),\n));\n","css":"/**\n * Forest: a jade primary with lime, aqua and an orange accent, on neutrals tinted jade.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/forest.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #eefaf4;\n --greese-color-surface: #daf4e8;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #001c11;\n --greese-color-fg-muted: #006f51;\n --greese-color-border: #baedd6;\n --greese-color-border-strong: #54cea1;\n --greese-color-track: #baedd6;\n --greese-color-primary: #006f51;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #517600;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #00707b;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #ffffff;\n --greese-color-accent: #c05d00;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #000000;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #001c11;\n --greese-color-surface: #003c2a;\n --greese-color-surface-overlay: #00553d;\n --greese-color-fg: #daf4e8;\n --greese-color-fg-muted: #8ee1be;\n --greese-color-border: #00553d;\n --greese-color-border-strong: #006f51;\n --greese-color-track: #008e68;\n --greese-color-primary: #54cea1;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #a6dc51;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #64d0de;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ff9d5e;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #001c11;\n --greese-color-surface: #003c2a;\n --greese-color-surface-overlay: #00553d;\n --greese-color-fg: #daf4e8;\n --greese-color-fg-muted: #8ee1be;\n --greese-color-border: #00553d;\n --greese-color-border-strong: #006f51;\n --greese-color-track: #008e68;\n --greese-color-primary: #54cea1;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #a6dc51;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #64d0de;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ff9d5e;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"gentle","description":"Gentle: unhurried and soft. Long durations that ease out and a wide stagger; things come into focus out of a blur, and overlays sink away. Pages change softly: the old one fades away while the new one comes into focus. A greese ui motion theme (ADR 0025): it assigns the motion roles (which built-in effect plays where, and which duration and easing it takes) and paces every entrance. It redefines no effect and no token, and sets no colors and no shapes, so it goes with any of those. Compile it with Sass's package importer, after greese ui's styles, or use the compiled gentle.css. Generated from apps/site/src/studio/motions.ts (npm run themes -w site).","scss":"/**\n * Gentle: unhurried and soft. Long durations that ease out and a wide stagger; things come into focus out of a blur, and overlays sink away. Pages change softly: the old one fades away while the new one comes into focus.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled gentle.css.\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.motion-defaults((\n duration: \"0.8s\",\n distance: \"1.5rem\",\n stagger: \"0.09s\",\n theme: \"blur-in\",\n content: \"blur-in\",\n rows: \"fade-up\",\n toast: \"fade-up\",\n overlay: \"blur-in\",\n overlay-exit: \"fade-out-down\",\n content-duration: \"slow\",\n rows-duration: \"slow\",\n overlay-duration: \"slow\",\n toast-duration: \"slow\",\n exit-duration: \"normal\",\n enter-ease: \"cubic-bezier(0.16, 1, 0.3, 1)\",\n exit-ease: \"cubic-bezier(0.7, 0, 0.84, 0)\",\n page: \"blur-in\",\n page-exit: \"fade-out\",\n page-duration: \"0.7s\",\n page-ease: \"cubic-bezier(0.16, 1, 0.3, 1)\",\n page-stagger: \"0.09s\",\n));\n","css":"/**\n * Gentle: unhurried and soft. Long durations that ease out and a wide stagger; things come into focus out of a blur, and overlays sink away. Pages change softly: the old one fades away while the new one comes into focus.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/gentle.css'\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n :root {\n --greese-motion-duration: 0.8s;\n --greese-motion-distance: 1.5rem;\n --greese-motion-stagger: 0.09s;\n --greese-motion-theme: greese-blur-in;\n --greese-motion-content: greese-blur-in;\n --greese-motion-rows: greese-fade-up;\n --greese-motion-toast: greese-fade-up;\n --greese-motion-overlay: greese-blur-in;\n --greese-motion-overlay-exit-translate: 0px var(--greese-motion-distance, 1rem);\n --greese-motion-overlay-exit-scale: 1;\n --greese-motion-overlay-exit-opacity: 0;\n --greese-motion-overlay-exit-mask-image: none;\n --greese-motion-overlay-exit-transform: none;\n --greese-motion-content-duration: var(--greese-duration-slow);\n --greese-motion-rows-duration: var(--greese-duration-slow);\n --greese-motion-overlay-duration: var(--greese-duration-slow);\n --greese-motion-toast-duration: var(--greese-duration-slow);\n --greese-motion-exit-duration: var(--greese-duration-normal);\n --greese-motion-enter-ease: cubic-bezier(0.16, 1, 0.3, 1);\n --greese-motion-exit-ease: cubic-bezier(0.7, 0, 0.84, 0);\n --greese-motion-page: greese-blur-in;\n --greese-motion-page-exit: greese-fade-out;\n --greese-motion-page-duration: 0.7s;\n --greese-motion-page-ease: cubic-bezier(0.16, 1, 0.3, 1);\n --greese-motion-page-stagger: 0.09s;\n }\n}\n@layer greese.utilities {\n @media (prefers-reduced-motion: no-preference) {\n @keyframes greese-blur-in {\n from {\n filter: blur(8px);\n }\n }\n @keyframes greese-fade-up {\n from {\n translate: 0px var(--greese-motion-distance, 1rem);\n opacity: 0;\n }\n }\n @keyframes greese-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n }\n }\n}"},{"id":"grape","description":"Grape: a lavender primary with magenta, royal blue and a jade accent, on neutrals tinted lavender. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled grape.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Grape: a lavender primary with magenta, royal blue and a jade accent, on neutrals tinted lavender.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled grape.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"lavender-600\", dark: \"lavender-400\"),\n secondary: (light: \"magenta-600\", dark: \"magenta-400\"),\n tertiary: (light: \"royal-600\", dark: \"royal-400\"),\n accent: (light: \"jade-600\", dark: \"jade-400\"),\n canvas: (light: \"lavender-50\", dark: \"lavender-999\"),\n surface: (light: \"lavender-100\", dark: \"lavender-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"lavender-800\"),\n fg: (light: \"lavender-999\", dark: \"lavender-100\"),\n fg-muted: (light: \"lavender-700\", dark: \"lavender-300\"),\n border: (light: \"lavender-200\", dark: \"lavender-800\"),\n border-strong: (light: \"lavender-400\", dark: \"lavender-700\"),\n track: (light: \"lavender-200\", dark: \"lavender-600\"),\n ),\n));\n","css":"/**\n * Grape: a lavender primary with magenta, royal blue and a jade accent, on neutrals tinted lavender.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/grape.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #f7f5ff;\n --greese-color-surface: #edeaff;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #190c33;\n --greese-color-fg-muted: #6443ab;\n --greese-color-border: #dfd8ff;\n --greese-color-border-strong: #b69fff;\n --greese-color-track: #dfd8ff;\n --greese-color-primary: #7e5bd0;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #bb32a3;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #5963e5;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #ffffff;\n --greese-color-accent: #008e68;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #000000;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #190c33;\n --greese-color-surface: #362361;\n --greese-color-surface-overlay: #4c3285;\n --greese-color-fg: #edeaff;\n --greese-color-fg-muted: #cdbfff;\n --greese-color-border: #4c3285;\n --greese-color-border-strong: #6443ab;\n --greese-color-track: #7e5bd0;\n --greese-color-primary: #b69fff;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #f97cde;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #9aaaff;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #54cea1;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #190c33;\n --greese-color-surface: #362361;\n --greese-color-surface-overlay: #4c3285;\n --greese-color-fg: #edeaff;\n --greese-color-fg-muted: #cdbfff;\n --greese-color-border: #4c3285;\n --greese-color-border-strong: #6443ab;\n --greese-color-track: #7e5bd0;\n --greese-color-primary: #b69fff;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #f97cde;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #9aaaff;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #54cea1;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"greese","description":"Greese: the official theme. A warm orange primary on greese ui's own neutrals. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled greese.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Greese: the official theme. A warm orange primary on greese ui's own neutrals.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled greese.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"orange-700\", dark: \"orange-400\"),\n ),\n));\n","css":"/**\n * Greese: the official theme. A warm orange primary on greese ui's own neutrals.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/greese.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-primary: #964700;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-primary: #ff9d5e;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-primary: #ff9d5e;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n }\n}"},{"id":"mono","description":"Mono: near-black (near-white in dark mode) and grays, with taupe and a single red accent, on gray neutrals. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled mono.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Mono: near-black (near-white in dark mode) and grays, with taupe and a single red accent, on gray neutrals.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled mono.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"silver-900\", dark: \"silver-100\"),\n secondary: (light: \"silver-600\", dark: \"silver-400\"),\n tertiary: (light: \"taupe-700\", dark: \"taupe-300\"),\n accent: (light: \"red-600\", dark: \"red-400\"),\n canvas: (light: \"gray-50\", dark: \"gray-999\"),\n surface: (light: \"gray-100\", dark: \"gray-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"gray-800\"),\n fg: (light: \"gray-999\", dark: \"gray-100\"),\n fg-muted: (light: \"gray-700\", dark: \"gray-300\"),\n border: (light: \"gray-200\", dark: \"gray-800\"),\n border-strong: (light: \"gray-400\", dark: \"gray-700\"),\n track: (light: \"gray-200\", dark: \"gray-600\"),\n ),\n));\n","css":"/**\n * Mono: near-black (near-white in dark mode) and grays, with taupe and a single red accent, on gray neutrals.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/mono.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #f7f7f7;\n --greese-color-surface: #ededed;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #161616;\n --greese-color-fg-muted: #5c5c5c;\n --greese-color-border: #dedede;\n --greese-color-border-strong: #b1b1b1;\n --greese-color-track: #dedede;\n --greese-color-primary: #2e3335;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #6f777c;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #67594f;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #ffffff;\n --greese-color-accent: #d52727;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #ffffff;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #161616;\n --greese-color-surface: #323232;\n --greese-color-surface-overlay: #464646;\n --greese-color-fg: #ededed;\n --greese-color-fg-muted: #cacaca;\n --greese-color-border: #464646;\n --greese-color-border-strong: #5c5c5c;\n --greese-color-track: #767676;\n --greese-color-primary: #ebedee;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #aab3b7;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #d3c7be;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ff8b7f;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #161616;\n --greese-color-surface: #323232;\n --greese-color-surface-overlay: #464646;\n --greese-color-fg: #ededed;\n --greese-color-fg-muted: #cacaca;\n --greese-color-border: #464646;\n --greese-color-border-strong: #5c5c5c;\n --greese-color-track: #767676;\n --greese-color-primary: #ebedee;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #aab3b7;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #d3c7be;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ff8b7f;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"ocean","description":"Ocean: a deep azure primary with royal blue, turquoise and a gold accent, on neutrals tinted azure. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled ocean.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Ocean: a deep azure primary with royal blue, turquoise and a gold accent, on neutrals tinted azure.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled ocean.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"azure-700\", dark: \"azure-400\"),\n secondary: (light: \"royal-600\", dark: \"royal-400\"),\n tertiary: (light: \"turquoise-700\", dark: \"turquoise-400\"),\n accent: (light: \"gold-500\", dark: \"gold-300\"),\n canvas: (light: \"azure-50\", dark: \"azure-999\"),\n surface: (light: \"azure-100\", dark: \"azure-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"azure-800\"),\n fg: (light: \"azure-999\", dark: \"azure-100\"),\n fg-muted: (light: \"azure-700\", dark: \"azure-300\"),\n border: (light: \"azure-200\", dark: \"azure-800\"),\n border-strong: (light: \"azure-400\", dark: \"azure-700\"),\n track: (light: \"azure-200\", dark: \"azure-600\"),\n ),\n));\n","css":"/**\n * Ocean: a deep azure primary with royal blue, turquoise and a gold accent, on neutrals tinted azure.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/ocean.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #eef9ff;\n --greese-color-surface: #daf1ff;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #001927;\n --greese-color-fg-muted: #00668f;\n --greese-color-border: #bde6ff;\n --greese-color-border-strong: #5ac0f7;\n --greese-color-track: #bde6ff;\n --greese-color-primary: #00668f;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #5963e5;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #007069;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #ffffff;\n --greese-color-accent: #df9c00;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #11171c;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #001927;\n --greese-color-surface: #003750;\n --greese-color-surface-overlay: #004d6e;\n --greese-color-fg: #daf1ff;\n --greese-color-fg-muted: #91d6ff;\n --greese-color-border: #004d6e;\n --greese-color-border-strong: #00668f;\n --greese-color-track: #0082b6;\n --greese-color-primary: #5ac0f7;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #9aaaff;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #5dcec5;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ffd593;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #001927;\n --greese-color-surface: #003750;\n --greese-color-surface-overlay: #004d6e;\n --greese-color-fg: #daf1ff;\n --greese-color-fg-muted: #91d6ff;\n --greese-color-border: #004d6e;\n --greese-color-border-strong: #00668f;\n --greese-color-track: #0082b6;\n --greese-color-primary: #5ac0f7;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #9aaaff;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #5dcec5;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #ffd593;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"outline","description":"Outline: drawn rather than filled. Solid and soft buttons and badges, soft alerts, filled and elevated cards and tiles, avatars, the current tab and segment, toasts and tooltips are outlined in their color, with text to match over a faint or neutral fill; what was outlined is filled instead. A greese ui color variant (ADR 0025): how any color theme's colors are worn, reassigned per component variant in @layer greese.overrides. It sets no color tokens, shapes or motion, so it goes with any color, shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled outline.css. Generated from apps/site/src/studio/variants.ts (npm run themes -w site).","scss":"/**\n * Outline: drawn rather than filled. Solid and soft buttons and badges, soft alerts, filled and elevated cards and tiles, avatars, the current tab and segment, toasts and tooltips are outlined in their color, with text to match over a faint or neutral fill; what was outlined is filled instead.\n *\n * A greese ui color variant (ADR 0025): how any color theme's colors are worn,\n * reassigned per component variant in @layer greese.overrides. It sets no\n * color tokens, shapes or motion, so it goes with any color, shape or motion\n * theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled outline.css.\n *\n * Generated from apps/site/src/studio/variants.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.component(Alert) {\n @include greese.modifier(soft) {\n background-color: var(--greese-color-canvas);\n border-color: var(--greese-alert-tone);\n }\n @include greese.modifier(outline) {\n background-color: color-mix(in oklab, var(--greese-alert-tone) 14%, transparent);\n border-color: transparent;\n }\n}\n\n@include greese.component(Avatar) {\n background-color: transparent;\n outline: 1.5px solid color-mix(in oklab, currentcolor 70%, transparent);\n outline-offset: -1.5px;\n}\n\n@include greese.component(Badge) {\n @include greese.modifier(solid) {\n color: var(--greese-badge-tone);\n background-color: color-mix(in oklab, var(--greese-badge-tone) 8%, var(--greese-badge-surface));\n border-color: var(--greese-badge-tone);\n }\n @include greese.modifier(soft) {\n background-color: var(--greese-badge-surface);\n border-color: color-mix(in oklab, var(--greese-badge-tone) 55%, var(--greese-badge-surface));\n }\n @include greese.modifier(outline) {\n color: var(--greese-badge-tone-on);\n background-color: var(--greese-badge-tone);\n border-color: var(--greese-badge-tone);\n }\n}\n\n@include greese.component(Button) {\n @include greese.modifier(solid) {\n --greese-button-fg: var(--greese-button-tone);\n --greese-button-bg: color-mix(in oklab, var(--greese-button-tone) 6%, transparent);\n --greese-button-border: var(--greese-button-tone);\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone) 14%, transparent);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone) 22%, transparent);\n }\n @include greese.modifier(soft) {\n --greese-button-fg: var(--greese-button-tone);\n --greese-button-bg: transparent;\n --greese-button-border: color-mix(in oklab, var(--greese-button-tone) 45%, transparent);\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone) 14%, transparent);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone) 22%, transparent);\n }\n @include greese.modifier(outline) {\n --greese-button-fg: var(--greese-button-on-tone);\n --greese-button-bg: var(--greese-button-tone);\n --greese-button-border: transparent;\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone), var(--greese-button-on-tone) 14%);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone), var(--greese-button-on-tone) 24%);\n }\n}\n\n@include greese.component(Card) {\n @include greese.modifier(filled) {\n background-color: transparent;\n border: 1px solid var(--greese-color-border-strong);\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @include greese.modifier(elevated) {\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-color-border-strong);\n box-shadow: none;\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @include greese.modifier(outline) {\n background-color: color-mix(in oklab, var(--greese-color-border) 65%, var(--greese-color-surface));\n border-color: transparent;\n --greese-shape-ring: transparent;\n }\n}\n\n@include greese.component(Segment) {\n --greese-segment-current-bg: transparent;\n --greese-segment-current-edge: inset 0 0 0 1.5px var(--greese-color-primary);\n --greese-segment-current-ring: var(--greese-color-primary);\n}\n\n@include greese.component(Tab) {\n --greese-tab-current-bg: transparent;\n --greese-tab-current-edge: inset 0 0 0 1.5px var(--greese-color-primary);\n --greese-tab-current-ring: var(--greese-color-primary);\n}\n\n@include greese.component(Tile) {\n background-color: color-mix(in oklab, var(--greese-color-border) 65%, var(--greese-color-surface));\n border-color: transparent;\n @include greese.modifier(filled) {\n background-color: transparent;\n border-color: var(--greese-color-border-strong);\n }\n}\n\n@include greese.component(Toast) {\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-toast-tone);\n border-inline-start-width: 3px;\n}\n\n@include greese.component(Tooltip) {\n color: var(--greese-color-fg);\n background-color: var(--greese-color-surface-overlay);\n border: 1px solid var(--greese-color-fg);\n --greese-tooltip-border: var(--greese-color-fg);\n}\n","css":"/**\n * Outline: drawn rather than filled. Solid and soft buttons and badges, soft alerts, filled and elevated cards and tiles, avatars, the current tab and segment, toasts and tooltips are outlined in their color, with text to match over a faint or neutral fill; what was outlined is filled instead.\n *\n * A greese ui color variant (ADR 0025): how any color theme's colors are worn,\n * reassigned per component variant in @layer greese.overrides. It sets no\n * color tokens, shapes or motion, so it goes with any color, shape or motion\n * theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/outline.css'\n *\n * Generated from apps/site/src/studio/variants.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-Alert.greese-Alert--soft {\n background-color: var(--greese-color-canvas);\n border-color: var(--greese-alert-tone);\n }\n .greese-Alert.greese-Alert--outline {\n background-color: color-mix(in oklab, var(--greese-alert-tone) 14%, transparent);\n border-color: transparent;\n }\n}\n@layer greese.overrides {\n .greese-Avatar {\n background-color: transparent;\n outline: 1.5px solid color-mix(in oklab, currentcolor 70%, transparent);\n outline-offset: -1.5px;\n }\n}\n@layer greese.overrides {\n .greese-Badge.greese-Badge--solid {\n color: var(--greese-badge-tone);\n background-color: color-mix(in oklab, var(--greese-badge-tone) 8%, var(--greese-badge-surface));\n border-color: var(--greese-badge-tone);\n }\n .greese-Badge.greese-Badge--soft {\n background-color: var(--greese-badge-surface);\n border-color: color-mix(in oklab, var(--greese-badge-tone) 55%, var(--greese-badge-surface));\n }\n .greese-Badge.greese-Badge--outline {\n color: var(--greese-badge-tone-on);\n background-color: var(--greese-badge-tone);\n border-color: var(--greese-badge-tone);\n }\n}\n@layer greese.overrides {\n .greese-Button.greese-Button--solid {\n --greese-button-fg: var(--greese-button-tone);\n --greese-button-bg: color-mix(in oklab, var(--greese-button-tone) 6%, transparent);\n --greese-button-border: var(--greese-button-tone);\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone) 14%, transparent);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone) 22%, transparent);\n }\n .greese-Button.greese-Button--soft {\n --greese-button-fg: var(--greese-button-tone);\n --greese-button-bg: transparent;\n --greese-button-border: color-mix(in oklab, var(--greese-button-tone) 45%, transparent);\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone) 14%, transparent);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone) 22%, transparent);\n }\n .greese-Button.greese-Button--outline {\n --greese-button-fg: var(--greese-button-on-tone);\n --greese-button-bg: var(--greese-button-tone);\n --greese-button-border: transparent;\n --greese-button-bg-hover: color-mix(in oklab, var(--greese-button-tone), var(--greese-button-on-tone) 14%);\n --greese-button-bg-active: color-mix(in oklab, var(--greese-button-tone), var(--greese-button-on-tone) 24%);\n }\n}\n@layer greese.overrides {\n .greese-Card.greese-Card--filled {\n background-color: transparent;\n border: 1px solid var(--greese-color-border-strong);\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n .greese-Card.greese-Card--elevated {\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-color-border-strong);\n box-shadow: none;\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n .greese-Card.greese-Card--outline {\n background-color: color-mix(in oklab, var(--greese-color-border) 65%, var(--greese-color-surface));\n border-color: transparent;\n --greese-shape-ring: transparent;\n }\n}\n@layer greese.overrides {\n .greese-Segment {\n --greese-segment-current-bg: transparent;\n --greese-segment-current-edge: inset 0 0 0 1.5px var(--greese-color-primary);\n --greese-segment-current-ring: var(--greese-color-primary);\n }\n}\n@layer greese.overrides {\n .greese-Tab {\n --greese-tab-current-bg: transparent;\n --greese-tab-current-edge: inset 0 0 0 1.5px var(--greese-color-primary);\n --greese-tab-current-ring: var(--greese-color-primary);\n }\n}\n@layer greese.overrides {\n .greese-Tile {\n background-color: color-mix(in oklab, var(--greese-color-border) 65%, var(--greese-color-surface));\n border-color: transparent;\n }\n .greese-Tile.greese-Tile--filled {\n background-color: transparent;\n border-color: var(--greese-color-border-strong);\n }\n}\n@layer greese.overrides {\n .greese-Toast {\n background-color: var(--greese-color-canvas);\n border: 1px solid var(--greese-toast-tone);\n border-inline-start-width: 3px;\n }\n}\n@layer greese.overrides {\n .greese-Tooltip {\n color: var(--greese-color-fg);\n background-color: var(--greese-color-surface-overlay);\n border: 1px solid var(--greese-color-fg);\n --greese-tooltip-border: var(--greese-color-fg);\n }\n}"},{"id":"pebble","description":"Pebble: as round as things get. Every control, field, tab, badge and tooltip is a pill, so square ones (icon buttons, checkboxes, avatars) are circles; containers take the extra-large radius, and a multi-line field the same, not a pill. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled pebble.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Pebble: as round as things get. Every control, field, tab, badge and tooltip is a pill, so square ones (icon buttons, checkboxes, avatars) are circles; containers take the extra-large radius, and a multi-line field the same, not a pill.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled pebble.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-pill)\",\n field: \"var(--greese-radius-pill)\",\n surface: \"var(--greese-radius-xl)\",\n panel: \"var(--greese-radius-xl)\",\n inset: \"var(--greese-radius-pill)\",\n pill: \"var(--greese-radius-pill)\",\n round: \"var(--greese-radius-round)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n border: 1px solid var(--greese-color-border);\n border-radius: var(--greese-corner-surface);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Textarea) {\n border-radius: var(--greese-radius-xl);\n}\n","css":"/**\n * Pebble: as round as things get. Every control, field, tab, badge and tooltip is a pill, so square ones (icon buttons, checkboxes, avatars) are circles; containers take the extra-large radius, and a multi-line field the same, not a pill.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/pebble.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-pill);\n --greese-corner-field: var(--greese-radius-pill);\n --greese-corner-surface: var(--greese-radius-xl);\n --greese-corner-panel: var(--greese-radius-xl);\n --greese-corner-inset: var(--greese-radius-pill);\n --greese-corner-pill: var(--greese-radius-pill);\n --greese-corner-round: var(--greese-radius-round);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n border: 1px solid var(--greese-color-border);\n border-radius: var(--greese-corner-surface);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Textarea {\n border-radius: var(--greese-radius-xl);\n }\n}"},{"id":"pocket","description":"Pocket: things rise out of an invisible slot at one of their own edges, as if from a pocket, rather than fading in. Reveals, panels, table rows and toasts rise out of theirs; menus drop out of a slot under their trigger and go back up into it; dialogs and tooltips rise out of a slot and sink back into it. Pages sink into a slot at their foot and the next rises out of it; going back, they go up into a slot at their head and the last drops out of it. A greese ui motion theme (ADR 0025): it assigns the motion roles (which built-in effect plays where, and which duration and easing it takes) and paces every entrance. It redefines no effect and no token, and sets no colors and no shapes, so it goes with any of those. Compile it with Sass's package importer, after greese ui's styles, or use the compiled pocket.css. Generated from apps/site/src/studio/motions.ts (npm run themes -w site).","scss":"/**\n * Pocket: things rise out of an invisible slot at one of their own edges, as if from a pocket, rather than fading in. Reveals, panels, table rows and toasts rise out of theirs; menus drop out of a slot under their trigger and go back up into it; dialogs and tooltips rise out of a slot and sink back into it. Pages sink into a slot at their foot and the next rises out of it; going back, they go up into a slot at their head and the last drops out of it.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled pocket.css.\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.motion-defaults((\n duration: \"0.55s\",\n distance: \"1.25rem\",\n stagger: \"0.05s\",\n theme: \"pocket-up\",\n content: \"pocket-up\",\n rows: \"pocket-up\",\n toast: \"pocket-up\",\n dialog: \"pocket-up\",\n dialog-exit: \"pocket-out-down\",\n popover: \"pocket-down\",\n popover-exit: \"pocket-out-up\",\n tooltip: \"pocket-up\",\n tooltip-exit: \"pocket-out-down\",\n content-duration: \"normal\",\n rows-duration: \"slow\",\n overlay-duration: \"normal\",\n toast-duration: \"normal\",\n exit-duration: \"fast\",\n enter-ease: \"cubic-bezier(0.2, 0.9, 0.1, 1)\",\n exit-ease: \"exit\",\n page: \"pocket-up\",\n page-exit: \"pocket-out-down\",\n page-back: \"pocket-down\",\n page-back-exit: \"pocket-out-up\",\n page-duration: \"0.55s\",\n page-ease: \"cubic-bezier(0.2, 0.9, 0.1, 1)\",\n page-stagger: \"0.05s\",\n));\n","css":"/**\n * Pocket: things rise out of an invisible slot at one of their own edges, as if from a pocket, rather than fading in. Reveals, panels, table rows and toasts rise out of theirs; menus drop out of a slot under their trigger and go back up into it; dialogs and tooltips rise out of a slot and sink back into it. Pages sink into a slot at their foot and the next rises out of it; going back, they go up into a slot at their head and the last drops out of it.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/pocket.css'\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n :root {\n --greese-motion-duration: 0.55s;\n --greese-motion-distance: 1.25rem;\n --greese-motion-stagger: 0.05s;\n --greese-motion-theme: greese-pocket-up;\n --greese-motion-content: greese-pocket-up;\n --greese-motion-rows: greese-pocket-up;\n --greese-motion-toast: greese-pocket-up;\n --greese-motion-dialog: greese-pocket-up;\n --greese-motion-dialog-exit-translate: 0px 100%;\n --greese-motion-dialog-exit-scale: 1;\n --greese-motion-dialog-exit-opacity: 1;\n --greese-motion-dialog-exit-mask-image: linear-gradient(black, black);\n --greese-motion-dialog-exit-mask-size: 100% 0%;\n --greese-motion-dialog-exit-mask-repeat: no-repeat;\n --greese-motion-dialog-exit-mask-position: 50% 0%;\n --greese-motion-dialog-exit-transform: none;\n --greese-motion-dialog-exit-mask-from: 100% 100%;\n --greese-motion-popover: greese-pocket-down;\n --greese-motion-popover-exit-translate: 0px -100%;\n --greese-motion-popover-exit-scale: 1;\n --greese-motion-popover-exit-opacity: 1;\n --greese-motion-popover-exit-mask-image: linear-gradient(black, black);\n --greese-motion-popover-exit-mask-size: 100% 0%;\n --greese-motion-popover-exit-mask-repeat: no-repeat;\n --greese-motion-popover-exit-mask-position: 50% 100%;\n --greese-motion-popover-exit-transform: none;\n --greese-motion-popover-exit-mask-from: 100% 100%;\n --greese-motion-tooltip: greese-pocket-up;\n --greese-motion-tooltip-exit-translate: 0px 100%;\n --greese-motion-tooltip-exit-scale: 1;\n --greese-motion-tooltip-exit-opacity: 1;\n --greese-motion-tooltip-exit-mask-image: linear-gradient(black, black);\n --greese-motion-tooltip-exit-mask-size: 100% 0%;\n --greese-motion-tooltip-exit-mask-repeat: no-repeat;\n --greese-motion-tooltip-exit-mask-position: 50% 0%;\n --greese-motion-tooltip-exit-transform: none;\n --greese-motion-tooltip-exit-mask-from: 100% 100%;\n --greese-motion-content-duration: var(--greese-duration-normal);\n --greese-motion-rows-duration: var(--greese-duration-slow);\n --greese-motion-overlay-duration: var(--greese-duration-normal);\n --greese-motion-toast-duration: var(--greese-duration-normal);\n --greese-motion-exit-duration: var(--greese-duration-fast);\n --greese-motion-enter-ease: cubic-bezier(0.2, 0.9, 0.1, 1);\n --greese-motion-exit-ease: var(--greese-easing-exit);\n --greese-motion-page: greese-pocket-up;\n --greese-motion-page-exit: greese-pocket-out-down;\n --greese-motion-page-back: greese-pocket-down;\n --greese-motion-page-back-exit: greese-pocket-out-up;\n --greese-motion-page-duration: 0.55s;\n --greese-motion-page-ease: cubic-bezier(0.2, 0.9, 0.1, 1);\n --greese-motion-page-stagger: 0.05s;\n }\n}\n@layer greese.utilities {\n @media (prefers-reduced-motion: no-preference) {\n @keyframes greese-pocket-up {\n from {\n translate: 0px 100%;\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n to {\n translate: 0px 0px;\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n }\n @keyframes greese-pocket-down {\n from {\n translate: 0px -100%;\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n to {\n translate: 0px 0px;\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n }\n @keyframes greese-pocket-out-down {\n from {\n translate: 0px 0px;\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n to {\n translate: 0px 100%;\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n }\n @keyframes greese-pocket-out-up {\n from {\n translate: 0px 0px;\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n to {\n translate: 0px -100%;\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n }\n }\n}"},{"id":"ridge","description":"Ridge: edges cut in ridges, like pinking shears. Containers have a zigzag hem that deepens when a card is hovered, controls and indicators zigzag ends, fields and alerts a zigzag start edge, tabs a zigzag top. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled ridge.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Ridge: edges cut in ridges, like pinking shears. Containers have a zigzag hem that deepens when a card is hovered, controls and indicators zigzag ends, fields and alerts a zigzag start edge, tabs a zigzag top.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled ridge.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-none)\",\n field: \"var(--greese-radius-none)\",\n surface: \"var(--greese-radius-none)\",\n panel: \"var(--greese-radius-none)\",\n inset: \"var(--greese-radius-none)\",\n pill: \"var(--greese-radius-none)\",\n round: \"var(--greese-radius-none)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Radio) {\n .greese-Radio-input {\n rotate: 45deg;\n scale: 0.7;\n }\n}\n\n@include greese.component(Slider) {\n &::-webkit-slider-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n\n &::-moz-range-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n}\n\n@include greese.component(Switch) {\n .greese-Switch-track::before {\n position: absolute;\n inset: 0;\n content: '';\n background-color: var(--greese-color-border-strong);\n clip-path: polygon(0 50%, 0.625rem 0, calc(100% - 0.625rem) 0, 100% 50%, calc(100% - 0.625rem) 100%, 0.625rem 100%);\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n\n .greese-Switch-track:has(.greese-Switch-input:checked)::before {\n background-color: var(--greese-color-primary);\n }\n\n .greese-Switch-input,\n .greese-Switch-input:checked {\n background-color: transparent;\n }\n\n .greese-Switch-thumb {\n rotate: 45deg;\n scale: 0.8;\n }\n}\n\n// Shapes (ADR 0024)\n@property --greese-shape-bleed {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-z {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: '<color>';\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ridge-control::after,\n .greese-shape-ridge-field::after,\n .greese-shape-ridge-container::after,\n .greese-shape-ridge-small::after,\n .greese-shape-ridge-indicator::after,\n .greese-shape-ridge-tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ridge-control::after,\n .greese-shape-ridge-field::after,\n .greese-shape-ridge-container::after,\n .greese-shape-ridge-small::after,\n .greese-shape-ridge-indicator::after,\n .greese-shape-ridge-tab::after {\n display: none;\n }\n }\n .greese-shape-ridge-mark {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ridge-mark::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ridge-mark {\n transition: --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ridge-mark {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ridge-mark::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-SegmentedControl-track::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-SegmentedControl-track::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear,\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n border-color var(--greese-duration-normal) var(--greese-easing-standard),\n translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected='true'] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-ridge-control,\n .greese-Button {\n --greese-shape-z: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(100% - var(--greese-shape-z) + 0.82 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.02 * var(--greese-shape-bleed)) 16.667%, calc(100% - var(--greese-shape-z) + 1.02 * var(--greese-shape-bleed)) 33.333%, calc(100% + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-z) + 1.02 * var(--greese-shape-bleed)) 66.667%, calc(100% + 1.02 * var(--greese-shape-bleed)) 83.333%, calc(100% - var(--greese-shape-z) + 0.82 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.82 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.02 * var(--greese-shape-bleed)) 83.333%, calc(var(--greese-shape-z) - 1.02 * var(--greese-shape-bleed)) 66.667%, calc(-1 * 1.02 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-z) - 1.02 * var(--greese-shape-bleed)) 33.333%, calc(-1 * 1.02 * var(--greese-shape-bleed)) 16.667%, calc(var(--greese-shape-z) - 0.82 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(100% - var(--greese-shape-z)) 0, 100% 16.667%, calc(100% - var(--greese-shape-z)) 33.333%, 100% 50%, calc(100% - var(--greese-shape-z)) 66.667%, 100% 83.333%, calc(100% - var(--greese-shape-z)) 100%, calc(var(--greese-shape-z)) 100%, 0 83.333%, calc(var(--greese-shape-z)) 66.667%, 0 50%, calc(var(--greese-shape-z)) 33.333%, 0 16.667%, calc(var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.02 * var(--greese-shape-border)) 16.667%, calc(var(--greese-shape-z) + 1.02 * var(--greese-shape-border)) 33.333%, calc(1.02 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-z) + 1.02 * var(--greese-shape-border)) 66.667%, calc(1.02 * var(--greese-shape-border)) 83.333%, calc(var(--greese-shape-z) + 0.82 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.02 * var(--greese-shape-border)) 83.333%, calc(100% - var(--greese-shape-z) - 1.02 * var(--greese-shape-border)) 66.667%, calc(100% - 1.02 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-z) - 1.02 * var(--greese-shape-border)) 33.333%, calc(100% - 1.02 * var(--greese-shape-border)) 16.667%, calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-z: 2.8px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-z: 2px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-z: 2px;\n }\n @media (hover: hover) {\n .greese-shape-ridge-control:hover,\n .greese-Button:hover {\n --greese-shape-z: 6px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-z: 4.2px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-z: 3px;\n }\n }\n .greese-shape-ridge-control:active,\n .greese-Button:active {\n --greese-shape-z: 2px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-z: 1.4px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-z: 1px;\n }\n .greese-shape-ridge-control:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-z) - 0.876 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.876 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.009 * var(--greese-shape-bleed)) 87.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 75%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 62.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 50%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 37.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 25%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 12.5%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-z)) 0, 100% 0, 100% 100%, calc(var(--greese-shape-z)) 100%, 0 87.5%, calc(var(--greese-shape-z)) 75%, 0 62.5%, calc(var(--greese-shape-z)) 50%, 0 37.5%, calc(var(--greese-shape-z)) 25%, 0 12.5%, calc(var(--greese-shape-z)) 0, calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.009 * var(--greese-shape-border)) 12.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 25%, calc(1.009 * var(--greese-shape-border)) 37.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 50%, calc(1.009 * var(--greese-shape-border)) 62.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 75%, calc(1.009 * var(--greese-shape-border)) 87.5%, calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ridge-field:dir(rtl),\n .greese-Input:dir(rtl),\n .greese-OtpField-slot:dir(rtl),\n .greese-Select:dir(rtl),\n .greese-Textarea:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.009 * var(--greese-shape-bleed)) 12.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 25%, calc(100% + 1.009 * var(--greese-shape-bleed)) 37.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 50%, calc(100% + 1.009 * var(--greese-shape-bleed)) 62.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 75%, calc(100% + 1.009 * var(--greese-shape-bleed)) 87.5%, calc(100% - var(--greese-shape-z) + 0.876 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-z) + 0.876 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 12.5%, calc(100% - var(--greese-shape-z)) 25%, 100% 37.5%, calc(100% - var(--greese-shape-z)) 50%, 100% 62.5%, calc(100% - var(--greese-shape-z)) 75%, 100% 87.5%, calc(100% - var(--greese-shape-z)) 100%, 0 100%, 0 0, calc(100% - var(--greese-shape-z)) 0, 100% 12.5%, calc(100% - 1.009 * var(--greese-shape-border)) 12.5%, calc(100% - var(--greese-shape-z) - 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.876 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.009 * var(--greese-shape-border)) 87.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 75%, calc(100% - 1.009 * var(--greese-shape-border)) 62.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 50%, calc(100% - 1.009 * var(--greese-shape-border)) 37.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 25%, calc(100% - 1.009 * var(--greese-shape-border)) 12.5%);\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-field:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-z: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-z) + 0.445 * var(--greese-shape-bleed)), 96.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 93.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 90.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 87.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 84.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 81.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 78.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 71.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 68.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 65.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 62.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 59.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 56.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 53.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 50% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 46.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 43.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 40.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 37.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 34.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 31.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 28.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 21.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 18.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 15.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 12.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 9.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 6.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 3.125% calc(100% + 1.345 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-z) + 0.445 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(100% - var(--greese-shape-z)), 96.875% 100%, 93.75% calc(100% - var(--greese-shape-z)), 90.625% 100%, 87.5% calc(100% - var(--greese-shape-z)), 84.375% 100%, 81.25% calc(100% - var(--greese-shape-z)), 78.125% 100%, 75% calc(100% - var(--greese-shape-z)), 71.875% 100%, 68.75% calc(100% - var(--greese-shape-z)), 65.625% 100%, 62.5% calc(100% - var(--greese-shape-z)), 59.375% 100%, 56.25% calc(100% - var(--greese-shape-z)), 53.125% 100%, 50% calc(100% - var(--greese-shape-z)), 46.875% 100%, 43.75% calc(100% - var(--greese-shape-z)), 40.625% 100%, 37.5% calc(100% - var(--greese-shape-z)), 34.375% 100%, 31.25% calc(100% - var(--greese-shape-z)), 28.125% 100%, 25% calc(100% - var(--greese-shape-z)), 21.875% 100%, 18.75% calc(100% - var(--greese-shape-z)), 15.625% 100%, 12.5% calc(100% - var(--greese-shape-z)), 9.375% 100%, 6.25% calc(100% - var(--greese-shape-z)), 3.125% 100%, 0 calc(100% - var(--greese-shape-z)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-z) - 0.445 * var(--greese-shape-border)), 3.125% calc(100% - 1.345 * var(--greese-shape-border)), 6.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 9.375% calc(100% - 1.345 * var(--greese-shape-border)), 12.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 15.625% calc(100% - 1.345 * var(--greese-shape-border)), 18.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 21.875% calc(100% - 1.345 * var(--greese-shape-border)), 25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 28.125% calc(100% - 1.345 * var(--greese-shape-border)), 31.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 34.375% calc(100% - 1.345 * var(--greese-shape-border)), 37.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 40.625% calc(100% - 1.345 * var(--greese-shape-border)), 43.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 46.875% calc(100% - 1.345 * var(--greese-shape-border)), 50% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 53.125% calc(100% - 1.345 * var(--greese-shape-border)), 56.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 59.375% calc(100% - 1.345 * var(--greese-shape-border)), 62.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 65.625% calc(100% - 1.345 * var(--greese-shape-border)), 68.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 71.875% calc(100% - 1.345 * var(--greese-shape-border)), 75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 78.125% calc(100% - 1.345 * var(--greese-shape-border)), 81.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 84.375% calc(100% - 1.345 * var(--greese-shape-border)), 87.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 90.625% calc(100% - 1.345 * var(--greese-shape-border)), 93.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 96.875% calc(100% - 1.345 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-z) - 0.445 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-ridge-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-z: 9px;\n }\n }\n .greese-shape-ridge-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ridge-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-z: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-z) - 0.802 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.802 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.024 * var(--greese-shape-bleed)) 90%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 80%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 70%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 60%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 40%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 30%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 20%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 10%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-z)) 0, 100% 0, 100% 100%, calc(var(--greese-shape-z)) 100%, 0 90%, calc(var(--greese-shape-z)) 80%, 0 70%, calc(var(--greese-shape-z)) 60%, 0 50%, calc(var(--greese-shape-z)) 40%, 0 30%, calc(var(--greese-shape-z)) 20%, 0 10%, calc(var(--greese-shape-z)) 0, calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.024 * var(--greese-shape-border)) 10%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 20%, calc(1.024 * var(--greese-shape-border)) 30%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 40%, calc(1.024 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 60%, calc(1.024 * var(--greese-shape-border)) 70%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 80%, calc(1.024 * var(--greese-shape-border)) 90%, calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ridge-small:dir(rtl),\n .greese-Alert:dir(rtl),\n .greese-Collapsible-trigger:dir(rtl),\n .greese-Tooltip:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.024 * var(--greese-shape-bleed)) 10%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 20%, calc(100% + 1.024 * var(--greese-shape-bleed)) 30%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 40%, calc(100% + 1.024 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 60%, calc(100% + 1.024 * var(--greese-shape-bleed)) 70%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 80%, calc(100% + 1.024 * var(--greese-shape-bleed)) 90%, calc(100% - var(--greese-shape-z) + 0.802 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-z) + 0.802 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 10%, calc(100% - var(--greese-shape-z)) 20%, 100% 30%, calc(100% - var(--greese-shape-z)) 40%, 100% 50%, calc(100% - var(--greese-shape-z)) 60%, 100% 70%, calc(100% - var(--greese-shape-z)) 80%, 100% 90%, calc(100% - var(--greese-shape-z)) 100%, 0 100%, 0 0, calc(100% - var(--greese-shape-z)) 0, 100% 10%, calc(100% - 1.024 * var(--greese-shape-border)) 10%, calc(100% - var(--greese-shape-z) - 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.802 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.024 * var(--greese-shape-border)) 90%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 80%, calc(100% - 1.024 * var(--greese-shape-border)) 70%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 60%, calc(100% - 1.024 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 40%, calc(100% - 1.024 * var(--greese-shape-border)) 30%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 20%, calc(100% - 1.024 * var(--greese-shape-border)) 10%);\n }\n .greese-shape-ridge-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ridge-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(100% - var(--greese-shape-z) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 25%, calc(100% - var(--greese-shape-z) + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% + 1.002 * var(--greese-shape-bleed)) 75%, calc(100% - var(--greese-shape-z) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 75%, calc(var(--greese-shape-z) - 1.002 * var(--greese-shape-bleed)) 50%, calc(-1 * 1.002 * var(--greese-shape-bleed)) 25%, calc(var(--greese-shape-z) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(100% - var(--greese-shape-z)) 0, 100% 25%, calc(100% - var(--greese-shape-z)) 50%, 100% 75%, calc(100% - var(--greese-shape-z)) 100%, calc(var(--greese-shape-z)) 100%, 0 75%, calc(var(--greese-shape-z)) 50%, 0 25%, calc(var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 25%, calc(var(--greese-shape-z) + 1.002 * var(--greese-shape-border)) 50%, calc(1.002 * var(--greese-shape-border)) 75%, calc(var(--greese-shape-z) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 75%, calc(100% - var(--greese-shape-z) - 1.002 * var(--greese-shape-border)) 50%, calc(100% - 1.002 * var(--greese-shape-border)) 25%, calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(50% calc(-1 * 1.147 * var(--greese-shape-bleed)), calc(100% + 2.04 * var(--greese-shape-bleed)) 50%, 50% calc(100% + 1.147 * var(--greese-shape-bleed)), calc(-1 * 2.04 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, 50% 0, 100% 50%, 50% 100%, 0 50%, 50% 0, 50% calc(1.147 * var(--greese-shape-border)), calc(2.04 * var(--greese-shape-border)) 50%, 50% calc(100% - 1.147 * var(--greese-shape-border)), calc(100% - 2.04 * var(--greese-shape-border)) 50%, 50% calc(1.147 * var(--greese-shape-border)));\n }\n .greese-shape-ridge-mark:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-tab,\n .greese-Tab {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-z) - 0.894 * var(--greese-shape-bleed)), 8.333% calc(-1 * 1.006 * var(--greese-shape-bleed)), 16.667% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 25% calc(-1 * 1.006 * var(--greese-shape-bleed)), 33.333% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 41.667% calc(-1 * 1.006 * var(--greese-shape-bleed)), 50% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 58.333% calc(-1 * 1.006 * var(--greese-shape-bleed)), 66.667% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 75% calc(-1 * 1.006 * var(--greese-shape-bleed)), 83.333% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 91.667% calc(-1 * 1.006 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-z) - 0.894 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 calc(var(--greese-shape-z)), 8.333% 0, 16.667% calc(var(--greese-shape-z)), 25% 0, 33.333% calc(var(--greese-shape-z)), 41.667% 0, 50% calc(var(--greese-shape-z)), 58.333% 0, 66.667% calc(var(--greese-shape-z)), 75% 0, 83.333% calc(var(--greese-shape-z)), 91.667% 0, 100% calc(var(--greese-shape-z)), 100% 100%, 0 100%, 0 calc(var(--greese-shape-z)), calc(var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)), 91.667% calc(1.006 * var(--greese-shape-border)), 83.333% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 75% calc(1.006 * var(--greese-shape-border)), 66.667% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 58.333% calc(1.006 * var(--greese-shape-border)), 50% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 41.667% calc(1.006 * var(--greese-shape-border)), 33.333% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 25% calc(1.006 * var(--greese-shape-border)), 16.667% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 8.333% calc(1.006 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)));\n }\n .greese-shape-ridge-tab:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n}\n","css":"/**\n * Ridge: edges cut in ridges, like pinking shears. Containers have a zigzag hem that deepens when a card is hovered, controls and indicators zigzag ends, fields and alerts a zigzag start edge, tabs a zigzag top.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/ridge.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-none);\n --greese-corner-field: var(--greese-radius-none);\n --greese-corner-surface: var(--greese-radius-none);\n --greese-corner-panel: var(--greese-radius-none);\n --greese-corner-inset: var(--greese-radius-none);\n --greese-corner-pill: var(--greese-radius-none);\n --greese-corner-round: var(--greese-radius-none);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Radio .greese-Radio-input {\n rotate: 45deg;\n scale: 0.7;\n }\n}\n@layer greese.overrides {\n .greese-Slider::-webkit-slider-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n .greese-Slider::-moz-range-thumb {\n rotate: 45deg;\n scale: 0.85;\n }\n}\n@layer greese.overrides {\n .greese-Switch .greese-Switch-track::before {\n position: absolute;\n inset: 0;\n content: \"\";\n background-color: var(--greese-color-border-strong);\n clip-path: polygon(0 50%, 0.625rem 0, calc(100% - 0.625rem) 0, 100% 50%, calc(100% - 0.625rem) 100%, 0.625rem 100%);\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n .greese-Switch .greese-Switch-track:has(.greese-Switch-input:checked)::before {\n background-color: var(--greese-color-primary);\n }\n .greese-Switch .greese-Switch-input,\n .greese-Switch .greese-Switch-input:checked {\n background-color: transparent;\n }\n .greese-Switch .greese-Switch-thumb {\n rotate: 45deg;\n scale: 0.8;\n }\n}\n@property --greese-shape-bleed {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-z {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: \"<color>\";\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ridge-control::after,\n .greese-shape-ridge-field::after,\n .greese-shape-ridge-container::after,\n .greese-shape-ridge-small::after,\n .greese-shape-ridge-indicator::after,\n .greese-shape-ridge-tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ridge-control,\n .greese-shape-ridge-field,\n .greese-shape-ridge-container,\n .greese-shape-ridge-small,\n .greese-shape-ridge-indicator,\n .greese-shape-ridge-tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ridge-control::after,\n .greese-shape-ridge-field::after,\n .greese-shape-ridge-container::after,\n .greese-shape-ridge-small::after,\n .greese-shape-ridge-indicator::after,\n .greese-shape-ridge-tab::after {\n display: none;\n }\n }\n .greese-shape-ridge-mark {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ridge-mark::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ridge-mark {\n transition: --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ridge-mark {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ridge-mark::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-SegmentedControl-track::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-SegmentedControl-track,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-SegmentedControl-track::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear, box-shadow var(--greese-duration-normal) var(--greese-easing-standard), border-color var(--greese-duration-normal) var(--greese-easing-standard), translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected=true] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-z var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-ridge-control,\n .greese-Button {\n --greese-shape-z: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(100% - var(--greese-shape-z) + 0.82 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.02 * var(--greese-shape-bleed)) 16.667%, calc(100% - var(--greese-shape-z) + 1.02 * var(--greese-shape-bleed)) 33.333%, calc(100% + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-z) + 1.02 * var(--greese-shape-bleed)) 66.667%, calc(100% + 1.02 * var(--greese-shape-bleed)) 83.333%, calc(100% - var(--greese-shape-z) + 0.82 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.82 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.02 * var(--greese-shape-bleed)) 83.333%, calc(var(--greese-shape-z) - 1.02 * var(--greese-shape-bleed)) 66.667%, calc(-1 * 1.02 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-z) - 1.02 * var(--greese-shape-bleed)) 33.333%, calc(-1 * 1.02 * var(--greese-shape-bleed)) 16.667%, calc(var(--greese-shape-z) - 0.82 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(100% - var(--greese-shape-z)) 0, 100% 16.667%, calc(100% - var(--greese-shape-z)) 33.333%, 100% 50%, calc(100% - var(--greese-shape-z)) 66.667%, 100% 83.333%, calc(100% - var(--greese-shape-z)) 100%, calc(var(--greese-shape-z)) 100%, 0 83.333%, calc(var(--greese-shape-z)) 66.667%, 0 50%, calc(var(--greese-shape-z)) 33.333%, 0 16.667%, calc(var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.02 * var(--greese-shape-border)) 16.667%, calc(var(--greese-shape-z) + 1.02 * var(--greese-shape-border)) 33.333%, calc(1.02 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-z) + 1.02 * var(--greese-shape-border)) 66.667%, calc(1.02 * var(--greese-shape-border)) 83.333%, calc(var(--greese-shape-z) + 0.82 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.02 * var(--greese-shape-border)) 83.333%, calc(100% - var(--greese-shape-z) - 1.02 * var(--greese-shape-border)) 66.667%, calc(100% - 1.02 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-z) - 1.02 * var(--greese-shape-border)) 33.333%, calc(100% - 1.02 * var(--greese-shape-border)) 16.667%, calc(100% - var(--greese-shape-z) - 0.82 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-z: 2.8px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-z: 2px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-z: 2px;\n }\n @media (hover: hover) {\n .greese-shape-ridge-control:hover,\n .greese-Button:hover {\n --greese-shape-z: 6px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-z: 4.2px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-z: 3px;\n }\n }\n .greese-shape-ridge-control:active,\n .greese-Button:active {\n --greese-shape-z: 2px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-z: 1.4px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-z: 1px;\n }\n .greese-shape-ridge-control:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-z) - 0.876 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.876 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.009 * var(--greese-shape-bleed)) 87.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 75%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 62.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 50%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 37.5%, calc(var(--greese-shape-z) - 1.009 * var(--greese-shape-bleed)) 25%, calc(-1 * 1.009 * var(--greese-shape-bleed)) 12.5%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-z)) 0, 100% 0, 100% 100%, calc(var(--greese-shape-z)) 100%, 0 87.5%, calc(var(--greese-shape-z)) 75%, 0 62.5%, calc(var(--greese-shape-z)) 50%, 0 37.5%, calc(var(--greese-shape-z)) 25%, 0 12.5%, calc(var(--greese-shape-z)) 0, calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.009 * var(--greese-shape-border)) 12.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 25%, calc(1.009 * var(--greese-shape-border)) 37.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 50%, calc(1.009 * var(--greese-shape-border)) 62.5%, calc(var(--greese-shape-z) + 1.009 * var(--greese-shape-border)) 75%, calc(1.009 * var(--greese-shape-border)) 87.5%, calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ridge-field:dir(rtl),\n .greese-Input:dir(rtl),\n .greese-OtpField-slot:dir(rtl),\n .greese-Select:dir(rtl),\n .greese-Textarea:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.009 * var(--greese-shape-bleed)) 12.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 25%, calc(100% + 1.009 * var(--greese-shape-bleed)) 37.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 50%, calc(100% + 1.009 * var(--greese-shape-bleed)) 62.5%, calc(100% - var(--greese-shape-z) + 1.009 * var(--greese-shape-bleed)) 75%, calc(100% + 1.009 * var(--greese-shape-bleed)) 87.5%, calc(100% - var(--greese-shape-z) + 0.876 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-z) + 0.876 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 12.5%, calc(100% - var(--greese-shape-z)) 25%, 100% 37.5%, calc(100% - var(--greese-shape-z)) 50%, 100% 62.5%, calc(100% - var(--greese-shape-z)) 75%, 100% 87.5%, calc(100% - var(--greese-shape-z)) 100%, 0 100%, 0 0, calc(100% - var(--greese-shape-z)) 0, 100% 12.5%, calc(100% - 1.009 * var(--greese-shape-border)) 12.5%, calc(100% - var(--greese-shape-z) - 0.876 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.876 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.009 * var(--greese-shape-border)) 87.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 75%, calc(100% - 1.009 * var(--greese-shape-border)) 62.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 50%, calc(100% - 1.009 * var(--greese-shape-border)) 37.5%, calc(100% - var(--greese-shape-z) - 1.009 * var(--greese-shape-border)) 25%, calc(100% - 1.009 * var(--greese-shape-border)) 12.5%);\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-field:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-z: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-z) + 0.445 * var(--greese-shape-bleed)), 96.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 93.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 90.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 87.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 84.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 81.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 78.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 71.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 68.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 65.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 62.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 59.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 56.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 53.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 50% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 46.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 43.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 40.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 37.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 34.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 31.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 28.125% calc(100% + 1.345 * var(--greese-shape-bleed)), 25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 21.875% calc(100% + 1.345 * var(--greese-shape-bleed)), 18.75% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 15.625% calc(100% + 1.345 * var(--greese-shape-bleed)), 12.5% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 9.375% calc(100% + 1.345 * var(--greese-shape-bleed)), 6.25% calc(100% - var(--greese-shape-z) + 1.345 * var(--greese-shape-bleed)), 3.125% calc(100% + 1.345 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-z) + 0.445 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(100% - var(--greese-shape-z)), 96.875% 100%, 93.75% calc(100% - var(--greese-shape-z)), 90.625% 100%, 87.5% calc(100% - var(--greese-shape-z)), 84.375% 100%, 81.25% calc(100% - var(--greese-shape-z)), 78.125% 100%, 75% calc(100% - var(--greese-shape-z)), 71.875% 100%, 68.75% calc(100% - var(--greese-shape-z)), 65.625% 100%, 62.5% calc(100% - var(--greese-shape-z)), 59.375% 100%, 56.25% calc(100% - var(--greese-shape-z)), 53.125% 100%, 50% calc(100% - var(--greese-shape-z)), 46.875% 100%, 43.75% calc(100% - var(--greese-shape-z)), 40.625% 100%, 37.5% calc(100% - var(--greese-shape-z)), 34.375% 100%, 31.25% calc(100% - var(--greese-shape-z)), 28.125% 100%, 25% calc(100% - var(--greese-shape-z)), 21.875% 100%, 18.75% calc(100% - var(--greese-shape-z)), 15.625% 100%, 12.5% calc(100% - var(--greese-shape-z)), 9.375% 100%, 6.25% calc(100% - var(--greese-shape-z)), 3.125% 100%, 0 calc(100% - var(--greese-shape-z)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-z) - 0.445 * var(--greese-shape-border)), 3.125% calc(100% - 1.345 * var(--greese-shape-border)), 6.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 9.375% calc(100% - 1.345 * var(--greese-shape-border)), 12.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 15.625% calc(100% - 1.345 * var(--greese-shape-border)), 18.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 21.875% calc(100% - 1.345 * var(--greese-shape-border)), 25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 28.125% calc(100% - 1.345 * var(--greese-shape-border)), 31.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 34.375% calc(100% - 1.345 * var(--greese-shape-border)), 37.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 40.625% calc(100% - 1.345 * var(--greese-shape-border)), 43.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 46.875% calc(100% - 1.345 * var(--greese-shape-border)), 50% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 53.125% calc(100% - 1.345 * var(--greese-shape-border)), 56.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 59.375% calc(100% - 1.345 * var(--greese-shape-border)), 62.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 65.625% calc(100% - 1.345 * var(--greese-shape-border)), 68.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 71.875% calc(100% - 1.345 * var(--greese-shape-border)), 75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 78.125% calc(100% - 1.345 * var(--greese-shape-border)), 81.25% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 84.375% calc(100% - 1.345 * var(--greese-shape-border)), 87.5% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 90.625% calc(100% - 1.345 * var(--greese-shape-border)), 93.75% calc(100% - var(--greese-shape-z) - 1.345 * var(--greese-shape-border)), 96.875% calc(100% - 1.345 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-z) - 0.445 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-ridge-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-z: 9px;\n }\n }\n .greese-shape-ridge-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ridge-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-z: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-z) - 0.802 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.802 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.024 * var(--greese-shape-bleed)) 90%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 80%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 70%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 60%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 40%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 30%, calc(var(--greese-shape-z) - 1.024 * var(--greese-shape-bleed)) 20%, calc(-1 * 1.024 * var(--greese-shape-bleed)) 10%);\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-z)) 0, 100% 0, 100% 100%, calc(var(--greese-shape-z)) 100%, 0 90%, calc(var(--greese-shape-z)) 80%, 0 70%, calc(var(--greese-shape-z)) 60%, 0 50%, calc(var(--greese-shape-z)) 40%, 0 30%, calc(var(--greese-shape-z)) 20%, 0 10%, calc(var(--greese-shape-z)) 0, calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.024 * var(--greese-shape-border)) 10%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 20%, calc(1.024 * var(--greese-shape-border)) 30%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 40%, calc(1.024 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 60%, calc(1.024 * var(--greese-shape-border)) 70%, calc(var(--greese-shape-z) + 1.024 * var(--greese-shape-border)) 80%, calc(1.024 * var(--greese-shape-border)) 90%, calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ridge-small:dir(rtl),\n .greese-Alert:dir(rtl),\n .greese-Collapsible-trigger:dir(rtl),\n .greese-Tooltip:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + 1.024 * var(--greese-shape-bleed)) 10%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 20%, calc(100% + 1.024 * var(--greese-shape-bleed)) 30%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 40%, calc(100% + 1.024 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 60%, calc(100% + 1.024 * var(--greese-shape-bleed)) 70%, calc(100% - var(--greese-shape-z) + 1.024 * var(--greese-shape-bleed)) 80%, calc(100% + 1.024 * var(--greese-shape-bleed)) 90%, calc(100% - var(--greese-shape-z) + 0.802 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-z) + 0.802 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 10%, calc(100% - var(--greese-shape-z)) 20%, 100% 30%, calc(100% - var(--greese-shape-z)) 40%, 100% 50%, calc(100% - var(--greese-shape-z)) 60%, 100% 70%, calc(100% - var(--greese-shape-z)) 80%, 100% 90%, calc(100% - var(--greese-shape-z)) 100%, 0 100%, 0 0, calc(100% - var(--greese-shape-z)) 0, 100% 10%, calc(100% - 1.024 * var(--greese-shape-border)) 10%, calc(100% - var(--greese-shape-z) - 0.802 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.802 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.024 * var(--greese-shape-border)) 90%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 80%, calc(100% - 1.024 * var(--greese-shape-border)) 70%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 60%, calc(100% - 1.024 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 40%, calc(100% - 1.024 * var(--greese-shape-border)) 30%, calc(100% - var(--greese-shape-z) - 1.024 * var(--greese-shape-border)) 20%, calc(100% - 1.024 * var(--greese-shape-border)) 10%);\n }\n .greese-shape-ridge-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ridge-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(100% - var(--greese-shape-z) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 25%, calc(100% - var(--greese-shape-z) + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% + 1.002 * var(--greese-shape-bleed)) 75%, calc(100% - var(--greese-shape-z) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-z) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 75%, calc(var(--greese-shape-z) - 1.002 * var(--greese-shape-bleed)) 50%, calc(-1 * 1.002 * var(--greese-shape-bleed)) 25%, calc(var(--greese-shape-z) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(100% - var(--greese-shape-z)) 0, 100% 25%, calc(100% - var(--greese-shape-z)) 50%, 100% 75%, calc(100% - var(--greese-shape-z)) 100%, calc(var(--greese-shape-z)) 100%, 0 75%, calc(var(--greese-shape-z)) 50%, 0 25%, calc(var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z)) 0, calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-z) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 25%, calc(var(--greese-shape-z) + 1.002 * var(--greese-shape-border)) 50%, calc(1.002 * var(--greese-shape-border)) 75%, calc(var(--greese-shape-z) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 75%, calc(100% - var(--greese-shape-z) - 1.002 * var(--greese-shape-border)) 50%, calc(100% - 1.002 * var(--greese-shape-border)) 25%, calc(100% - var(--greese-shape-z) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ridge-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(50% calc(-1 * 1.147 * var(--greese-shape-bleed)), calc(100% + 2.04 * var(--greese-shape-bleed)) 50%, 50% calc(100% + 1.147 * var(--greese-shape-bleed)), calc(-1 * 2.04 * var(--greese-shape-bleed)) 50%);\n --greese-shape-ring-clip: polygon(evenodd, 50% 0, 100% 50%, 50% 100%, 0 50%, 50% 0, 50% calc(1.147 * var(--greese-shape-border)), calc(2.04 * var(--greese-shape-border)) 50%, 50% calc(100% - 1.147 * var(--greese-shape-border)), calc(100% - 2.04 * var(--greese-shape-border)) 50%, 50% calc(1.147 * var(--greese-shape-border)));\n }\n .greese-shape-ridge-mark:focus-visible {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ridge-tab,\n .greese-Tab {\n --greese-shape-z: 3px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-z) - 0.894 * var(--greese-shape-bleed)), 8.333% calc(-1 * 1.006 * var(--greese-shape-bleed)), 16.667% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 25% calc(-1 * 1.006 * var(--greese-shape-bleed)), 33.333% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 41.667% calc(-1 * 1.006 * var(--greese-shape-bleed)), 50% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 58.333% calc(-1 * 1.006 * var(--greese-shape-bleed)), 66.667% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 75% calc(-1 * 1.006 * var(--greese-shape-bleed)), 83.333% calc(var(--greese-shape-z) - 1.006 * var(--greese-shape-bleed)), 91.667% calc(-1 * 1.006 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-z) - 0.894 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 calc(var(--greese-shape-z)), 8.333% 0, 16.667% calc(var(--greese-shape-z)), 25% 0, 33.333% calc(var(--greese-shape-z)), 41.667% 0, 50% calc(var(--greese-shape-z)), 58.333% 0, 66.667% calc(var(--greese-shape-z)), 75% 0, 83.333% calc(var(--greese-shape-z)), 91.667% 0, 100% calc(var(--greese-shape-z)), 100% 100%, 0 100%, 0 calc(var(--greese-shape-z)), calc(var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)), 91.667% calc(1.006 * var(--greese-shape-border)), 83.333% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 75% calc(1.006 * var(--greese-shape-border)), 66.667% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 58.333% calc(1.006 * var(--greese-shape-border)), 50% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 41.667% calc(1.006 * var(--greese-shape-border)), 33.333% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 25% calc(1.006 * var(--greese-shape-border)), 16.667% calc(var(--greese-shape-z) + 1.006 * var(--greese-shape-border)), 8.333% calc(1.006 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-z) + 0.894 * var(--greese-shape-border)));\n }\n .greese-shape-ridge-tab:focus-visible {\n --greese-shape-z: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n}"},{"id":"snappy","description":"Snappy: quick and decisive. Short durations, a sharp curve, a tight stagger; things pop in from a short distance, and overlays scale in and away. Pages pop: the old one pops away all at once and the new one pops in. A greese ui motion theme (ADR 0025): it assigns the motion roles (which built-in effect plays where, and which duration and easing it takes) and paces every entrance. It redefines no effect and no token, and sets no colors and no shapes, so it goes with any of those. Compile it with Sass's package importer, after greese ui's styles, or use the compiled snappy.css. Generated from apps/site/src/studio/motions.ts (npm run themes -w site).","scss":"/**\n * Snappy: quick and decisive. Short durations, a sharp curve, a tight stagger; things pop in from a short distance, and overlays scale in and away. Pages pop: the old one pops away all at once and the new one pops in.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled snappy.css.\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.motion-defaults((\n duration: \"0.25s\",\n distance: \"0.5rem\",\n stagger: \"0.03s\",\n theme: \"pop-in\",\n content: \"fade-up\",\n rows: \"fade-up\",\n toast: \"pop-in\",\n overlay: \"scale-in\",\n overlay-exit: \"scale-out\",\n content-duration: \"fast\",\n rows-duration: \"fast\",\n overlay-duration: \"fast\",\n toast-duration: \"fast\",\n exit-duration: \"fast\",\n enter-ease: \"cubic-bezier(0, 0, 0, 1)\",\n exit-ease: \"exit\",\n page: \"pop-in\",\n page-exit: \"pop-out\",\n page-duration: \"0.25s\",\n page-ease: \"cubic-bezier(0, 0, 0, 1)\",\n page-stagger: \"0.03s\",\n page-exit-order: \"together\",\n));\n","css":"/**\n * Snappy: quick and decisive. Short durations, a sharp curve, a tight stagger; things pop in from a short distance, and overlays scale in and away. Pages pop: the old one pops away all at once and the new one pops in.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/snappy.css'\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n :root {\n --greese-motion-duration: 0.25s;\n --greese-motion-distance: 0.5rem;\n --greese-motion-stagger: 0.03s;\n --greese-motion-theme: greese-pop-in;\n --greese-motion-content: greese-fade-up;\n --greese-motion-rows: greese-fade-up;\n --greese-motion-toast: greese-pop-in;\n --greese-motion-overlay: greese-scale-in;\n --greese-motion-overlay-exit-translate: 0px 0px;\n --greese-motion-overlay-exit-scale: 0;\n --greese-motion-overlay-exit-opacity: 0;\n --greese-motion-overlay-exit-mask-image: none;\n --greese-motion-overlay-exit-transform: none;\n --greese-motion-content-duration: var(--greese-duration-fast);\n --greese-motion-rows-duration: var(--greese-duration-fast);\n --greese-motion-overlay-duration: var(--greese-duration-fast);\n --greese-motion-toast-duration: var(--greese-duration-fast);\n --greese-motion-exit-duration: var(--greese-duration-fast);\n --greese-motion-enter-ease: cubic-bezier(0, 0, 0, 1);\n --greese-motion-exit-ease: var(--greese-easing-exit);\n --greese-motion-page: greese-pop-in;\n --greese-motion-page-exit: greese-pop-out;\n --greese-motion-page-duration: 0.25s;\n --greese-motion-page-ease: cubic-bezier(0, 0, 0, 1);\n --greese-motion-page-stagger: 0.03s;\n --greese-motion-page-exit-order: together;\n }\n}\n@layer greese.utilities {\n @media (prefers-reduced-motion: no-preference) {\n @keyframes greese-pop-in {\n from {\n scale: 0.8;\n opacity: 0;\n }\n 60% {\n scale: 1.04;\n opacity: 1;\n }\n }\n @keyframes greese-fade-up {\n from {\n translate: 0px var(--greese-motion-distance, 1rem);\n opacity: 0;\n }\n }\n @keyframes greese-scale-in {\n from {\n scale: 0;\n }\n }\n @keyframes greese-pop-out {\n from {\n scale: 1;\n }\n 40% {\n scale: 1.04;\n opacity: 1;\n }\n to {\n scale: 0.8;\n opacity: 0;\n }\n }\n }\n}"},{"id":"soft","description":"Soft: every corner rounded, a step rounder than the library. Controls and fields take the large radius, containers the extra-large one, accordion items are rounded panels and the off-canvas sidebar rounds its inner edge. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled soft.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Soft: every corner rounded, a step rounder than the library. Controls and fields take the large radius, containers the extra-large one, accordion items are rounded panels and the off-canvas sidebar rounds its inner edge.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled soft.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-lg)\",\n field: \"var(--greese-radius-lg)\",\n surface: \"var(--greese-radius-xl)\",\n panel: \"var(--greese-radius-lg)\",\n inset: \"var(--greese-radius-md)\",\n pill: \"var(--greese-radius-pill)\",\n round: \"var(--greese-radius-round)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n border: 1px solid var(--greese-color-border);\n border-radius: var(--greese-corner-panel);\n }\n}\n\n@include greese.component(Avatar) {\n border-radius: var(--greese-radius-lg);\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Sidebar) {\n border-start-end-radius: var(--greese-corner-surface);\n border-end-end-radius: var(--greese-corner-surface);\n}\n\n@include greese.component(SpeedDial) {\n .greese-SpeedDial-trigger {\n border-radius: var(--greese-radius-xl);\n }\n\n .greese-SpeedDialAction-icon {\n border-radius: var(--greese-radius-lg);\n }\n}\n","css":"/**\n * Soft: every corner rounded, a step rounder than the library. Controls and fields take the large radius, containers the extra-large one, accordion items are rounded panels and the off-canvas sidebar rounds its inner edge.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/soft.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-lg);\n --greese-corner-field: var(--greese-radius-lg);\n --greese-corner-surface: var(--greese-radius-xl);\n --greese-corner-panel: var(--greese-radius-lg);\n --greese-corner-inset: var(--greese-radius-md);\n --greese-corner-pill: var(--greese-radius-pill);\n --greese-corner-round: var(--greese-radius-round);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n border: 1px solid var(--greese-color-border);\n border-radius: var(--greese-corner-panel);\n }\n}\n@layer greese.overrides {\n .greese-Avatar {\n border-radius: var(--greese-radius-lg);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Sidebar {\n border-start-end-radius: var(--greese-corner-surface);\n border-end-end-radius: var(--greese-corner-surface);\n }\n}\n@layer greese.overrides {\n .greese-SpeedDial .greese-SpeedDial-trigger {\n border-radius: var(--greese-radius-xl);\n }\n .greese-SpeedDial .greese-SpeedDialAction-icon {\n border-radius: var(--greese-radius-lg);\n }\n}"},{"id":"sunset","description":"Sunset: a burnt orange primary with ruby, gold and a magenta accent, on neutrals tinted orange. A greese ui color theme (ADR 0025): the brand colors and the neutrals (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme; content and strong shades are derived for contrast (WCAG AA). It sets no shapes and no motion, so it goes with any shape or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled sunset.css. Generated from apps/site/src/studio/presets.ts (npm run themes -w site).","scss":"/**\n * Sunset: a burnt orange primary with ruby, gold and a magenta accent, on neutrals tinted orange.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled sunset.css.\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n color: (\n primary: (light: \"orange-700\", dark: \"orange-400\"),\n secondary: (light: \"ruby-600\", dark: \"ruby-400\"),\n tertiary: (light: \"gold-700\", dark: \"gold-400\"),\n accent: (light: \"magenta-600\", dark: \"magenta-400\"),\n canvas: (light: \"orange-50\", dark: \"orange-999\"),\n surface: (light: \"orange-100\", dark: \"orange-900\"),\n surface-overlay: (light: \"#ffffff\", dark: \"orange-800\"),\n fg: (light: \"orange-999\", dark: \"orange-100\"),\n fg-muted: (light: \"orange-700\", dark: \"orange-300\"),\n border: (light: \"orange-200\", dark: \"orange-800\"),\n border-strong: (light: \"orange-400\", dark: \"orange-700\"),\n track: (light: \"orange-200\", dark: \"orange-600\"),\n ),\n));\n","css":"/**\n * Sunset: a burnt orange primary with ruby, gold and a magenta accent, on neutrals tinted orange.\n *\n * A greese ui color theme (ADR 0025): the brand colors and the neutrals\n * (canvas, surfaces, text, borders) in both schemes, in @layer greese.theme;\n * content and strong shades are derived for contrast (WCAG AA). It sets no\n * shapes and no motion, so it goes with any shape or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/sunset.css'\n *\n * Generated from apps/site/src/studio/presets.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root,\n [data-greese-scheme=light],\n [data-greese-scheme=system] {\n --greese-color-canvas: #fff4ee;\n --greese-color-surface: #ffe8da;\n --greese-color-surface-overlay: #ffffff;\n --greese-color-fg: #290d00;\n --greese-color-fg-muted: #964700;\n --greese-color-border: #ffd8c1;\n --greese-color-border-strong: #ff9d5e;\n --greese-color-track: #ffd8c1;\n --greese-color-primary: #964700;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 80%, #000);\n --greese-color-primary-content: #ffffff;\n --greese-color-secondary: #d12655;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 80%, #000);\n --greese-color-secondary-content: #ffffff;\n --greese-color-tertiary: #8a5f00;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 80%, #000);\n --greese-color-tertiary-content: #ffffff;\n --greese-color-accent: #bb32a3;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 80%, #000);\n --greese-color-accent-content: #ffffff;\n }\n @media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme=light]),\n [data-greese-scheme=system] {\n --greese-color-canvas: #290d00;\n --greese-color-surface: #522300;\n --greese-color-surface-overlay: #733400;\n --greese-color-fg: #ffe8da;\n --greese-color-fg-muted: #ffc19c;\n --greese-color-border: #733400;\n --greese-color-border-strong: #964700;\n --greese-color-track: #c05d00;\n --greese-color-primary: #ff9d5e;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #ff8798;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #feb93d;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #f97cde;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n }\n [data-greese-scheme=dark] {\n --greese-color-canvas: #290d00;\n --greese-color-surface: #522300;\n --greese-color-surface-overlay: #733400;\n --greese-color-fg: #ffe8da;\n --greese-color-fg-muted: #ffc19c;\n --greese-color-border: #733400;\n --greese-color-border-strong: #964700;\n --greese-color-track: #c05d00;\n --greese-color-primary: #ff9d5e;\n --greese-color-primary-strong: color-mix(in oklab, var(--greese-color-primary) 70%, #fff);\n --greese-color-primary-content: #11171c;\n --greese-color-secondary: #ff8798;\n --greese-color-secondary-strong: color-mix(in oklab, var(--greese-color-secondary) 70%, #fff);\n --greese-color-secondary-content: #11171c;\n --greese-color-tertiary: #feb93d;\n --greese-color-tertiary-strong: color-mix(in oklab, var(--greese-color-tertiary) 70%, #fff);\n --greese-color-tertiary-content: #11171c;\n --greese-color-accent: #f97cde;\n --greese-color-accent-strong: color-mix(in oklab, var(--greese-color-accent) 70%, #fff);\n --greese-color-accent-content: #11171c;\n }\n}"},{"id":"ticket","description":"Ticket: square corners, with a round notch punched in each side of containers, fields and tabs; controls and indicators are tags that point onward, and a control’s point stretches when hovered. Marks are notched like stamps. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled ticket.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Ticket: square corners, with a round notch punched in each side of containers, fields and tabs; controls and indicators are tags that point onward, and a control’s point stretches when hovered. Marks are notched like stamps.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled ticket.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-none)\",\n field: \"var(--greese-radius-none)\",\n surface: \"var(--greese-radius-none)\",\n panel: \"var(--greese-radius-none)\",\n inset: \"var(--greese-radius-none)\",\n pill: \"var(--greese-radius-none)\",\n round: \"var(--greese-radius-none)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n\n > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n// Shapes (ADR 0024)\n@property --greese-shape-bleed {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-n {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-r {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-t {\n syntax: '<length>';\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: '<color>';\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-control::after,\n .greese-shape-ticket-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-control::after,\n .greese-shape-ticket-indicator::after {\n display: none;\n }\n }\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-field::after,\n .greese-shape-ticket-container::after,\n .greese-shape-ticket-small::after,\n .greese-shape-ticket-tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-field::after,\n .greese-shape-ticket-container::after,\n .greese-shape-ticket-small::after,\n .greese-shape-ticket-tab::after {\n display: none;\n }\n }\n .greese-shape-ticket-mark {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-mark::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-mark {\n transition: --greese-shape-n var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-mark {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-mark::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear,\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n border-color var(--greese-duration-normal) var(--greese-easing-standard),\n translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected='true'] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard),\n --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard),\n --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: '';\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-ticket-control,\n .greese-Button {\n --greese-shape-t: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-t) + 0.847 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.014 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-t) + 0.847 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-t)) 0, 100% 50%, calc(100% - var(--greese-shape-t)) 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-t) - 0.847 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.014 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-t) - 0.847 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-control:dir(rtl),\n .greese-Button:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-t) - 0.847 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.014 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-t) - 0.847 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-t)) 100%, 0 50%, calc(var(--greese-shape-t)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-t) + 0.847 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.014 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-t) + 0.847 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-t: 7px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-t: 5px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-t: 5px;\n }\n @media (hover: hover) {\n .greese-shape-ticket-control:hover,\n .greese-Button:hover {\n --greese-shape-t: 15px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-t: 10.5px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-t: 7.5px;\n }\n }\n .greese-shape-ticket-control:active,\n .greese-Button:active {\n --greese-shape-t: 6px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-t: 4.2px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-t: 3px;\n }\n .greese-shape-ticket-control:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-r: 5px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ticket-field:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-r: 12px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-ticket-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-r: 16px;\n }\n }\n .greese-shape-ticket-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-r: 7px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-t: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-t) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-t) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-t)) 0, 100% 50%, calc(100% - var(--greese-shape-t)) 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-t) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-t) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-indicator:dir(rtl),\n .greese-Badge:dir(rtl),\n .greese-Chip:dir(rtl),\n .greese-Segment:dir(rtl),\n .greese-SegmentedControl-track:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-t) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-t) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-t)) 100%, 0 50%, calc(var(--greese-shape-t)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-t) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-t) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ticket-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-n: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-n)) 0, calc(100% - var(--greese-shape-n)) 0, calc(100% - var(--greese-shape-n)) calc(var(--greese-shape-n)), 100% calc(var(--greese-shape-n)), 100% calc(100% - var(--greese-shape-n)), calc(100% - var(--greese-shape-n)) calc(100% - var(--greese-shape-n)), calc(100% - var(--greese-shape-n)) 100%, calc(var(--greese-shape-n)) 100%, calc(var(--greese-shape-n)) calc(100% - var(--greese-shape-n)), 0 calc(100% - var(--greese-shape-n)), 0 calc(var(--greese-shape-n)), calc(var(--greese-shape-n)) calc(var(--greese-shape-n)), calc(var(--greese-shape-n)) 0, calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-mark:focus-visible {\n --greese-shape-n: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):focus-visible,\n .greese-Status:not(.greese-Status--pulse):focus-visible {\n --greese-shape-n: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-tab,\n .greese-Tab {\n --greese-shape-r: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-tab:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n}\n","css":"/**\n * Ticket: square corners, with a round notch punched in each side of containers, fields and tabs; controls and indicators are tags that point onward, and a control’s point stretches when hovered. Marks are notched like stamps.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/ticket.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-none);\n --greese-corner-field: var(--greese-radius-none);\n --greese-corner-surface: var(--greese-radius-none);\n --greese-corner-panel: var(--greese-radius-none);\n --greese-corner-inset: var(--greese-radius-none);\n --greese-corner-pill: var(--greese-radius-none);\n --greese-corner-round: var(--greese-radius-none);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n .greese-AccordionItem > .greese-Collapsible-content {\n padding-block-start: var(--greese-space-3);\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@property --greese-shape-bleed {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-border {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-n {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-r {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-t {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --greese-shape-ring {\n syntax: \"<color>\";\n inherits: true;\n initial-value: transparent;\n}\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-control::after,\n .greese-shape-ticket-indicator::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-control,\n .greese-shape-ticket-indicator {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-control::after,\n .greese-shape-ticket-indicator::after {\n display: none;\n }\n }\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-field::after,\n .greese-shape-ticket-container::after,\n .greese-shape-ticket-small::after,\n .greese-shape-ticket-tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-field,\n .greese-shape-ticket-container,\n .greese-shape-ticket-small,\n .greese-shape-ticket-tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-field::after,\n .greese-shape-ticket-container::after,\n .greese-shape-ticket-small::after,\n .greese-shape-ticket-tab::after {\n display: none;\n }\n }\n .greese-shape-ticket-mark {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-shape-ticket-mark::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-shape-ticket-mark {\n transition: --greese-shape-n var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-shape-ticket-mark {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-shape-ticket-mark::after {\n display: none;\n }\n }\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Tile {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-AccordionItem > .greese-Collapsible-content::after,\n .greese-Tile::after {\n display: none;\n }\n }\n .greese-Alert {\n --greese-shape-ring: color-mix(in oklab, var(--greese-alert-tone) 30%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Alert::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Alert {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Alert {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Alert::after {\n display: none;\n }\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: var(--greese-shape-clip) border-box;\n }\n @media (forced-colors: active) {\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n clip-path: none;\n }\n }\n .greese-Badge {\n --greese-shape-ring: color-mix(in oklab, var(--greese-badge-tone) 35%, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Badge::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Badge {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Badge {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Badge::after {\n display: none;\n }\n }\n .greese-Button {\n --greese-shape-ring: var(--greese-button-border, transparent);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Button::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Button {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Button::after {\n display: none;\n }\n }\n .greese-Card {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Card::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Card.greese-Card--outline {\n --greese-shape-ring: var(--greese-color-border);\n }\n .greese-Card.greese-Card--elevated {\n --greese-shape-ring: var(--greese-color-border-strong);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n .greese-Card.greese-Card--interactive {\n transition: --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear, box-shadow var(--greese-duration-normal) var(--greese-easing-standard), border-color var(--greese-duration-normal) var(--greese-easing-standard), translate var(--greese-duration-normal) var(--greese-easing-standard);\n }\n }\n @media (forced-colors: active) {\n .greese-Card {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Card::after {\n display: none;\n }\n }\n .greese-Chip {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Chip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Chip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Chip::after {\n display: none;\n }\n }\n .greese-Collapsible-trigger {\n --greese-shape-ring: var(--greese-collapsible-border, var(--greese-color-border));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Collapsible-trigger::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Collapsible-trigger {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Collapsible-trigger {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Collapsible-trigger::after {\n display: none;\n }\n }\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n --greese-shape-ring: var(--greese-color-border);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Dialog::after,\n .greese-Menu::after,\n .greese-Popover::after {\n display: none;\n }\n }\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Input:hover,\n .greese-Select:hover,\n .greese-Textarea:hover {\n --greese-shape-ring: var(--greese-color-fg-muted);\n }\n .greese-Input[aria-invalid=true], .greese-Input[data-invalid],\n .greese-Select[aria-invalid=true], .greese-Select[data-invalid],\n .greese-Textarea[aria-invalid=true], .greese-Textarea[data-invalid] {\n --greese-shape-ring: var(--greese-color-negative);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Input,\n .greese-Select,\n .greese-Textarea {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Input::after,\n .greese-Select::after,\n .greese-Textarea::after {\n display: none;\n }\n }\n .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-border-strong);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-OtpField-slot::before {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-OtpField[data-invalid] .greese-OtpField-slot {\n --greese-shape-ring: var(--greese-color-negative);\n }\n .greese-OtpField-slot.greese-OtpField-slot--active {\n --greese-shape-ring: var(--greese-color-focus-ring);\n --greese-shape-border: 2px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-OtpField-slot {\n transition: box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-OtpField-slot {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-OtpField-slot::before {\n display: none;\n }\n }\n .greese-Segment {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Segment::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Segment:has(:checked) {\n --greese-shape-ring: var(--greese-segment-current-ring, transparent);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Segment {\n transition: background-color var(--greese-duration-fast) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Segment {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Segment::after {\n display: none;\n }\n }\n .greese-SegmentedControl-track {\n --greese-shape-ring: var(--greese-color-border);\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-SegmentedControl-track::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-SegmentedControl-track {\n transition: --greese-shape-t var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-SegmentedControl-track {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-SegmentedControl-track::after {\n display: none;\n }\n }\n .greese-Tab {\n --greese-shape-ring: transparent;\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tab::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Tab[aria-selected=true] {\n --greese-shape-ring: var(--greese-tab-current-ring, transparent);\n --greese-shape-border: 1.5px;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: color var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard), --greese-shape-r var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-border var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-ring var(--greese-duration-normal) var(--greese-easing-standard), --greese-shape-bleed 0s linear;\n }\n }\n @media (forced-colors: active) {\n .greese-Tab {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tab::after {\n display: none;\n }\n }\n .greese-Toast {\n --greese-shape-ring: color-mix(in oklab, var(--greese-toast-edge) 45%, var(--greese-color-border-strong));\n position: relative;\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Toast::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n .greese-Toast {\n box-shadow: inset 3px 0 0 var(--greese-toast-edge);\n }\n .greese-Toast:dir(rtl) {\n box-shadow: inset -3px 0 0 var(--greese-toast-edge);\n }\n @media (forced-colors: active) {\n .greese-Toast {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Toast::after {\n display: none;\n }\n }\n .greese-Tooltip {\n --greese-shape-ring: var(--greese-tooltip-border, transparent);\n isolation: isolate;\n border-color: transparent;\n clip-path: var(--greese-shape-clip) padding-box;\n }\n .greese-Tooltip::after {\n position: absolute;\n inset: 0;\n inline-size: auto;\n block-size: auto;\n translate: none;\n z-index: 1;\n pointer-events: none;\n content: \"\";\n background: var(--greese-shape-ring);\n clip-path: var(--greese-shape-ring-clip);\n }\n @media (forced-colors: active) {\n .greese-Tooltip {\n clip-path: none;\n border-color: CanvasText;\n }\n .greese-Tooltip::after {\n display: none;\n }\n }\n .greese-shape-ticket-control,\n .greese-Button {\n --greese-shape-t: 10px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-t) + 0.847 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.014 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-t) + 0.847 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-t)) 0, 100% 50%, calc(100% - var(--greese-shape-t)) 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-t) - 0.847 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.014 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-t) - 0.847 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-control:dir(rtl),\n .greese-Button:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-t) - 0.847 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.014 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-t) - 0.847 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-t)) 100%, 0 50%, calc(var(--greese-shape-t)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-t) + 0.847 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.014 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-t) + 0.847 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Button.greese-Button--size-sm {\n --greese-shape-t: 7px;\n }\n .greese-Button.greese-Button--size-xs {\n --greese-shape-t: 5px;\n }\n .greese-Button.greese-IconButton {\n --greese-shape-t: 5px;\n }\n @media (hover: hover) {\n .greese-shape-ticket-control:hover,\n .greese-Button:hover {\n --greese-shape-t: 15px;\n }\n .greese-Button.greese-Button--size-sm:hover {\n --greese-shape-t: 10.5px;\n }\n .greese-Button.greese-Button--size-xs:hover,\n .greese-Button.greese-IconButton:hover {\n --greese-shape-t: 7.5px;\n }\n }\n .greese-shape-ticket-control:active,\n .greese-Button:active {\n --greese-shape-t: 6px;\n }\n .greese-Button.greese-Button--size-sm:active {\n --greese-shape-t: 4.2px;\n }\n .greese-Button.greese-Button--size-xs:active,\n .greese-Button.greese-IconButton:active {\n --greese-shape-t: 3px;\n }\n .greese-shape-ticket-control:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Button:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-field,\n .greese-Input,\n .greese-OtpField-slot,\n .greese-Select,\n .greese-Textarea {\n --greese-shape-r: 5px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-Input:has(:focus-visible),\n .greese-Select:has(:focus-visible),\n .greese-Textarea:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ticket-field:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-container,\n .greese-AccordionItem > .greese-Collapsible-content,\n .greese-Card,\n .greese-Dialog,\n .greese-Menu,\n .greese-Popover,\n .greese-Tile,\n .greese-Toast {\n --greese-shape-r: 12px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n @media (hover: hover) {\n .greese-shape-ticket-container:hover,\n .greese-Card.greese-Card--interactive:hover {\n --greese-shape-r: 16px;\n }\n }\n .greese-shape-ticket-container:focus-visible,\n .greese-AccordionItem > .greese-Collapsible-content:focus-visible,\n .greese-Card:focus-visible,\n .greese-Tile:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Dialog:focus-visible,\n .greese-Menu:focus-visible,\n .greese-Popover:focus-visible,\n .greese-Toast:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-small,\n .greese-Alert,\n .greese-Collapsible-trigger,\n .greese-Tooltip {\n --greese-shape-r: 7px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-small:focus-visible,\n .greese-Alert:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Collapsible-trigger:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Tooltip:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-indicator,\n .greese-Badge,\n .greese-Chip,\n .greese-Segment,\n .greese-SegmentedControl-track {\n --greese-shape-t: 6px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-t) + 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + 1.002 * var(--greese-shape-bleed)) 50%, calc(100% - var(--greese-shape-t) + 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, calc(100% - var(--greese-shape-t)) 0, 100% 50%, calc(100% - var(--greese-shape-t)) 100%, 0 100%, 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-t) - 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - 1.002 * var(--greese-shape-border)) 50%, calc(100% - var(--greese-shape-t) - 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-indicator:dir(rtl),\n .greese-Badge:dir(rtl),\n .greese-Chip:dir(rtl),\n .greese-Segment:dir(rtl),\n .greese-SegmentedControl-track:dir(rtl) {\n --greese-shape-clip: polygon(calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-t) - 0.936 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * 1.002 * var(--greese-shape-bleed)) 50%, calc(var(--greese-shape-t) - 0.936 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 100% 100%, calc(var(--greese-shape-t)) 100%, 0 50%, calc(var(--greese-shape-t)) 0, 100% 0, 100% 100%, calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-t) + 0.936 * var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(1.002 * var(--greese-shape-border)) 50%, calc(var(--greese-shape-t) + 0.936 * var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)));\n }\n .greese-Segment:has(:focus-visible) {\n --greese-shape-border: 3px;\n --greese-shape-ring: var(--greese-color-focus-ring);\n outline-color: transparent;\n }\n .greese-shape-ticket-indicator:focus-visible,\n .greese-Badge:focus-visible,\n .greese-SegmentedControl-track:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Chip:focus-visible {\n --greese-shape-t: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-shape-ticket-mark,\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar),\n .greese-Status:not(.greese-Status--pulse) {\n --greese-shape-n: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% - var(--greese-shape-n) + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)), calc(var(--greese-shape-n) - var(--greese-shape-bleed)) calc(var(--greese-shape-n) - var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, calc(var(--greese-shape-n)) 0, calc(100% - var(--greese-shape-n)) 0, calc(100% - var(--greese-shape-n)) calc(var(--greese-shape-n)), 100% calc(var(--greese-shape-n)), 100% calc(100% - var(--greese-shape-n)), calc(100% - var(--greese-shape-n)) calc(100% - var(--greese-shape-n)), calc(100% - var(--greese-shape-n)) 100%, calc(var(--greese-shape-n)) 100%, calc(var(--greese-shape-n)) calc(100% - var(--greese-shape-n)), 0 calc(100% - var(--greese-shape-n)), 0 calc(var(--greese-shape-n)), calc(var(--greese-shape-n)) calc(var(--greese-shape-n)), calc(var(--greese-shape-n)) 0, calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-n) - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(var(--greese-shape-n) + var(--greese-shape-border)), calc(100% - var(--greese-shape-n) - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-n) + var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-mark:focus-visible {\n --greese-shape-n: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n .greese-Avatar:not(.greese-AvatarGroup-item > .greese-Avatar):focus-visible,\n .greese-Status:not(.greese-Status--pulse):focus-visible {\n --greese-shape-n: 0px;\n --greese-shape-bleed: 8px;\n }\n .greese-shape-ticket-tab,\n .greese-Tab {\n --greese-shape-r: 4px;\n --greese-shape-border: 1px;\n --greese-shape-clip: polygon(calc(-1 * var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(-1 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(100% - var(--greese-shape-r) + 1.02 * var(--greese-shape-bleed)) 50%, calc(100% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(100% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(100% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(100% + var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(100% + var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% + var(--greese-shape-r) - 0.821 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% + 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% + 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)), calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% + 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)), calc(var(--greese-shape-r) - 1.02 * var(--greese-shape-bleed)) 50%, calc(0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-bleed)) calc(50% - 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-bleed)), calc(0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-bleed)) calc(50% - 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-bleed)), calc(0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-bleed)) calc(50% - 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-bleed)), calc(-1 * var(--greese-shape-bleed)) calc(50% - var(--greese-shape-r) + 0.821 * var(--greese-shape-bleed)));\n --greese-shape-ring-clip: polygon(evenodd, 0 0, 100% 0, 100% calc(50% - var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(100% - 0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(100% - var(--greese-shape-r)) 50%, calc(100% - 0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(100% - 0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(100% - 0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), 100% calc(50% + var(--greese-shape-r)), 100% 100%, 0 100%, 0 calc(50% + var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% + 0.924 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% + 0.707 * var(--greese-shape-r)), calc(0.924 * var(--greese-shape-r)) calc(50% + 0.383 * var(--greese-shape-r)), calc(var(--greese-shape-r)) 50%, calc(0.924 * var(--greese-shape-r)) calc(50% - 0.383 * var(--greese-shape-r)), calc(0.707 * var(--greese-shape-r)) calc(50% - 0.707 * var(--greese-shape-r)), calc(0.383 * var(--greese-shape-r)) calc(50% - 0.924 * var(--greese-shape-r)), 0 calc(50% - var(--greese-shape-r)), 0 0, calc(var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(var(--greese-shape-r) + 1.02 * var(--greese-shape-border)) 50%, calc(0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(100% - var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% + var(--greese-shape-r) + 0.821 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% + 0.924 * var(--greese-shape-r) + 0.942 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% + 0.707 * var(--greese-shape-r) + 0.721 * var(--greese-shape-border)), calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% + 0.383 * var(--greese-shape-r) + 0.39 * var(--greese-shape-border)), calc(100% - var(--greese-shape-r) - 1.02 * var(--greese-shape-border)) 50%, calc(100% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)) calc(50% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)), calc(100% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)) calc(50% - 0.707 * var(--greese-shape-r) - 0.721 * var(--greese-shape-border)), calc(100% - 0.383 * var(--greese-shape-r) - 0.39 * var(--greese-shape-border)) calc(50% - 0.924 * var(--greese-shape-r) - 0.942 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(50% - var(--greese-shape-r) - 0.821 * var(--greese-shape-border)), calc(100% - var(--greese-shape-border)) calc(var(--greese-shape-border)), calc(var(--greese-shape-border)) calc(var(--greese-shape-border)));\n }\n .greese-shape-ticket-tab:focus-visible {\n --greese-shape-r: 0px;\n --greese-shape-bleed: 8px;\n transition-delay: 0s, 0s, 0s, var(--greese-duration-normal);\n }\n}"},{"id":"tilt","description":"Tilt: real perspective. Hovered, buttons and chips lean back toward you from their lower edge and cards and tiles turn and lift off the page; pressed, they push into it. The current tab stands up off its list. Softer corners than the library’s. A greese ui shape theme (ADR 0025): radii, and components outlined with one clip and one border ring each (ADR 0024), in @layer greese.overrides. It sets no colors and no motion, so it goes with any color or motion theme. Compile it with Sass's package importer, after greese ui's styles, or use the compiled tilt.css. Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).","scss":"/**\n * Tilt: real perspective. Hovered, buttons and chips lean back toward you from their lower edge and cards and tiles turn and lift off the page; pressed, they push into it. The current tab stands up off its list. Softer corners than the library’s.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled tilt.css.\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.tokens((\n corner: (\n control: \"var(--greese-radius-lg)\",\n field: \"var(--greese-radius-md)\",\n surface: \"var(--greese-radius-lg)\",\n panel: \"var(--greese-radius-lg)\",\n inset: \"var(--greese-radius-md)\",\n pill: \"var(--greese-radius-pill)\",\n round: \"var(--greese-radius-round)\",\n ),\n));\n\n@include greese.component(Accordion) {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n}\n\n@include greese.component(AccordionItem) {\n border-block-end: 0;\n}\n\n@include greese.component(Button) {\n transform-origin: 50% 100%;\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-normal) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n\n @media (hover: hover) {\n &:hover:not(:disabled, [aria-disabled='true']) {\n transform: perspective(24rem) rotateX(18deg) translateZ(0.25rem);\n }\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: perspective(24rem) translateZ(-0.75rem);\n }\n }\n}\n\n@include greese.component(Card) {\n &.greese-Card--interactive {\n transform-origin: 50% 50%;\n \n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-normal) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n \n @media (hover: hover) {\n &:hover:not(:disabled, [aria-disabled='true']) {\n transform: perspective(60rem) rotateX(5deg) rotateY(-7deg) translateZ(1rem);\n }\n }\n \n &:active:not(:disabled, [aria-disabled='true']) {\n transform: perspective(60rem) translateZ(-0.5rem);\n }\n }\n }\n}\n\n@include greese.component(Chip) {\n transform-origin: 50% 100%;\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-normal) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n\n @media (hover: hover) {\n &:hover:not(:disabled, [aria-disabled='true']) {\n transform: perspective(20rem) rotateX(18deg);\n }\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: perspective(20rem) translateZ(-0.5rem);\n }\n }\n}\n\n@include greese.component(Collapsible) {\n > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n\n @media (hover: hover) {\n &:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n }\n\n &[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n\n > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n\n@include greese.component(Tab) {\n transform-origin: 50% 100%;\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-normal) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-fast) var(--greese-easing-standard);\n\n &[aria-selected='true'] {\n transform: perspective(16rem) rotateX(-14deg);\n }\n }\n}\n\n@include greese.component(Tile) {\n transform-origin: 50% 50%;\n\n @include greese.motion-safe {\n transition:\n transform var(--greese-duration-normal) var(--greese-easing-standard),\n background-color var(--greese-duration-fast) var(--greese-easing-standard),\n border-color var(--greese-duration-fast) var(--greese-easing-standard),\n box-shadow var(--greese-duration-normal) var(--greese-easing-standard),\n color var(--greese-duration-fast) var(--greese-easing-standard);\n\n @media (hover: hover) {\n &:hover:not(:disabled, [aria-disabled='true']) {\n transform: perspective(50rem) rotateX(6deg) rotateY(-8deg) translateZ(0.75rem);\n }\n }\n\n &:active:not(:disabled, [aria-disabled='true']) {\n transform: perspective(50rem) translateZ(-0.5rem);\n }\n }\n}\n","css":"/**\n * Tilt: real perspective. Hovered, buttons and chips lean back toward you from their lower edge and cards and tiles turn and lift off the page; pressed, they push into it. The current tab stands up off its list. Softer corners than the library’s.\n *\n * A greese ui shape theme (ADR 0025): radii, and components outlined with one\n * clip and one border ring each (ADR 0024), in @layer greese.overrides. It\n * sets no colors and no motion, so it goes with any color or motion theme.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/tilt.css'\n *\n * Generated from apps/site/src/studio/shapes.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.theme {\n :root {\n --greese-corner-control: var(--greese-radius-lg);\n --greese-corner-field: var(--greese-radius-md);\n --greese-corner-surface: var(--greese-radius-lg);\n --greese-corner-panel: var(--greese-radius-lg);\n --greese-corner-inset: var(--greese-radius-md);\n --greese-corner-pill: var(--greese-radius-pill);\n --greese-corner-round: var(--greese-radius-round);\n }\n}\n@layer greese.overrides {\n .greese-Accordion {\n display: grid;\n gap: var(--greese-space-2);\n border-block-start: 0;\n }\n}\n@layer greese.overrides {\n .greese-AccordionItem {\n border-block-end: 0;\n }\n}\n@layer greese.overrides {\n .greese-Button {\n transform-origin: 50% 100%;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button {\n transition: transform var(--greese-duration-normal) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-normal) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n @media (prefers-reduced-motion: no-preference) and (hover: hover) {\n .greese-Button:hover:not(:disabled, [aria-disabled=true]) {\n transform: perspective(24rem) rotateX(18deg) translateZ(0.25rem);\n }\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Button:active:not(:disabled, [aria-disabled=true]) {\n transform: perspective(24rem) translateZ(-0.75rem);\n }\n }\n}\n@layer greese.overrides {\n .greese-Card.greese-Card--interactive {\n transform-origin: 50% 50%;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card.greese-Card--interactive {\n transition: transform var(--greese-duration-normal) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-normal) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n @media (prefers-reduced-motion: no-preference) and (hover: hover) {\n .greese-Card.greese-Card--interactive:hover:not(:disabled, [aria-disabled=true]) {\n transform: perspective(60rem) rotateX(5deg) rotateY(-7deg) translateZ(1rem);\n }\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Card.greese-Card--interactive:active:not(:disabled, [aria-disabled=true]) {\n transform: perspective(60rem) translateZ(-0.5rem);\n }\n }\n}\n@layer greese.overrides {\n .greese-Chip {\n transform-origin: 50% 100%;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip {\n transition: transform var(--greese-duration-normal) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-normal) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n @media (prefers-reduced-motion: no-preference) and (hover: hover) {\n .greese-Chip:hover:not(:disabled, [aria-disabled=true]) {\n transform: perspective(20rem) rotateX(18deg);\n }\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Chip:active:not(:disabled, [aria-disabled=true]) {\n transform: perspective(20rem) translateZ(-0.5rem);\n }\n }\n}\n@layer greese.overrides {\n .greese-Collapsible > .greese-Collapsible-trigger {\n padding-inline: var(--greese-space-4);\n background-color: var(--greese-color-surface);\n border: 1px solid var(--greese-collapsible-border, var(--greese-color-border));\n border-radius: var(--greese-corner-control);\n }\n @media (hover: hover) {\n .greese-Collapsible > .greese-Collapsible-trigger:hover {\n background-color: color-mix(in oklab, var(--greese-color-fg) 5%, var(--greese-color-surface));\n }\n }\n .greese-Collapsible[open] > .greese-Collapsible-trigger {\n margin-block-end: var(--greese-space-2);\n }\n .greese-Collapsible > .greese-Collapsible-content {\n padding-inline: var(--greese-space-4);\n }\n}\n@layer greese.overrides {\n .greese-Tab {\n transform-origin: 50% 100%;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tab {\n transition: transform var(--greese-duration-normal) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-fast) var(--greese-easing-standard);\n }\n .greese-Tab[aria-selected=true] {\n transform: perspective(16rem) rotateX(-14deg);\n }\n }\n}\n@layer greese.overrides {\n .greese-Tile {\n transform-origin: 50% 50%;\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tile {\n transition: transform var(--greese-duration-normal) var(--greese-easing-standard), background-color var(--greese-duration-fast) var(--greese-easing-standard), border-color var(--greese-duration-fast) var(--greese-easing-standard), box-shadow var(--greese-duration-normal) var(--greese-easing-standard), color var(--greese-duration-fast) var(--greese-easing-standard);\n }\n }\n @media (prefers-reduced-motion: no-preference) and (hover: hover) {\n .greese-Tile:hover:not(:disabled, [aria-disabled=true]) {\n transform: perspective(50rem) rotateX(6deg) rotateY(-8deg) translateZ(0.75rem);\n }\n }\n @media (prefers-reduced-motion: no-preference) {\n .greese-Tile:active:not(:disabled, [aria-disabled=true]) {\n transform: perspective(50rem) translateZ(-0.5rem);\n }\n }\n}"},{"id":"wipe","description":"Wipe: things are revealed in place rather than moved. Reveals wipe up, panels and toasts open from the middle, table rows wipe across, menus wipe down from their trigger and back up, tooltips open and close from the middle, and dialogs open and close as a circle. Pages change along one edge, the whole page at once: the next wipes in as the last wipes away, from the right going forward and from the left going back. A greese ui motion theme (ADR 0025): it assigns the motion roles (which built-in effect plays where, and which duration and easing it takes) and paces every entrance. It redefines no effect and no token, and sets no colors and no shapes, so it goes with any of those. Compile it with Sass's package importer, after greese ui's styles, or use the compiled wipe.css. Generated from apps/site/src/studio/motions.ts (npm run themes -w site).","scss":"/**\n * Wipe: things are revealed in place rather than moved. Reveals wipe up, panels and toasts open from the middle, table rows wipe across, menus wipe down from their trigger and back up, tooltips open and close from the middle, and dialogs open and close as a circle. Pages change along one edge, the whole page at once: the next wipes in as the last wipes away, from the right going forward and from the left going back.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Compile it with Sass's package importer, after greese ui's\n * styles, or use the compiled wipe.css.\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n// Generated by greese ui Theme Studio from greese-theme.json. Edit it there, or in\n// the studio (npm run studio); changes made here are overwritten.\n@use 'pkg:@greese/ui/scss/kit' as greese;\n\n@include greese.motion-defaults((\n duration: \"0.6s\",\n distance: \"0.75rem\",\n stagger: \"0.06s\",\n theme: \"wipe-up\",\n content: \"wipe-open-x\",\n rows: \"wipe-right\",\n toast: \"wipe-open-x\",\n dialog: \"iris-in\",\n dialog-exit: \"iris-out\",\n popover: \"wipe-down\",\n popover-exit: \"wipe-out-up\",\n tooltip: \"wipe-open-x\",\n tooltip-exit: \"wipe-close-x\",\n content-duration: \"normal\",\n rows-duration: \"slow\",\n overlay-duration: \"normal\",\n toast-duration: \"normal\",\n exit-duration: \"normal\",\n enter-ease: \"cubic-bezier(0.65, 0, 0.35, 1)\",\n exit-ease: \"cubic-bezier(0.65, 0, 0.35, 1)\",\n page: \"wipe-left\",\n page-exit: \"wipe-out-left\",\n page-back: \"wipe-right\",\n page-back-exit: \"wipe-out-right\",\n page-mode: \"snapshot\",\n page-duration: \"0.6s\",\n page-ease: \"cubic-bezier(0.65, 0, 0.35, 1)\",\n page-stagger: \"0.06s\",\n));\n","css":"/**\n * Wipe: things are revealed in place rather than moved. Reveals wipe up, panels and toasts open from the middle, table rows wipe across, menus wipe down from their trigger and back up, tooltips open and close from the middle, and dialogs open and close as a circle. Pages change along one edge, the whole page at once: the next wipes in as the last wipes away, from the right going forward and from the left going back.\n *\n * A greese ui motion theme (ADR 0025): it assigns the motion roles (which\n * built-in effect plays where, and which duration and easing it takes) and\n * paces every entrance. It redefines no effect and no token, and sets no\n * colors and no shapes, so it goes with any of those.\n * Load it after greese ui's styles:\n *\n * import '@greese/ui/themes/wipe.css'\n *\n * Generated from apps/site/src/studio/motions.ts (npm run themes -w site).\n */\n@layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;\n@layer greese.overrides {\n :root {\n --greese-motion-duration: 0.6s;\n --greese-motion-distance: 0.75rem;\n --greese-motion-stagger: 0.06s;\n --greese-motion-theme: greese-wipe-up;\n --greese-motion-content: greese-wipe-open-x;\n --greese-motion-rows: greese-wipe-right;\n --greese-motion-toast: greese-wipe-open-x;\n --greese-motion-dialog: greese-iris-in;\n --greese-motion-dialog-exit-translate: 0px 0px;\n --greese-motion-dialog-exit-scale: 1;\n --greese-motion-dialog-exit-opacity: 1;\n --greese-motion-dialog-exit-mask-image: radial-gradient(closest-side, black 98%, transparent);\n --greese-motion-dialog-exit-mask-size: 0% 0%;\n --greese-motion-dialog-exit-mask-repeat: no-repeat;\n --greese-motion-dialog-exit-mask-position: 50% 50%;\n --greese-motion-dialog-exit-transform: none;\n --greese-motion-dialog-exit-mask-from: 142% 142%;\n --greese-motion-popover: greese-wipe-down;\n --greese-motion-popover-exit-translate: 0px 0px;\n --greese-motion-popover-exit-scale: 1;\n --greese-motion-popover-exit-opacity: 1;\n --greese-motion-popover-exit-mask-image: linear-gradient(black, black);\n --greese-motion-popover-exit-mask-size: 100% 0%;\n --greese-motion-popover-exit-mask-repeat: no-repeat;\n --greese-motion-popover-exit-mask-position: 50% 0%;\n --greese-motion-popover-exit-transform: none;\n --greese-motion-popover-exit-mask-from: 100% 100%;\n --greese-motion-tooltip: greese-wipe-open-x;\n --greese-motion-tooltip-exit-translate: 0px 0px;\n --greese-motion-tooltip-exit-scale: 1;\n --greese-motion-tooltip-exit-opacity: 1;\n --greese-motion-tooltip-exit-mask-image: linear-gradient(black, black);\n --greese-motion-tooltip-exit-mask-size: 0% 100%;\n --greese-motion-tooltip-exit-mask-repeat: no-repeat;\n --greese-motion-tooltip-exit-mask-position: 50% 50%;\n --greese-motion-tooltip-exit-transform: none;\n --greese-motion-tooltip-exit-mask-from: 100% 100%;\n --greese-motion-content-duration: var(--greese-duration-normal);\n --greese-motion-rows-duration: var(--greese-duration-slow);\n --greese-motion-overlay-duration: var(--greese-duration-normal);\n --greese-motion-toast-duration: var(--greese-duration-normal);\n --greese-motion-exit-duration: var(--greese-duration-normal);\n --greese-motion-enter-ease: cubic-bezier(0.65, 0, 0.35, 1);\n --greese-motion-exit-ease: cubic-bezier(0.65, 0, 0.35, 1);\n --greese-motion-page: greese-wipe-left;\n --greese-motion-page-exit: greese-wipe-out-left;\n --greese-motion-page-back: greese-wipe-right;\n --greese-motion-page-back-exit: greese-wipe-out-right;\n --greese-motion-page-mode: snapshot;\n --greese-motion-page-duration: 0.6s;\n --greese-motion-page-ease: cubic-bezier(0.65, 0, 0.35, 1);\n --greese-motion-page-stagger: 0.06s;\n }\n}\n@layer greese.utilities {\n @media (prefers-reduced-motion: no-preference) {\n @keyframes greese-wipe-up {\n from {\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n to {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 100%;\n }\n }\n @keyframes greese-wipe-open-x {\n from {\n mask-size: 0% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 50%;\n }\n to {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 50%;\n }\n }\n @keyframes greese-wipe-right {\n from {\n mask-size: 0% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 0% 50%;\n }\n to {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 0% 50%;\n }\n }\n @keyframes greese-iris-in {\n from {\n mask-size: 0% 0%;\n mask-image: radial-gradient(closest-side, black 98%, transparent);\n mask-repeat: no-repeat;\n mask-position: 50% 50%;\n }\n to {\n mask-size: 142% 142%;\n mask-image: radial-gradient(closest-side, black 98%, transparent);\n mask-repeat: no-repeat;\n mask-position: 50% 50%;\n }\n }\n @keyframes greese-wipe-down {\n from {\n mask-size: 100% 0%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n to {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 50% 0%;\n }\n }\n @keyframes greese-wipe-left {\n from {\n mask-size: 0% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 100% 50%;\n }\n to {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 100% 50%;\n }\n }\n @keyframes greese-wipe-out-left {\n from {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 0% 50%;\n }\n to {\n mask-size: 0% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 0% 50%;\n }\n }\n @keyframes greese-wipe-out-right {\n from {\n mask-size: 100% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 100% 50%;\n }\n to {\n mask-size: 0% 100%;\n mask-image: linear-gradient(black, black);\n mask-repeat: no-repeat;\n mask-position: 100% 50%;\n }\n }\n }\n}"}],"templates":[{"id":"admin","description":"Admin dashboard: an app shell with a sidebar (off-canvas on phones), a toolbar with search and notifications, KPI stats, sales by channel, service status, and an orders table with status tabs and pagination.","source":"/**\n * Admin dashboard: an app shell with a sidebar (off-canvas on phones), a\n * toolbar with search and notifications, KPI stats, sales by channel, service\n * status, and an orders table with status tabs and pagination.\n */\nimport { useState, type JSX } from 'react'\nimport {\n AppBar,\n Avatar,\n AvatarGroup,\n Badge,\n Button,\n Card,\n Grid,\n Heading,\n IconButton,\n Indicator,\n Pagination,\n Progress,\n Sidebar,\n SidebarLayout,\n SidebarTrigger,\n Spacer,\n Stack,\n Stat,\n StatGroup,\n Status,\n Tab,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeaderCell,\n TableRow,\n TabList,\n Tabs,\n Text,\n TextField,\n} from '@greese/react'\nimport {\n BellIcon,\n CartIcon,\n DocumentIcon,\n HomeIcon,\n LayersIcon,\n SearchIcon,\n SlidersIcon,\n UserIcon,\n} from '@greese/icons'\n\nconst nav = [\n { label: 'Overview', icon: <HomeIcon /> },\n { label: 'Orders', icon: <CartIcon /> },\n { label: 'Customers', icon: <UserIcon /> },\n { label: 'Products', icon: <LayersIcon /> },\n { label: 'Reports', icon: <DocumentIcon /> },\n { label: 'Settings', icon: <SlidersIcon /> },\n]\n\nconst channels = [\n { name: 'Online store', share: 58 },\n { name: 'Marketplace', share: 24 },\n { name: 'Retail', share: 12 },\n { name: 'Wholesale', share: 6 },\n]\n\nconst services = [\n { name: 'Storefront', tone: 'positive', state: 'Operational' },\n { name: 'Payments', tone: 'positive', state: 'Operational' },\n { name: 'Search index', tone: 'warning', state: 'Degraded' },\n { name: 'Email delivery', tone: 'positive', state: 'Operational' },\n] as const\n\ntype OrderState = 'Paid' | 'Pending' | 'Shipped' | 'Refunded'\nconst orders: Array<{\n id: string\n customer: string\n items: number\n total: number\n state: OrderState\n}> = [\n { id: '#10482', customer: 'Maya Chen', items: 3, total: 142.8, state: 'Paid' },\n { id: '#10481', customer: 'Jonas Weber', items: 1, total: 39, state: 'Pending' },\n { id: '#10480', customer: 'Aiyana Brooks', items: 5, total: 318.45, state: 'Shipped' },\n { id: '#10479', customer: 'Tomás Ruiz', items: 2, total: 76.2, state: 'Shipped' },\n { id: '#10478', customer: 'Priya Natarajan', items: 1, total: 54, state: 'Refunded' },\n { id: '#10477', customer: 'Lena Novak', items: 4, total: 201.9, state: 'Pending' },\n]\n\nconst stateTone = {\n Paid: 'primary',\n Pending: 'warning',\n Shipped: 'positive',\n Refunded: 'neutral',\n} as const\n\nconst money = (n: number) =>\n n.toLocaleString('en-US', { style: 'currency', currency: 'USD' })\n\nexport const Admin = (): JSX.Element => {\n const [tab, setTab] = useState('all')\n const [page, setPage] = useState(1)\n const [current, setCurrent] = useState('Overview')\n const shown = orders.filter((o) => tab === 'all' || o.state.toLowerCase() === tab)\n\n return (\n <SidebarLayout breakpoint=\"md\" className=\"tpl-shell\">\n <Sidebar label=\"Admin navigation\">\n <Stack gap={1} p={3}>\n <Text weight=\"bold\" className=\"tpl-brand\">\n Northwind Admin\n </Text>\n {nav.map((item) => (\n <Button\n key={item.label}\n variant={current === item.label ? 'soft' : 'ghost'}\n tone={current === item.label ? 'primary' : 'neutral'}\n startIcon={item.icon}\n className=\"tpl-nav-button\"\n aria-current={current === item.label ? 'page' : undefined}\n onClick={() => setCurrent(item.label)}\n >\n {item.label}\n </Button>\n ))}\n </Stack>\n </Sidebar>\n\n <div className=\"tpl-main\">\n <AppBar>\n <Stack direction=\"row\" align=\"center\" gap={2} px={4} py={2}>\n <SidebarTrigger />\n <TextField\n label=\"Search\"\n hideLabel\n size=\"sm\"\n type=\"search\"\n placeholder=\"Search orders, customers…\"\n startAdornment={<SearchIcon />}\n />\n <Spacer />\n <Indicator\n content={\n <Badge tone=\"negative\" variant=\"solid\">\n 3\n </Badge>\n }\n >\n <IconButton label=\"Notifications, 3 unread\" size=\"sm\">\n <BellIcon />\n </IconButton>\n </Indicator>\n <Avatar name=\"Sam Okafor\" size=\"sm\" />\n </Stack>\n </AppBar>\n\n <Stack gap={5} p={{ xs: 4, md: 5 }} greese={{ enter: 'theme', stagger: 0.06 }}>\n <Stack direction=\"row\" justify=\"between\" align=\"end\" gap={3} wrap=\"wrap\">\n <Heading level={1} variant=\"h3\">\n {current}\n </Heading>\n <AvatarGroup max={3} size=\"sm\">\n <Avatar name=\"Sam Okafor\" />\n <Avatar name=\"Rina Patel\" />\n <Avatar name=\"Luis Ortega\" />\n <Avatar name=\"Ada Kim\" />\n <Avatar name=\"Ben Fox\" />\n </AvatarGroup>\n </Stack>\n\n <Card variant=\"outline\">\n <StatGroup>\n <Stat\n label=\"Revenue\"\n value=\"$48,210\"\n description=\"up 12% on last week\"\n tone=\"positive\"\n />\n <Stat label=\"Orders\" value=\"1,204\" description=\"up 3%\" tone=\"positive\" />\n <Stat label=\"New customers\" value=\"312\" description=\"flat\" tone=\"muted\" />\n <Stat\n label=\"Refund rate\"\n value=\"1.8%\"\n description=\"up 0.4 points\"\n tone=\"negative\"\n />\n </StatGroup>\n </Card>\n\n <Grid container columns={12} gap={4}>\n <Grid size={{ xs: 12, lg: 7 }}>\n <Card variant=\"outline\">\n <Heading level={2} variant=\"h5\">\n Sales by channel\n </Heading>\n <Stack gap={4}>\n {channels.map((c) => (\n <Stack key={c.name} gap={1}>\n <Stack direction=\"row\" justify=\"between\">\n <Text variant=\"p3\">{c.name}</Text>\n <Text variant=\"p3\" weight=\"semibold\">\n {c.share}%\n </Text>\n </Stack>\n <Progress\n value={c.share}\n size=\"sm\"\n aria-label={`${c.name}: ${c.share}%`}\n />\n </Stack>\n ))}\n </Stack>\n </Card>\n </Grid>\n <Grid size={{ xs: 12, lg: 5 }}>\n <Card variant=\"outline\">\n <Heading level={2} variant=\"h5\">\n Services\n </Heading>\n <Stack gap={3}>\n {services.map((s) => (\n <Stack key={s.name} direction=\"row\" justify=\"between\" align=\"center\">\n <Text variant=\"p3\">{s.name}</Text>\n <Status\n tone={s.tone}\n label={s.state}\n pulse={s.tone !== 'positive'}\n />\n </Stack>\n ))}\n </Stack>\n </Card>\n </Grid>\n </Grid>\n\n <Card variant=\"outline\">\n <Stack direction=\"row\" justify=\"between\" align=\"center\" gap={3} wrap=\"wrap\">\n <Heading level={2} variant=\"h5\">\n Orders\n </Heading>\n <Button size=\"sm\" variant=\"soft\" tone=\"neutral\">\n Export CSV\n </Button>\n </Stack>\n <Tabs value={tab} onValueChange={setTab}>\n <TabList aria-label=\"Order status\">\n <Tab value=\"all\">All</Tab>\n <Tab value=\"pending\">Pending</Tab>\n <Tab value=\"shipped\">Shipped</Tab>\n <Tab value=\"refunded\">Refunded</Tab>\n </TabList>\n </Tabs>\n <Table caption=\"Orders\" hideCaption stackBelow=\"sm\" hoverable>\n <TableHead>\n <TableRow>\n <TableHeaderCell>Order</TableHeaderCell>\n <TableHeaderCell>Customer</TableHeaderCell>\n <TableHeaderCell align=\"end\">Items</TableHeaderCell>\n <TableHeaderCell align=\"end\">Total</TableHeaderCell>\n <TableHeaderCell>Status</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {shown.map((o) => (\n <TableRow key={o.id}>\n <TableCell label=\"Order\">\n <Text weight=\"semibold\">{o.id}</Text>\n </TableCell>\n <TableCell label=\"Customer\">{o.customer}</TableCell>\n <TableCell label=\"Items\" align=\"end\">\n {o.items}\n </TableCell>\n <TableCell label=\"Total\" align=\"end\">\n {money(o.total)}\n </TableCell>\n <TableCell label=\"Status\">\n <Badge tone={stateTone[o.state]}>{o.state}</Badge>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n <Pagination\n count={8}\n page={page}\n onPageChange={setPage}\n label=\"Orders pages\"\n />\n </Card>\n </Stack>\n </div>\n </SidebarLayout>\n )\n}\n"},{"id":"blog","description":"Blog and newsletter: a masthead, topic filters, a featured story, a grid of posts, a subscribe form that confirms with a toast, the most-read list and pagination. Cover art is CSS gradients, so there are no images to load.","source":"/**\n * Blog and newsletter: a masthead, topic filters, a featured story, a grid of\n * posts, a subscribe form that confirms with a toast, the most-read list and\n * pagination. Cover art is CSS gradients, so there are no images to load.\n */\nimport { useState, type CSSProperties, type FormEvent, type JSX } from 'react'\nimport {\n Avatar,\n Badge,\n Button,\n Card,\n Chip,\n Container,\n Grid,\n Heading,\n Link,\n List,\n ListItem,\n Pagination,\n Stack,\n Text,\n TextField,\n toast,\n} from '@greese/react'\nimport { ArrowRightIcon, HeartIcon } from '@greese/icons'\n\ninterface Post {\n id: number\n title: string\n excerpt: string\n topic: Topic\n author: string\n minutes: number\n date: string\n /** The cover's hue, in degrees. */\n hue: number\n}\n\nconst TOPICS = ['Design', 'Engineering', 'Culture', 'Product'] as const\ntype Topic = (typeof TOPICS)[number]\n\nconst POSTS: Post[] = [\n {\n id: 1,\n title: 'The case for boring CSS',\n excerpt:\n 'Cascade layers, custom properties and a little restraint go further than any runtime.',\n topic: 'Engineering',\n author: 'Ada Kim',\n minutes: 7,\n date: 'Oct 21',\n hue: 210,\n },\n {\n id: 2,\n title: 'Designing for the thumb',\n excerpt:\n 'Why every primary action on a phone belongs in the bottom third of the screen.',\n topic: 'Design',\n author: 'Rina Patel',\n minutes: 5,\n date: 'Oct 18',\n hue: 330,\n },\n {\n id: 3,\n title: 'Shipping on Fridays',\n excerpt:\n 'What changed when we stopped treating the end of the week as a deploy freeze.',\n topic: 'Culture',\n author: 'Luis Ortega',\n minutes: 6,\n date: 'Oct 15',\n hue: 25,\n },\n {\n id: 4,\n title: 'Roadmaps that survive contact',\n excerpt:\n 'Plans written as bets, not promises, and how we review them every six weeks.',\n topic: 'Product',\n author: 'Sam Okafor',\n minutes: 9,\n date: 'Oct 11',\n hue: 150,\n },\n {\n id: 5,\n title: 'Motion with a purpose',\n excerpt: 'Animation that explains a change of state, and the rest that we cut.',\n topic: 'Design',\n author: 'Ada Kim',\n minutes: 4,\n date: 'Oct 8',\n hue: 270,\n },\n {\n id: 6,\n title: 'One table, three layouts',\n excerpt:\n 'How a single data table becomes cards on a phone without a second component.',\n topic: 'Engineering',\n author: 'Tomás Ruiz',\n minutes: 8,\n date: 'Oct 4',\n hue: 190,\n },\n]\n\n/** A cover: two hues in a gradient, from the post's own. */\nconst Cover = ({ hue, tall }: { hue: number; tall?: boolean }) => (\n <div\n className=\"tpl-art\"\n data-tall={tall || undefined}\n style={{ '--tpl-hue': hue } as CSSProperties}\n aria-hidden=\"true\"\n />\n)\n\nconst Byline = ({ post }: { post: Post }) => (\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Avatar name={post.author} size=\"xs\" />\n <Text variant=\"caption\" tone=\"muted\">\n {post.author} · {post.date} · {post.minutes} min read\n </Text>\n </Stack>\n)\n\nconst Subscribe = (): JSX.Element => {\n const [email, setEmail] = useState('')\n const submit = (event: FormEvent) => {\n event.preventDefault()\n toast({\n title: 'You’re subscribed',\n description: `The next issue goes to ${email}.`,\n tone: 'positive',\n })\n setEmail('')\n }\n return (\n <Card variant=\"filled\">\n <Heading level={2} variant=\"h5\">\n The Thursday letter\n </Heading>\n <Text variant=\"p3\" tone=\"muted\">\n One essay a week on design and engineering. No tracking, unsubscribe in one click.\n </Text>\n <form onSubmit={submit}>\n <Stack gap={2}>\n <TextField\n label=\"Email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n value={email}\n onChange={(e) => setEmail(e.currentTarget.value)}\n />\n <Button type=\"submit\">Subscribe</Button>\n </Stack>\n </form>\n </Card>\n )\n}\n\nexport const Blog = (): JSX.Element => {\n const [topics, setTopics] = useState<Topic[]>([])\n const [page, setPage] = useState(1)\n const [liked, setLiked] = useState<number[]>([])\n const [featured, ...rest] = POSTS\n const posts = rest.filter((p) => !topics.length || topics.includes(p.topic))\n\n return (\n <Container size=\"lg\">\n <Stack gap={6} py={{ xs: 5, md: 7 }}>\n <Stack\n gap={3}\n align=\"center\"\n textAlign=\"center\"\n greese={{ enter: 'theme', stagger: 0.06 }}\n >\n <Text variant=\"caption\" tone=\"muted\" className=\"tpl-kicker\">\n Issue 142 · October 2026\n </Text>\n <Heading level={1} variant=\"h1\">\n Field Notes\n </Heading>\n <Text tone=\"muted\" className=\"tpl-measure\">\n Essays on building software people enjoy using, from the team at Northwind.\n </Text>\n <Stack\n direction=\"row\"\n gap={2}\n wrap=\"wrap\"\n justify=\"center\"\n role=\"group\"\n aria-label=\"Filter by topic\"\n >\n {TOPICS.map((topic) => (\n <Chip\n key={topic}\n selectable\n selected={topics.includes(topic)}\n onSelectedChange={(on) =>\n setTopics((all) =>\n on ? [...all, topic] : all.filter((t) => t !== topic)\n )\n }\n >\n {topic}\n </Chip>\n ))}\n </Stack>\n </Stack>\n\n {featured && (\n <Card variant=\"outline\" interactive asChild>\n <a href=\"#featured\" className=\"tpl-featured\">\n <Cover hue={featured.hue} tall />\n <Stack gap={3} justify=\"center\">\n <span>\n <Badge tone=\"primary\">Featured · {featured.topic}</Badge>\n </span>\n <Heading level={2} variant=\"h2\">\n {featured.title}\n </Heading>\n <Text tone=\"muted\">{featured.excerpt}</Text>\n <Byline post={featured} />\n </Stack>\n </a>\n </Card>\n )}\n\n <Grid container columns={{ xs: 1, lg: '1fr 20rem' }} gap={6}>\n <Stack gap={5}>\n <Grid\n container\n minChildWidth=\"16rem\"\n gap={4}\n greese={{ inView: 'theme', stagger: 0.06 }}\n >\n {posts.map((post) => (\n <Card key={post.id} variant=\"outline\">\n <Cover hue={post.hue} />\n <Stack direction=\"row\" justify=\"between\" align=\"center\">\n <Badge>{post.topic}</Badge>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n tone={liked.includes(post.id) ? 'primary' : 'neutral'}\n aria-pressed={liked.includes(post.id)}\n startIcon={<HeartIcon />}\n onClick={() =>\n setLiked((all) =>\n all.includes(post.id)\n ? all.filter((id) => id !== post.id)\n : [...all, post.id]\n )\n }\n >\n {liked.includes(post.id) ? 'Liked' : 'Like'}\n </Button>\n </Stack>\n <Heading level={3} variant=\"h5\">\n <Link href={`#post-${post.id}`} tone=\"neutral\" underline=\"hover\">\n {post.title}\n </Link>\n </Heading>\n <Text variant=\"p3\" tone=\"muted\">\n {post.excerpt}\n </Text>\n <Byline post={post} />\n </Card>\n ))}\n </Grid>\n {posts.length === 0 && (\n <Text tone=\"muted\">No posts on those topics yet.</Text>\n )}\n <Pagination\n count={12}\n page={page}\n onPageChange={setPage}\n label=\"Older posts\"\n />\n </Stack>\n\n <Stack gap={5}>\n <Subscribe />\n <Stack gap={2}>\n <Heading level={2} variant=\"h6\">\n Most read this month\n </Heading>\n <List divided>\n {POSTS.slice(0, 4).map((post, i) => (\n <ListItem\n key={post.id}\n start={\n <Text weight=\"bold\" tone=\"muted\">\n {i + 1}\n </Text>\n }\n title={\n <Link href={`#post-${post.id}`} tone=\"neutral\" underline=\"hover\">\n {post.title}\n </Link>\n }\n description={`${post.author} · ${post.minutes} min`}\n />\n ))}\n </List>\n <Link href=\"#archive\" underline=\"hover\">\n <Stack direction=\"row\" gap={1} align=\"center\" asChild>\n <span>\n The full archive <ArrowRightIcon />\n </span>\n </Stack>\n </Link>\n </Stack>\n </Stack>\n </Grid>\n </Stack>\n </Container>\n )\n}\n"},{"id":"finance","description":"Finance: a personal finance dashboard. Net worth and account totals as stats, a twelve-month cash-flow chart drawn in CSS, budgets as progress bars, recent transactions in a table that stacks on phones, and the accounts list. Transfer opens a dialog with a form.","source":"/**\n * Finance: a personal finance dashboard. Net worth and account totals as\n * stats, a twelve-month cash-flow chart drawn in CSS, budgets as progress\n * bars, recent transactions in a table that stacks on phones, and the\n * accounts list. Transfer opens a dialog with a form.\n */\nimport { useState, type JSX } from 'react'\nimport {\n Avatar,\n Badge,\n Button,\n Card,\n Dialog,\n Field,\n Grid,\n Heading,\n List,\n ListItem,\n NumberField,\n Progress,\n SegmentedControl,\n Segment,\n Select,\n Stack,\n Stat,\n StatGroup,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeaderCell,\n TableRow,\n Text,\n toast,\n} from '@greese/react'\nimport { PlusIcon, SendIcon, TrendDownIcon, TrendUpIcon } from '@greese/icons'\n\nconst money = (n: number, cents = false) =>\n n.toLocaleString('en-US', {\n style: 'currency',\n currency: 'USD',\n maximumFractionDigits: cents ? 2 : 0,\n minimumFractionDigits: cents ? 2 : 0,\n })\n\nconst months = [\n 'Nov',\n 'Dec',\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n]\nconst income = [6.2, 6.2, 6.4, 6.4, 7.9, 6.4, 6.4, 6.6, 6.6, 6.6, 8.1, 6.6]\nconst spending = [4.8, 6.9, 4.1, 4.4, 4.6, 5.2, 4.9, 5.6, 6.1, 4.7, 5.0, 4.3]\n\nconst budgets = [\n { name: 'Groceries', spent: 412, limit: 600 },\n { name: 'Dining out', spent: 286, limit: 250 },\n { name: 'Transport', spent: 96, limit: 180 },\n { name: 'Subscriptions', spent: 64, limit: 80 },\n]\n\nconst transactions = [\n {\n id: 1,\n date: 'Oct 22',\n name: 'Whole Grain Market',\n category: 'Groceries',\n amount: -84.12,\n },\n { id: 2, date: 'Oct 21', name: 'Payroll: Northwind', category: 'Income', amount: 3300 },\n {\n id: 3,\n date: 'Oct 20',\n name: 'Metro card top-up',\n category: 'Transport',\n amount: -40,\n },\n { id: 4, date: 'Oct 19', name: 'Sushi Ko', category: 'Dining out', amount: -62.5 },\n { id: 5, date: 'Oct 18', name: 'Streamly', category: 'Subscriptions', amount: -15.99 },\n {\n id: 6,\n date: 'Oct 17',\n name: 'Transfer to savings',\n category: 'Transfer',\n amount: -500,\n },\n]\n\nconst accounts = [\n { name: 'Everyday checking', detail: 'Harbor Bank ··· 4821', balance: 4280.17 },\n { name: 'High-yield savings', detail: 'Harbor Bank ··· 0093', balance: 8200 },\n { name: 'Index portfolio', detail: 'Fieldstone ··· 7710', balance: 151900 },\n { name: 'Travel card', detail: 'Arc Credit ··· 3346', balance: -9840.55 },\n]\n\nconst categoryTone = {\n Income: 'positive',\n Transfer: 'neutral',\n Groceries: 'primary',\n 'Dining out': 'warning',\n Transport: 'info',\n Subscriptions: 'secondary',\n} as const\n\n/** Income and spending by month, as paired bars: CSS heights, no chart library. */\nconst CashFlow = (): JSX.Element => {\n const max = Math.max(...income, ...spending)\n const net = income.reduce((a, b) => a + b, 0) - spending.reduce((a, b) => a + b, 0)\n return (\n <Stack gap={3}>\n <div\n className=\"tpl-chart\"\n role=\"img\"\n aria-label={`Cash flow for the last twelve months: ${money(net * 1000)} saved in all.`}\n >\n {months.map((month, i) => (\n <div key={month} className=\"tpl-chart-month\">\n <div className=\"tpl-chart-pair\">\n <span\n className=\"tpl-chart-bar tpl-chart-bar--in\"\n style={{ blockSize: `${(income[i]! / max) * 100}%` }}\n />\n <span\n className=\"tpl-chart-bar tpl-chart-bar--out\"\n style={{ blockSize: `${(spending[i]! / max) * 100}%` }}\n />\n </div>\n <Text variant=\"caption\" tone=\"muted\">\n {month}\n </Text>\n </div>\n ))}\n </div>\n <Stack direction=\"row\" gap={4} wrap=\"wrap\">\n <Text variant=\"caption\" tone=\"muted\" className=\"tpl-key tpl-key--in\">\n Income\n </Text>\n <Text variant=\"caption\" tone=\"muted\" className=\"tpl-key tpl-key--out\">\n Spending\n </Text>\n </Stack>\n </Stack>\n )\n}\n\nconst TransferDialog = (): JSX.Element => {\n const [open, setOpen] = useState(false)\n const [amount, setAmount] = useState<number | null>(250)\n return (\n <Dialog\n open={open}\n onOpenChange={setOpen}\n title=\"Transfer money\"\n trigger={<Button startIcon={<SendIcon />}>Transfer</Button>}\n footer={\n <Stack direction=\"row\" gap={2} justify=\"end\">\n <Button variant=\"ghost\" tone=\"neutral\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n disabled={!amount}\n onClick={() => {\n setOpen(false)\n toast({\n title: 'Transfer scheduled',\n description: `${money(amount ?? 0, true)} arrives tomorrow.`,\n tone: 'positive',\n })\n }}\n >\n Send {amount ? money(amount, true) : ''}\n </Button>\n </Stack>\n }\n >\n <Stack gap={4}>\n <Field label=\"From\">\n <Select defaultValue=\"checking\">\n <option value=\"checking\">Everyday checking ··· 4821</option>\n <option value=\"savings\">High-yield savings ··· 0093</option>\n </Select>\n </Field>\n <Field label=\"To\">\n <Select defaultValue=\"savings\">\n <option value=\"savings\">High-yield savings ··· 0093</option>\n <option value=\"card\">Travel card ··· 3346</option>\n </Select>\n </Field>\n <NumberField\n label=\"Amount (USD)\"\n value={amount}\n onValueChange={setAmount}\n min={1}\n step={50}\n />\n </Stack>\n </Dialog>\n )\n}\n\nexport const Finance = (): JSX.Element => {\n const [range, setRange] = useState('12m')\n return (\n <Stack gap={5} className=\"tpl-page\" greese={{ enter: 'theme', stagger: 0.06 }}>\n <Stack\n direction={{ xs: 'column', sm: 'row' }}\n gap={3}\n justify=\"between\"\n align={{ sm: 'end' }}\n >\n <Stack gap={1}>\n <Text tone=\"muted\">Thursday, October 23</Text>\n <Heading level={1} variant=\"h3\">\n Good morning, Alex\n </Heading>\n </Stack>\n <Stack direction=\"row\" gap={2}>\n <Button variant=\"soft\" tone=\"neutral\" startIcon={<PlusIcon />}>\n Add account\n </Button>\n <TransferDialog />\n </Stack>\n </Stack>\n\n <Card variant=\"outline\">\n <StatGroup>\n <Stat\n label=\"Net worth\"\n value={money(184320)}\n description=\"up 2.4% this month\"\n tone=\"positive\"\n media={<TrendUpIcon />}\n />\n <Stat\n label=\"Cash\"\n value={money(12480)}\n description=\"across 2 accounts\"\n tone=\"muted\"\n />\n <Stat\n label=\"Investments\"\n value={money(151900)}\n description=\"up 3.1%\"\n tone=\"positive\"\n />\n <Stat\n label=\"Debt\"\n value={money(-9840)}\n description=\"down 6% since September\"\n tone=\"negative\"\n media={<TrendDownIcon />}\n />\n </StatGroup>\n </Card>\n\n <Grid container columns={12} gap={4}>\n <Grid size={{ xs: 12, md: 8 }}>\n <Card variant=\"outline\">\n <Stack direction=\"row\" justify=\"between\" align=\"center\" gap={3} wrap=\"wrap\">\n <Heading level={2} variant=\"h5\">\n Cash flow\n </Heading>\n <SegmentedControl\n label=\"Range\"\n hideLabel\n size=\"sm\"\n value={range}\n onValueChange={setRange}\n >\n <Segment value=\"6m\">6 months</Segment>\n <Segment value=\"12m\">12 months</Segment>\n </SegmentedControl>\n </Stack>\n <CashFlow />\n </Card>\n </Grid>\n <Grid size={{ xs: 12, md: 4 }}>\n <Card variant=\"outline\">\n <Heading level={2} variant=\"h5\">\n October budgets\n </Heading>\n <Stack gap={4}>\n {budgets.map((b) => {\n const over = b.spent > b.limit\n return (\n <Stack key={b.name} gap={1}>\n <Stack direction=\"row\" justify=\"between\">\n <Text variant=\"p3\" weight=\"semibold\">\n {b.name}\n </Text>\n <Text variant=\"p3\" tone={over ? 'negative' : 'muted'}>\n {money(b.spent)} of {money(b.limit)}\n </Text>\n </Stack>\n <Progress\n value={Math.min(b.spent, b.limit)}\n max={b.limit}\n size=\"sm\"\n aria-label={`${b.name}: ${money(b.spent)} of ${money(b.limit)}`}\n className={over ? 'tpl-over' : undefined}\n />\n </Stack>\n )\n })}\n </Stack>\n </Card>\n </Grid>\n\n <Grid size={{ xs: 12, md: 8 }}>\n <Card variant=\"outline\">\n <Table caption=\"Recent transactions\" stackBelow=\"sm\" hoverable>\n <TableHead>\n <TableRow>\n <TableHeaderCell>Date</TableHeaderCell>\n <TableHeaderCell>Description</TableHeaderCell>\n <TableHeaderCell>Category</TableHeaderCell>\n <TableHeaderCell align=\"end\">Amount</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {transactions.map((t) => (\n <TableRow key={t.id}>\n <TableCell label=\"Date\">{t.date}</TableCell>\n <TableCell label=\"Description\">{t.name}</TableCell>\n <TableCell label=\"Category\">\n <Badge tone={categoryTone[t.category as keyof typeof categoryTone]}>\n {t.category}\n </Badge>\n </TableCell>\n <TableCell label=\"Amount\" align=\"end\">\n <Text\n tone={t.amount > 0 ? 'positive' : undefined}\n weight=\"semibold\"\n >\n {t.amount > 0 ? '+' : ''}\n {money(t.amount, true)}\n </Text>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </Card>\n </Grid>\n <Grid size={{ xs: 12, md: 4 }}>\n <Card variant=\"outline\">\n <Heading level={2} variant=\"h5\">\n Accounts\n </Heading>\n <List divided>\n {accounts.map((a) => (\n <ListItem\n key={a.name}\n start={<Avatar name={a.name} size=\"sm\" shape=\"square\" />}\n title={a.name}\n description={a.detail}\n end={\n <Text\n variant=\"p3\"\n weight=\"semibold\"\n tone={a.balance < 0 ? 'negative' : undefined}\n >\n {money(a.balance, true)}\n </Text>\n }\n />\n ))}\n </List>\n </Card>\n </Grid>\n </Grid>\n </Stack>\n )\n}\n"},{"id":"mail","description":"Email client: folders, a searchable message list and a reading pane side by side on wide screens; on phones the list and the message take turns, with a back button. Starring, archiving, a reply box and a compose dialog work.","source":"/**\n * Email client: folders, a searchable message list and a reading pane side by\n * side on wide screens; on phones the list and the message take turns, with a\n * back button. Starring, archiving, a reply box and a compose dialog work.\n */\nimport { useState, type JSX } from 'react'\nimport {\n Avatar,\n Badge,\n Button,\n Card,\n Chip,\n Dialog,\n Divider,\n Heading,\n IconButton,\n Stack,\n Text,\n Textarea,\n TextField,\n toast,\n} from '@greese/react'\nimport {\n ArchiveIcon,\n ChevronLeftIcon,\n DocumentIcon,\n InboxIcon,\n PlusIcon,\n SearchIcon,\n SendIcon,\n StarFilledIcon,\n StarIcon,\n TrashIcon,\n} from '@greese/icons'\n\ninterface Message {\n id: number\n from: string\n email: string\n subject: string\n preview: string\n body: string[]\n time: string\n unread: boolean\n starred: boolean\n label?: 'Work' | 'Personal' | 'Receipts'\n}\n\nconst MESSAGES: Message[] = [\n {\n id: 1,\n from: 'Rina Patel',\n email: 'rina@northwind.dev',\n subject: 'Design review moved to Thursday',\n preview: 'Quick heads-up: we pushed the review to Thursday at 2pm so…',\n body: [\n 'Hi Alex,',\n 'Quick heads-up: we pushed the design review to Thursday at 2pm so the research summary can land first. Same room, same agenda.',\n 'If Thursday doesn’t work, reply with a time and I’ll shuffle things around.',\n 'Thanks, Rina',\n ],\n time: '9:41',\n unread: true,\n starred: true,\n label: 'Work',\n },\n {\n id: 2,\n from: 'Harbor Bank',\n email: 'statements@harborbank.example',\n subject: 'Your October statement is ready',\n preview: 'Your statement for the account ending 4821 is ready to view…',\n body: [\n 'Your statement for the account ending 4821 is ready to view in online banking.',\n 'This message was sent automatically. Please do not reply.',\n ],\n time: '8:02',\n unread: true,\n starred: false,\n label: 'Receipts',\n },\n {\n id: 3,\n from: 'Tomás Ruiz',\n email: 'tomas@example.com',\n subject: 'Photos from the weekend',\n preview: 'Finally sorted through them, the lake ones came out great…',\n body: [\n 'Finally sorted through them: the lake ones came out great, the rest are mostly of the dog.',\n 'Shared album link coming tonight. Dinner next week?',\n 'T.',\n ],\n time: 'Yesterday',\n unread: false,\n starred: false,\n label: 'Personal',\n },\n {\n id: 4,\n from: 'Luis Ortega',\n email: 'luis@northwind.dev',\n subject: 'Re: Q4 roadmap draft',\n preview: 'Left comments on the onboarding section, mostly small…',\n body: [\n 'Left comments on the onboarding section, mostly small wording things.',\n 'The bigger question is whether the import tool ships in Q4 or slides to Q1. I lean Q1.',\n 'Luis',\n ],\n time: 'Mon',\n unread: false,\n starred: true,\n label: 'Work',\n },\n {\n id: 5,\n from: 'Fieldstone',\n email: 'hello@fieldstone.example',\n subject: 'Your quarterly portfolio summary',\n preview: 'Your portfolio returned 3.1% this quarter. Here’s what moved…',\n body: [\n 'Your portfolio returned 3.1% this quarter. Here’s what moved it, and what’s next.',\n ],\n time: 'Oct 18',\n unread: false,\n starred: false,\n label: 'Receipts',\n },\n]\n\nconst folders = [\n { id: 'inbox', label: 'Inbox', icon: <InboxIcon /> },\n { id: 'starred', label: 'Starred', icon: <StarIcon /> },\n { id: 'sent', label: 'Sent', icon: <SendIcon /> },\n { id: 'drafts', label: 'Drafts', icon: <DocumentIcon /> },\n { id: 'archive', label: 'Archive', icon: <ArchiveIcon /> },\n { id: 'trash', label: 'Trash', icon: <TrashIcon /> },\n]\n\nconst Compose = (): JSX.Element => {\n const [open, setOpen] = useState(false)\n return (\n <Dialog\n open={open}\n onOpenChange={setOpen}\n size=\"lg\"\n title=\"New message\"\n trigger={\n <Button startIcon={<PlusIcon />} fullWidth>\n Compose\n </Button>\n }\n footer={\n <Stack direction=\"row\" gap={2} justify=\"end\">\n <Button variant=\"ghost\" tone=\"neutral\" onClick={() => setOpen(false)}>\n Discard\n </Button>\n <Button\n startIcon={<SendIcon />}\n onClick={() => {\n setOpen(false)\n toast({ title: 'Message sent', tone: 'positive' })\n }}\n >\n Send\n </Button>\n </Stack>\n }\n >\n <Stack gap={3}>\n <TextField label=\"To\" type=\"email\" placeholder=\"name@example.com\" />\n <TextField label=\"Subject\" />\n <Textarea aria-label=\"Message\" rows={8} />\n </Stack>\n </Dialog>\n )\n}\n\nexport const Mail = (): JSX.Element => {\n const [messages, setMessages] = useState(MESSAGES)\n const [folder, setFolder] = useState('inbox')\n const [openId, setOpenId] = useState<number | undefined>(1)\n const [query, setQuery] = useState('')\n\n const update = (id: number, change: Partial<Message>) =>\n setMessages((all) => all.map((m) => (m.id === id ? { ...m, ...change } : m)))\n\n const visible = messages.filter(\n (m) =>\n (folder !== 'starred' || m.starred) &&\n (folder === 'inbox' || folder === 'starred') &&\n `${m.from} ${m.subject} ${m.preview}`.toLowerCase().includes(query.toLowerCase())\n )\n const open = messages.find((m) => m.id === openId)\n const unread = messages.filter((m) => m.unread).length\n\n return (\n <div className=\"tpl-mail\" data-reading={open ? '' : undefined}>\n <nav className=\"tpl-mail-folders\" aria-label=\"Folders\">\n <Stack gap={1} p={3}>\n <Compose />\n <Divider />\n {folders.map((f) => (\n <Button\n key={f.id}\n variant={folder === f.id ? 'soft' : 'ghost'}\n tone={folder === f.id ? 'primary' : 'neutral'}\n startIcon={f.icon}\n className=\"tpl-nav-button\"\n aria-current={folder === f.id ? 'page' : undefined}\n onClick={() => {\n setFolder(f.id)\n setOpenId(undefined)\n }}\n endIcon={\n f.id === 'inbox' && unread ? (\n <Badge tone=\"primary\">{unread}</Badge>\n ) : undefined\n }\n >\n {f.label}\n </Button>\n ))}\n <Divider />\n <Text variant=\"caption\" tone=\"muted\">\n Labels\n </Text>\n <Stack direction=\"row\" gap={1} wrap=\"wrap\">\n <Chip tone=\"primary\">Work</Chip>\n <Chip tone=\"secondary\">Personal</Chip>\n <Chip>Receipts</Chip>\n </Stack>\n </Stack>\n </nav>\n\n <section className=\"tpl-mail-list\" aria-label=\"Messages\">\n <Stack gap={2} p={3}>\n <TextField\n label=\"Search mail\"\n hideLabel\n type=\"search\"\n size=\"sm\"\n placeholder=\"Search mail\"\n startAdornment={<SearchIcon />}\n value={query}\n onChange={(e) => setQuery(e.currentTarget.value)}\n />\n </Stack>\n <ul className=\"tpl-mail-items\">\n {visible.map((m) => (\n <li key={m.id}>\n <button\n type=\"button\"\n className=\"tpl-mail-item\"\n aria-current={m.id === openId || undefined}\n data-unread={m.unread || undefined}\n onClick={() => {\n setOpenId(m.id)\n update(m.id, { unread: false })\n }}\n >\n <Avatar name={m.from} size=\"sm\" />\n <span className=\"tpl-mail-item-text\">\n <span className=\"tpl-mail-item-top\">\n <Text variant=\"p3\" weight={m.unread ? 'bold' : 'medium'} truncate>\n {m.from}\n </Text>\n <Text variant=\"caption\" tone=\"muted\">\n {m.time}\n </Text>\n </span>\n <Text variant=\"p3\" weight={m.unread ? 'semibold' : 'regular'} truncate>\n {m.subject}\n </Text>\n <Text variant=\"caption\" tone=\"muted\" truncate>\n {m.preview}\n </Text>\n </span>\n </button>\n </li>\n ))}\n {visible.length === 0 && (\n <li>\n <Text tone=\"muted\" className=\"tpl-empty\">\n Nothing here.\n </Text>\n </li>\n )}\n </ul>\n </section>\n\n <section className=\"tpl-mail-reader\" aria-label=\"Message\">\n {open ? (\n <Stack gap={4} p={{ xs: 3, md: 5 }} greese={{ enter: 'theme', stagger: 0.06 }}>\n <Stack direction=\"row\" gap={1} align=\"center\">\n <IconButton\n label=\"Back to messages\"\n className=\"tpl-mail-back\"\n onClick={() => setOpenId(undefined)}\n >\n <ChevronLeftIcon />\n </IconButton>\n <IconButton\n label={open.starred ? 'Unstar' : 'Star'}\n aria-pressed={open.starred}\n onClick={() => update(open.id, { starred: !open.starred })}\n >\n {open.starred ? <StarFilledIcon /> : <StarIcon />}\n </IconButton>\n <IconButton\n label=\"Archive\"\n onClick={() => {\n const before = messages\n setMessages(messages.filter((m) => m.id !== open.id))\n setOpenId(undefined)\n toast({\n title: 'Archived',\n action: { label: 'Undo', onClick: () => setMessages(before) },\n })\n }}\n >\n <ArchiveIcon />\n </IconButton>\n </Stack>\n <Stack gap={2}>\n <Heading level={1} variant=\"h4\">\n {open.subject}\n </Heading>\n {open.label && (\n <span>\n <Badge>{open.label}</Badge>\n </span>\n )}\n </Stack>\n <Stack direction=\"row\" gap={3} align=\"center\">\n <Avatar name={open.from} />\n <Stack gap={0}>\n <Text weight=\"semibold\">{open.from}</Text>\n <Text variant=\"caption\" tone=\"muted\">\n {open.email} · {open.time}\n </Text>\n </Stack>\n </Stack>\n <Stack gap={3}>\n {open.body.map((p, i) => (\n <Text key={i}>{p}</Text>\n ))}\n </Stack>\n <Card variant=\"outline\">\n <Textarea\n aria-label={`Reply to ${open.from}`}\n placeholder={`Reply to ${open.from}…`}\n rows={3}\n />\n <Stack direction=\"row\" justify=\"end\">\n <Button\n size=\"sm\"\n startIcon={<SendIcon />}\n onClick={() =>\n toast({ title: `Reply sent to ${open.from}`, tone: 'positive' })\n }\n >\n Send\n </Button>\n </Stack>\n </Card>\n </Stack>\n ) : (\n <Stack align=\"center\" justify=\"center\" className=\"tpl-empty\" p={5}>\n <Text tone=\"muted\">Select a message to read it.</Text>\n </Stack>\n )}\n </section>\n </div>\n )\n}\n"},{"id":"saas","description":"SaaS landing page: hero with a product preview, customer logos, a feature grid, pricing with a monthly and yearly switch, testimonials, an FAQ accordion and a closing call to action.","source":"/**\n * SaaS landing page: hero with a product preview, customer logos, a feature\n * grid, pricing with a monthly and yearly switch, testimonials, an FAQ\n * accordion and a closing call to action.\n */\nimport { useState, type JSX } from 'react'\nimport {\n Accordion,\n AccordionItem,\n Avatar,\n Badge,\n Button,\n Card,\n Container,\n Grid,\n Heading,\n List,\n ListItem,\n Progress,\n Rating,\n Segment,\n SegmentedControl,\n Stack,\n Stat,\n Text,\n} from '@greese/react'\nimport {\n AccessibilityIcon,\n ArrowRightIcon,\n CheckIcon,\n FeatherIcon,\n LayersIcon,\n MotionIcon,\n PhoneIcon,\n ServerIcon,\n} from '@greese/icons'\n\nconst features = [\n {\n icon: <FeatherIcon />,\n title: 'Light by default',\n text: 'Pages ship a few kilobytes of CSS and almost no JavaScript.',\n },\n {\n icon: <PhoneIcon />,\n title: 'Phone first',\n text: 'Every screen starts at 320px and grows, with 44px touch targets.',\n },\n {\n icon: <AccessibilityIcon />,\n title: 'Accessible',\n text: 'Native elements, real focus order, and tested with screen readers.',\n },\n {\n icon: <MotionIcon />,\n title: 'Motion built in',\n text: 'Entrances and interactions on any component, reduced-motion aware.',\n },\n {\n icon: <LayersIcon />,\n title: 'Themeable',\n text: 'Tokens, component styles and motion, edited live in the Studio.',\n },\n {\n icon: <ServerIcon />,\n title: 'Server friendly',\n text: 'Layout and text components render on the server untouched.',\n },\n]\n\nconst plans = [\n {\n name: 'Starter',\n monthly: 0,\n blurb: 'For side projects and trying things out.',\n features: ['3 projects', 'Community support', 'All components'],\n },\n {\n name: 'Team',\n monthly: 24,\n blurb: 'For product teams shipping every week.',\n features: [\n 'Unlimited projects',\n 'Theme Studio sync',\n 'Priority support',\n 'Design reviews',\n ],\n popular: true,\n },\n {\n name: 'Enterprise',\n monthly: 79,\n blurb: 'For organizations with many brands.',\n features: ['Everything in Team', 'SSO and audit log', 'Custom themes', 'Uptime SLA'],\n },\n]\n\nconst quotes = [\n {\n name: 'Maya Chen',\n role: 'Design lead, Fieldstone',\n text: 'We replaced two libraries and a pile of overrides. Our pages got faster and our designers got their brand back.',\n },\n {\n name: 'Jonas Weber',\n role: 'CTO, Arc Credit',\n text: 'The Studio means our themes are a file in the repo, reviewed like code. That alone was worth it.',\n },\n {\n name: 'Aiyana Brooks',\n role: 'Engineer, Harbor',\n text: 'Native dialogs and popovers. No portals, no z-index wars, and focus just works.',\n },\n]\n\nconst faqs = [\n ['Is there a free plan?', 'Yes. Starter is free forever for up to three projects.'],\n [\n 'Can I change plans later?',\n 'Any time. Changes apply from your next billing date, prorated.',\n ],\n [\n 'Do you offer discounts for nonprofits?',\n 'Nonprofits and schools get Team at half price. Write to us.',\n ],\n [\n 'Where is my data stored?',\n 'In the EU or the US, your choice, encrypted at rest and in transit.',\n ],\n] as const\n\nexport const Saas = (): JSX.Element => {\n const [billing, setBilling] = useState('yearly')\n const price = (monthly: number) =>\n billing === 'yearly' ? Math.round(monthly * 0.8) : monthly\n\n return (\n <Stack gap={0}>\n <section className=\"tpl-hero\">\n <Container size=\"lg\">\n <Grid\n container\n columns={{ xs: 1, md: 2 }}\n gap={6}\n align=\"center\"\n py={{ xs: 6, md: 8 }}\n >\n <Stack gap={4} greese={{ enter: 'theme', stagger: 0.06 }}>\n <span>\n <Badge tone=\"primary\" variant=\"soft\">\n New: shape themes\n </Badge>\n </span>\n <Heading level={1} variant=\"h1\">\n Ship interfaces your users feel are fast.\n </Heading>\n <Text variant=\"p1\" tone=\"muted\">\n Launchpad gives product teams one design system for every screen:\n themeable, accessible, and small enough to forget about.\n </Text>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\">\n <Button size=\"lg\" endIcon={<ArrowRightIcon />}>\n Start free trial\n </Button>\n <Button size=\"lg\" variant=\"soft\" tone=\"neutral\">\n Book a demo\n </Button>\n </Stack>\n <Text variant=\"caption\" tone=\"muted\">\n No card needed · 14 days of Team, then Starter for free\n </Text>\n </Stack>\n <Card\n variant=\"elevated\"\n aria-label=\"Product preview\"\n greese={{ enter: 'theme', delay: 0.2 }}\n >\n <Stack direction=\"row\" justify=\"between\" align=\"center\">\n <Text weight=\"semibold\">Release health</Text>\n <Badge tone=\"positive\">Live</Badge>\n </Stack>\n <Grid container columns={2} gap={3}>\n <Stat\n label=\"Page weight\"\n value=\"38 kB\"\n description=\"down 61%\"\n tone=\"positive\"\n />\n <Stat label=\"LCP\" value=\"0.9 s\" description=\"p75, mobile\" tone=\"muted\" />\n </Grid>\n <Stack gap={2}>\n <Text variant=\"p3\">Accessibility checks</Text>\n <Progress value={96} aria-label=\"Accessibility checks: 96% passing\" />\n <Text variant=\"p3\">Design tokens adopted</Text>\n <Progress value={82} aria-label=\"Design tokens adopted: 82%\" />\n </Stack>\n </Card>\n </Grid>\n </Container>\n </section>\n\n <Container size=\"lg\">\n <Stack gap={8} py={{ xs: 6, md: 8 }}>\n <Stack gap={3} align=\"center\">\n <Text variant=\"caption\" tone=\"muted\">\n Trusted by teams at\n </Text>\n <Stack direction=\"row\" gap={{ xs: 4, md: 7 }} wrap=\"wrap\" justify=\"center\">\n {['Northwind', 'Fieldstone', 'Harbor', 'Arc Credit', 'Lumen'].map(\n (logo) => (\n <Text\n key={logo}\n variant=\"s2\"\n weight=\"bold\"\n tone=\"muted\"\n className=\"tpl-logo\"\n >\n {logo}\n </Text>\n )\n )}\n </Stack>\n </Stack>\n\n <Stack gap={5} id=\"features\">\n <Stack gap={2} align=\"center\" textAlign=\"center\" greese={{ inView: 'theme' }}>\n <Heading level={2} variant=\"h2\">\n Everything a product team needs\n </Heading>\n <Text tone=\"muted\" className=\"tpl-measure\">\n Components, themes and motion that work together, so the next screen takes\n an afternoon.\n </Text>\n </Stack>\n <Grid\n container\n minChildWidth=\"16rem\"\n gap={4}\n greese={{ inView: 'theme', stagger: 0.06 }}\n >\n {features.map((f) => (\n <Card key={f.title} variant=\"outline\">\n <span className=\"tpl-feature-icon\" aria-hidden=\"true\">\n {f.icon}\n </span>\n <Heading level={3} variant=\"h6\">\n {f.title}\n </Heading>\n <Text variant=\"p3\" tone=\"muted\">\n {f.text}\n </Text>\n </Card>\n ))}\n </Grid>\n </Stack>\n\n <Stack gap={5} id=\"pricing\">\n <Stack gap={3} align=\"center\" textAlign=\"center\" greese={{ inView: 'theme' }}>\n <Heading level={2} variant=\"h2\">\n Simple pricing\n </Heading>\n <SegmentedControl\n label=\"Billing\"\n hideLabel\n value={billing}\n onValueChange={setBilling}\n >\n <Segment value=\"monthly\">Monthly</Segment>\n <Segment value=\"yearly\">Yearly · save 20%</Segment>\n </SegmentedControl>\n </Stack>\n <Grid\n container\n columns={{ xs: 1, md: 3 }}\n gap={4}\n align=\"stretch\"\n greese={{ inView: 'theme', stagger: 0.06 }}\n >\n {plans.map((plan) => (\n <Card\n key={plan.name}\n variant={plan.popular ? 'elevated' : 'outline'}\n className=\"tpl-plan\"\n >\n <Stack direction=\"row\" justify=\"between\" align=\"center\">\n <Heading level={3} variant=\"h5\">\n {plan.name}\n </Heading>\n {plan.popular && (\n <Badge tone=\"primary\" variant=\"solid\">\n Most popular\n </Badge>\n )}\n </Stack>\n <Text variant=\"p3\" tone=\"muted\">\n {plan.blurb}\n </Text>\n <Stack direction=\"row\" gap={1} align=\"end\">\n <Text variant=\"h2\" weight=\"bold\">\n ${price(plan.monthly)}\n </Text>\n <Text tone=\"muted\">/ user / month</Text>\n </Stack>\n <List>\n {plan.features.map((feature) => (\n <ListItem key={feature} start={<CheckIcon />} title={feature} />\n ))}\n </List>\n <Button\n variant={plan.popular ? 'solid' : 'soft'}\n tone={plan.popular ? 'primary' : 'neutral'}\n fullWidth\n >\n {plan.monthly ? `Choose ${plan.name}` : 'Start for free'}\n </Button>\n </Card>\n ))}\n </Grid>\n </Stack>\n\n <Grid\n container\n minChildWidth=\"18rem\"\n gap={4}\n greese={{ inView: 'theme', stagger: 0.06 }}\n >\n {quotes.map((q) => (\n <Card key={q.name} variant=\"filled\">\n <Rating\n label={`${q.name}'s rating`}\n hideLabel\n value={5}\n readOnly\n size=\"sm\"\n />\n <Text>“{q.text}”</Text>\n <Stack direction=\"row\" gap={3} align=\"center\">\n <Avatar name={q.name} size=\"sm\" />\n <Stack gap={0}>\n <Text variant=\"p3\" weight=\"semibold\">\n {q.name}\n </Text>\n <Text variant=\"caption\" tone=\"muted\">\n {q.role}\n </Text>\n </Stack>\n </Stack>\n </Card>\n ))}\n </Grid>\n\n <Grid\n container\n columns={{ xs: 1, md: '1fr 2fr' }}\n gap={6}\n greese={{ inView: 'theme' }}\n >\n <Heading level={2} variant=\"h3\">\n Questions, answered\n </Heading>\n <Accordion>\n {faqs.map(([question, answer]) => (\n <AccordionItem key={question} title={question}>\n {answer}\n </AccordionItem>\n ))}\n </Accordion>\n </Grid>\n\n <Card variant=\"filled\" className=\"tpl-cta\" greese={{ inView: 'theme' }}>\n <Stack gap={3} align=\"center\" textAlign=\"center\" py={4}>\n <Heading level={2} variant=\"h3\">\n Your next screen, this afternoon.\n </Heading>\n <Button size=\"lg\" endIcon={<ArrowRightIcon />}>\n Start free trial\n </Button>\n </Stack>\n </Card>\n </Stack>\n </Container>\n </Stack>\n )\n}\n"},{"id":"store","description":"E-commerce store: a product grid with search, category filters and sorting, ratings and sale prices, add-to-cart with a count on the cart button, and a cart drawer with quantities, a subtotal and checkout.","source":"/**\n * E-commerce store: a product grid with search, category filters and\n * sorting, ratings and sale prices, add-to-cart with a count on the cart\n * button, and a cart drawer with quantities, a subtotal and checkout.\n */\nimport { useMemo, useState, type CSSProperties, type JSX } from 'react'\nimport {\n Badge,\n Button,\n Card,\n Chip,\n Container,\n Divider,\n Drawer,\n Field,\n Grid,\n Heading,\n IconButton,\n Indicator,\n NumberField,\n Rating,\n Select,\n Stack,\n Text,\n TextField,\n toast,\n} from '@greese/react'\nimport { CartIcon, HeartIcon, SearchIcon, TrashIcon } from '@greese/icons'\n\ninterface Product {\n id: number\n name: string\n category: Category\n price: number\n was?: number\n rating: number\n reviews: number\n hue: number\n}\n\nconst CATEGORIES = ['Kitchen', 'Desk', 'Outdoor', 'Bath'] as const\ntype Category = (typeof CATEGORIES)[number]\n\nconst PRODUCTS: Product[] = [\n {\n id: 1,\n name: 'Stoneware mug, set of 2',\n category: 'Kitchen',\n price: 34,\n rating: 4.5,\n reviews: 212,\n hue: 28,\n },\n {\n id: 2,\n name: 'Walnut desk organizer',\n category: 'Desk',\n price: 58,\n was: 72,\n rating: 4.8,\n reviews: 96,\n hue: 35,\n },\n {\n id: 3,\n name: 'Linen hand towels',\n category: 'Bath',\n price: 26,\n rating: 4.2,\n reviews: 151,\n hue: 190,\n },\n {\n id: 4,\n name: 'Enamel camp kettle',\n category: 'Outdoor',\n price: 44,\n rating: 4.6,\n reviews: 74,\n hue: 150,\n },\n {\n id: 5,\n name: 'Felt laptop sleeve',\n category: 'Desk',\n price: 39,\n rating: 4.4,\n reviews: 188,\n hue: 220,\n },\n {\n id: 6,\n name: 'Cast iron skillet',\n category: 'Kitchen',\n price: 49,\n was: 65,\n rating: 4.9,\n reviews: 403,\n hue: 10,\n },\n {\n id: 7,\n name: 'Cedar bath caddy',\n category: 'Bath',\n price: 52,\n rating: 4.3,\n reviews: 39,\n hue: 45,\n },\n {\n id: 8,\n name: 'Waxed canvas tote',\n category: 'Outdoor',\n price: 68,\n rating: 4.7,\n reviews: 120,\n hue: 95,\n },\n]\n\nconst money = (n: number) =>\n n.toLocaleString('en-US', { style: 'currency', currency: 'USD' })\n\ntype Sort = 'featured' | 'price-low' | 'price-high' | 'rating'\n\nconst sorters: Record<Sort, (a: Product, b: Product) => number> = {\n featured: (a, b) => a.id - b.id,\n 'price-low': (a, b) => a.price - b.price,\n 'price-high': (a, b) => b.price - a.price,\n rating: (a, b) => b.rating - a.rating,\n}\n\nexport const Store = (): JSX.Element => {\n const [query, setQuery] = useState('')\n const [categories, setCategories] = useState<Category[]>([])\n const [sort, setSort] = useState<Sort>('featured')\n const [cart, setCart] = useState<Record<number, number>>({ 6: 1 })\n const [cartOpen, setCartOpen] = useState(false)\n const [saved, setSaved] = useState<number[]>([])\n\n const shown = useMemo(\n () =>\n PRODUCTS.filter(\n (p) =>\n (!categories.length || categories.includes(p.category)) &&\n p.name.toLowerCase().includes(query.toLowerCase())\n ).sort(sorters[sort]),\n [categories, query, sort]\n )\n const lines = Object.entries(cart)\n .map(([id, qty]) => ({ product: PRODUCTS.find((p) => p.id === Number(id))!, qty }))\n .filter((line) => line.qty > 0)\n const count = lines.reduce((n, l) => n + l.qty, 0)\n const subtotal = lines.reduce((n, l) => n + l.qty * l.product.price, 0)\n\n const add = (p: Product) => {\n setCart((c) => ({ ...c, [p.id]: (c[p.id] ?? 0) + 1 }))\n toast({\n title: 'Added to cart',\n description: p.name,\n action: { label: 'View cart', onClick: () => setCartOpen(true) },\n })\n }\n\n return (\n <Container size=\"lg\">\n <Stack gap={5} py={{ xs: 4, md: 6 }}>\n <Stack\n direction=\"row\"\n justify=\"between\"\n align=\"end\"\n gap={3}\n wrap=\"wrap\"\n greese={{ enter: 'theme', stagger: 0.06 }}\n >\n <Stack gap={1}>\n <Heading level={1} variant=\"h2\">\n Goods for slow mornings\n </Heading>\n <Text tone=\"muted\">Free shipping over $75 · Returns within 30 days</Text>\n </Stack>\n <Indicator\n content={\n count ? (\n <Badge tone=\"primary\" variant=\"solid\">\n {count}\n </Badge>\n ) : null\n }\n >\n <Button\n variant=\"soft\"\n tone=\"neutral\"\n startIcon={<CartIcon />}\n onClick={() => setCartOpen(true)}\n >\n Cart\n </Button>\n </Indicator>\n </Stack>\n\n <Grid container columns={{ xs: 1, md: '1fr auto' }} gap={3} align=\"end\">\n <TextField\n label=\"Search products\"\n hideLabel\n type=\"search\"\n placeholder=\"Search products\"\n startAdornment={<SearchIcon />}\n value={query}\n onChange={(e) => setQuery(e.currentTarget.value)}\n />\n <Field label=\"Sort by\" hideLabel>\n <Select value={sort} onChange={(e) => setSort(e.currentTarget.value as Sort)}>\n <option value=\"featured\">Featured</option>\n <option value=\"price-low\">Price: low to high</option>\n <option value=\"price-high\">Price: high to low</option>\n <option value=\"rating\">Best rated</option>\n </Select>\n </Field>\n </Grid>\n <Stack direction=\"row\" gap={2} wrap=\"wrap\" role=\"group\" aria-label=\"Categories\">\n {CATEGORIES.map((c) => (\n <Chip\n key={c}\n selectable\n selected={categories.includes(c)}\n onSelectedChange={(on) =>\n setCategories((all) => (on ? [...all, c] : all.filter((x) => x !== c)))\n }\n >\n {c}\n </Chip>\n ))}\n </Stack>\n\n <Text variant=\"p3\" tone=\"muted\" role=\"status\">\n {shown.length} {shown.length === 1 ? 'product' : 'products'}\n </Text>\n <Grid\n container\n minChildWidth=\"14rem\"\n gap={4}\n greese={{ inView: 'theme', stagger: 0.06 }}\n >\n {shown.map((p) => (\n <Card key={p.id} variant=\"outline\" padding={3}>\n <div\n className=\"tpl-product-art\"\n style={{ '--tpl-hue': p.hue } as CSSProperties}\n aria-hidden=\"true\"\n >\n {p.was && (\n <Badge tone=\"negative\" variant=\"solid\" className=\"tpl-product-sale\">\n Sale\n </Badge>\n )}\n </div>\n <Stack gap={1}>\n <Stack direction=\"row\" justify=\"between\" align=\"start\" gap={2}>\n <Heading level={2} variant=\"h6\">\n {p.name}\n </Heading>\n <IconButton\n size=\"sm\"\n label={\n saved.includes(p.id)\n ? `Remove ${p.name} from saved`\n : `Save ${p.name}`\n }\n aria-pressed={saved.includes(p.id)}\n tone={saved.includes(p.id) ? 'primary' : 'neutral'}\n onClick={() =>\n setSaved((s) =>\n s.includes(p.id) ? s.filter((id) => id !== p.id) : [...s, p.id]\n )\n }\n >\n <HeartIcon />\n </IconButton>\n </Stack>\n <Stack direction=\"row\" gap={2} align=\"center\">\n <Rating\n label={`Rated ${p.rating} out of 5`}\n hideLabel\n value={p.rating}\n step={0.5}\n readOnly\n size=\"xs\"\n />\n <Text variant=\"caption\" tone=\"muted\">\n {p.reviews}\n </Text>\n </Stack>\n <Stack direction=\"row\" gap={2} align=\"baseline\">\n <Text weight=\"bold\">{money(p.price)}</Text>\n {p.was && (\n <Text variant=\"p3\" tone=\"muted\" className=\"tpl-was\">\n <span className=\"greese-VisuallyHidden\">was </span>\n {money(p.was)}\n </Text>\n )}\n </Stack>\n </Stack>\n <Button fullWidth onClick={() => add(p)}>\n Add to cart\n </Button>\n </Card>\n ))}\n </Grid>\n </Stack>\n\n <Drawer\n open={cartOpen}\n onOpenChange={setCartOpen}\n title={`Your cart (${count})`}\n placement={{ xs: 'bottom', md: 'end' }}\n footer={\n <Stack gap={3}>\n <Stack direction=\"row\" justify=\"between\">\n <Text weight=\"semibold\">Subtotal</Text>\n <Text weight=\"bold\">{money(subtotal)}</Text>\n </Stack>\n <Text variant=\"caption\" tone=\"muted\">\n {subtotal >= 75\n ? 'Shipping is on us.'\n : `${money(75 - subtotal)} more for free shipping.`}\n </Text>\n <Button\n size=\"lg\"\n fullWidth\n disabled={!count}\n onClick={() => {\n setCartOpen(false)\n setCart({})\n toast({\n title: 'Order placed',\n description: 'A receipt is on its way.',\n tone: 'positive',\n })\n }}\n >\n Check out\n </Button>\n </Stack>\n }\n >\n {lines.length === 0 ? (\n <Text tone=\"muted\">Your cart is empty.</Text>\n ) : (\n <Stack gap={4}>\n {lines.map(({ product, qty }, i) => (\n <Stack key={product.id} gap={3}>\n {i > 0 && <Divider />}\n <Stack direction=\"row\" gap={3} align=\"center\">\n <div\n className=\"tpl-product-art tpl-product-art--thumb\"\n style={{ '--tpl-hue': product.hue } as CSSProperties}\n aria-hidden=\"true\"\n />\n <Stack gap={1} className=\"tpl-grow\">\n <Text weight=\"semibold\">{product.name}</Text>\n <Text variant=\"p3\" tone=\"muted\">\n {money(product.price)} each\n </Text>\n </Stack>\n <IconButton\n size=\"sm\"\n label={`Remove ${product.name}`}\n onClick={() => setCart((c) => ({ ...c, [product.id]: 0 }))}\n >\n <TrashIcon />\n </IconButton>\n </Stack>\n <NumberField\n label={`Quantity of ${product.name}`}\n hideLabel\n value={qty}\n min={0}\n max={10}\n onValueChange={(v) => setCart((c) => ({ ...c, [product.id]: v ?? 0 }))}\n />\n </Stack>\n ))}\n </Stack>\n )}\n </Drawer>\n </Container>\n )\n}\n"}],"templateStyles":"@use 'pkg:@greese/ui/scss/kit' as greese;\n\n/* The templates' few layout rules: everything else is components and their\n props. Colors are tokens, so every template follows the theme. */\n\n.tpl-page {\n padding: var(--greese-space-4);\n\n @include greese.up(md) {\n padding: var(--greese-space-6);\n }\n}\n\n.tpl-kicker {\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.tpl-measure {\n max-inline-size: 40rem;\n}\n\n.tpl-grow {\n flex: 1;\n min-inline-size: 0;\n}\n\n.tpl-empty {\n min-block-size: 12rem;\n padding: var(--greese-space-5);\n text-align: center;\n}\n\n/* The bar above a template: back to the gallery, its name, its source. */\n.tpl-bar {\n display: flex;\n gap: var(--greese-space-3);\n align-items: center;\n padding: var(--greese-space-2) var(--greese-space-4);\n border-block-end: 1px solid var(--greese-color-border);\n}\n\n.tpl-source {\n display: inline-flex;\n gap: var(--greese-space-1);\n align-items: center;\n margin-inline-start: auto;\n font-size: var(--greese-type-p3-font-size);\n}\n\n.tpl-open {\n display: inline-flex;\n gap: var(--greese-space-1);\n align-items: center;\n}\n\n/* Cover art: two hues of one, in a gradient. No images to load. */\n.tpl-art {\n aspect-ratio: 16 / 9;\n background:\n radial-gradient(\n circle at 25% 30%,\n oklch(0.85 0.12 var(--tpl-hue)) 0 18%,\n transparent 19%\n ),\n linear-gradient(\n 135deg,\n oklch(0.72 0.14 var(--tpl-hue)),\n oklch(0.5 0.16 calc(var(--tpl-hue) + 50))\n );\n border-radius: var(--greese-corner-panel);\n\n &[data-tall] {\n aspect-ratio: 4 / 3;\n }\n}\n\n/* Finance: income and spending bars, side by side per month. */\n.tpl-chart {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--greese-space-1);\n align-items: end;\n block-size: 12rem;\n}\n\n.tpl-chart-month {\n display: grid;\n grid-template-rows: 1fr auto;\n gap: var(--greese-space-1);\n block-size: 100%;\n text-align: center;\n}\n\n.tpl-chart-pair {\n display: flex;\n gap: 2px;\n align-items: end;\n justify-content: center;\n}\n\n.tpl-chart-bar {\n inline-size: min(0.6rem, 40%);\n border-start-start-radius: 3px;\n border-start-end-radius: 3px;\n}\n\n.tpl-chart-bar--in,\n.tpl-key--in::before {\n background: var(--greese-color-primary);\n}\n\n.tpl-chart-bar--out,\n.tpl-key--out::before {\n background: var(--greese-color-border-strong);\n}\n\n.tpl-key::before {\n display: inline-block;\n inline-size: 0.6rem;\n block-size: 0.6rem;\n margin-inline-end: var(--greese-space-1);\n content: '';\n border-radius: 2px;\n}\n\n/* A budget over its limit: the bar in the negative color (Progress fills\n with the primary color, read here). */\n.tpl-over {\n --greese-color-primary: var(--greese-color-negative);\n}\n\n/* Admin: the sidebar sticks under the site's header. */\n.tpl-shell {\n --greese-sidebar-top: 3.5rem;\n\n min-block-size: calc(100dvh - 3.5rem);\n}\n\n.tpl-brand {\n padding: var(--greese-space-2) var(--greese-space-3) var(--greese-space-3);\n}\n\n.tpl-nav-button {\n justify-content: flex-start;\n}\n\n.tpl-main {\n min-inline-size: 0;\n}\n\n/* Mail: three panes from md; below it, the list and the message take turns. */\n.tpl-mail {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n min-block-size: calc(100dvh - 7rem);\n\n @include greese.up(md) {\n grid-template-columns: 13rem 20rem minmax(0, 1fr);\n block-size: calc(100dvh - 7rem);\n }\n}\n\n.tpl-mail-folders,\n.tpl-mail-list {\n min-block-size: 0;\n overflow: auto;\n border-block-end: 1px solid var(--greese-color-border);\n\n @include greese.up(md) {\n border-block-end: 0;\n border-inline-end: 1px solid var(--greese-color-border);\n }\n}\n\n// Phones: the folders are a row that scrolls sideways.\n@include greese.down(md) {\n .tpl-mail-folders > .greese-Stack {\n flex-direction: row;\n align-items: center;\n overflow-x: auto;\n }\n\n .tpl-mail-folders .greese-Divider,\n .tpl-mail-folders .greese-Text,\n .tpl-mail-folders .greese-Stack .greese-Stack {\n display: none;\n }\n\n .tpl-mail-folders .greese-Button {\n flex: none;\n inline-size: auto;\n }\n\n .tpl-mail[data-reading] .tpl-mail-list,\n .tpl-mail:not([data-reading]) .tpl-mail-reader {\n display: none;\n }\n}\n\n@include greese.up(md) {\n .tpl-mail-back {\n display: none;\n }\n}\n\n.tpl-mail-reader {\n min-block-size: 0;\n overflow: auto;\n}\n\n.tpl-mail-items {\n padding: 0;\n margin: 0;\n list-style: none;\n}\n\n.tpl-mail-item {\n display: flex;\n gap: var(--greese-space-3);\n align-items: flex-start;\n inline-size: 100%;\n padding: var(--greese-space-3);\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n background: none;\n border: 0;\n border-block-end: 1px solid var(--greese-color-border);\n\n &:hover {\n background: var(--greese-color-surface);\n }\n\n &:focus-visible {\n outline: 2px solid var(--greese-color-focus-ring);\n outline-offset: -2px;\n }\n\n &[aria-current] {\n background: color-mix(in oklab, var(--greese-color-primary) 10%, transparent);\n }\n\n &[data-unread] {\n box-shadow: inset 3px 0 var(--greese-color-primary);\n }\n}\n\n.tpl-mail-item-text {\n display: grid;\n flex: 1;\n gap: 2px;\n min-inline-size: 0;\n}\n\n.tpl-mail-item-top {\n display: flex;\n gap: var(--greese-space-2);\n justify-content: space-between;\n}\n\n/* Blog: the featured story beside its cover from md. */\n.tpl-featured {\n display: grid;\n gap: var(--greese-space-5);\n color: inherit;\n text-decoration: none;\n\n @include greese.up(md) {\n grid-template-columns: 1.2fr 1fr;\n align-items: center;\n }\n}\n\n/* SaaS */\n.tpl-hero {\n background: linear-gradient(\n 180deg,\n color-mix(in oklab, var(--greese-color-primary) 9%, var(--greese-color-canvas)),\n var(--greese-color-canvas)\n );\n}\n\n.tpl-logo {\n letter-spacing: -0.02em;\n opacity: 0.7;\n}\n\n.tpl-feature-icon {\n display: inline-grid;\n place-items: center;\n inline-size: 2.5rem;\n block-size: 2.5rem;\n font-size: 1.25rem;\n color: var(--greese-color-primary);\n background: color-mix(in oklab, var(--greese-color-primary) 12%, transparent);\n border-radius: var(--greese-corner-panel);\n}\n\n.tpl-plan {\n block-size: 100%;\n\n > .greese-Button {\n margin-block-start: auto;\n }\n}\n\n.tpl-cta {\n background: color-mix(\n in oklab,\n var(--greese-color-primary) 10%,\n var(--greese-color-surface)\n );\n}\n\n/* Store */\n.tpl-product-art {\n position: relative;\n aspect-ratio: 1;\n background:\n radial-gradient(\n ellipse at 50% 60%,\n oklch(0.6 0.12 var(--tpl-hue)) 0 30%,\n transparent 31%\n ),\n oklch(0.93 0.04 var(--tpl-hue));\n border-radius: var(--greese-corner-panel);\n}\n\n.tpl-product-art--thumb {\n flex: none;\n inline-size: 3.5rem;\n}\n\n.tpl-product-sale {\n position: absolute;\n inset-block-start: var(--greese-space-2);\n inset-inline-start: var(--greese-space-2);\n}\n\n.tpl-was {\n text-decoration: line-through;\n}\n\n/* The gallery's cards: the template's screenshot in the scheme being worn\n (the kit's rule: the scheme attribute, else the system's), over the\n gradient while it loads. */\n.tpl-shot-frame {\n position: relative;\n overflow: hidden;\n border: 1px solid var(--greese-color-border);\n}\n\n.tpl-shot {\n display: block;\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n object-position: top;\n}\n\n.tpl-shot--dark {\n display: none;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not([data-greese-scheme='light']) {\n .tpl-shot--light {\n display: none;\n }\n\n .tpl-shot--dark {\n display: block;\n }\n }\n}\n\n:root[data-greese-scheme='dark'] {\n .tpl-shot--light {\n display: none;\n }\n\n .tpl-shot--dark {\n display: block;\n }\n}\n"}
|