{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"toast","type":"registry:ui","title":"Toast","description":"A short, dismissible message that confirms an action, with an optional undo.","dependencies":["@radix-ui/react-slot","@radix-ui/react-toast","clsx","lucide-react","tailwind-merge"],"registryDependencies":["https://caliperui.site/r/styles.json"],"files":[{"path":"ui/button.tsx","type":"registry:ui","target":"components/ui/button.tsx","content":"\"use client\";\n\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport { LoaderCircle } from \"lucide-react\";\nimport {\n  useLayoutEffect,\n  useRef,\n  useState,\n  type ComponentProps,\n  type ReactNode,\n} from \"react\";\nimport { cn } from \"./lib/cn\";\nimport \"./shared/loading-indicator.css\";\nimport \"./button.css\";\n\n/* Colour, material and press live in button.css keyed on data-variant, so a\n   consumer's utility classes still override them. Raised to press: the\n   button sinks 1px into an inner shade instead of scaling. */\nconst variants = {\n  default: \"\",\n  secondary: \"\",\n  ghost: \"\",\n  destructive: \"\",\n};\n\nconst sizes = {\n  sm: \"h-8 gap-1.5 rounded-full px-3 text-[13px] max-md:min-h-11 [@media(pointer:coarse)]:min-h-11\",\n  md: \"h-[var(--control-height)] gap-2 rounded-full px-3.5 text-sm\",\n  lg: \"h-11 gap-2 rounded-full px-[18px] text-[15px]\",\n  icon: \"size-[var(--control-height)] rounded-full p-0\",\n};\n\nexport type ButtonProps = ComponentProps<\"button\"> & {\n  variant?: keyof typeof variants;\n  size?: keyof typeof sizes;\n  asChild?: boolean;\n  /** Shows a spinner over the label and swallows clicks while keeping focus and width. */\n  loading?: boolean;\n  /** Animate a meaningful label/icon change, such as saving → saved. */\n  feedbackKey?: string;\n};\n\nexport function Button({\n  className,\n  variant = \"default\",\n  size = \"md\",\n  asChild = false,\n  loading = false,\n  feedbackKey,\n  disabled,\n  \"aria-disabled\": ariaDisabled,\n  children,\n  onClick,\n  onClickCapture,\n  tabIndex,\n  type = \"button\",\n  ...props\n}: ButtonProps) {\n  const Component = asChild ? Slot : \"button\";\n  const nativeDisabled = Boolean(disabled);\n  const blocked =\n    nativeDisabled ||\n    loading ||\n    ariaDisabled === true ||\n    ariaDisabled === \"true\";\n\n  return (\n    <Component\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      type={asChild ? undefined : type}\n      className={cn(\n        \"relative inline-flex shrink-0 items-center justify-center whitespace-nowrap border border-transparent font-medium tracking-[-0.006em] outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none aria-disabled:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n        variants[variant],\n        sizes[size],\n        className,\n      )}\n      disabled={asChild ? undefined : nativeDisabled}\n      aria-disabled={nativeDisabled || ariaDisabled ? true : undefined}\n      aria-busy={loading || undefined}\n      tabIndex={asChild && nativeDisabled ? -1 : tabIndex}\n      {...props}\n      onKeyDown={(event) => {\n        if (blocked && (event.key === \"Enter\" || event.key === \" \")) {\n          event.preventDefault();\n        }\n        props.onKeyDown?.(event);\n      }}\n      onClickCapture={(event) => {\n        if (blocked) {\n          event.preventDefault();\n          event.stopPropagation();\n          return;\n        }\n        onClickCapture?.(event);\n      }}\n      onClick={onClick}\n    >\n      {loading && asChild && (\n        <LoaderCircle data-slot=\"loading-indicator\" aria-hidden=\"true\" />\n      )}\n      {loading && !asChild && feedbackKey === undefined && (\n        <span data-slot=\"button-busy\" aria-hidden=\"true\">\n          <LoaderCircle data-slot=\"loading-indicator\" />\n        </span>\n      )}\n      <Slottable>\n        {loading && !asChild && feedbackKey === undefined ? (\n          <span data-slot=\"button-label\" data-hidden=\"true\">\n            {children}\n          </span>\n        ) : feedbackKey !== undefined && !asChild ? (\n          <ButtonFeedback stateKey={feedbackKey}>\n            {loading && (\n              <LoaderCircle data-slot=\"loading-indicator\" aria-hidden=\"true\" />\n            )}\n            {children}\n          </ButtonFeedback>\n        ) : (\n          children\n        )}\n      </Slottable>\n    </Component>\n  );\n}\n\nfunction ButtonFeedback({\n  stateKey,\n  children,\n}: {\n  stateKey: string;\n  children: ReactNode;\n}) {\n  const content = useRef<HTMLSpanElement>(null);\n  const [initialKey] = useState(stateKey);\n  const [width, setWidth] = useState<number>();\n  useLayoutEffect(() => {\n    const element = content.current;\n    if (!element) return;\n    const measure = () => setWidth(element.offsetWidth);\n    measure();\n    const observer = new ResizeObserver(measure);\n    observer.observe(element);\n    return () => observer.disconnect();\n  }, [stateKey]);\n  return (\n    <span data-slot=\"button-feedback\" style={{ width }}>\n      <span\n        key={stateKey}\n        ref={content}\n        data-slot=\"button-feedback-label\"\n        data-enter={stateKey !== initialKey}\n      >\n        {children}\n      </span>\n    </span>\n  );\n}\n"},{"path":"ui/feedback.tsx","type":"registry:ui","target":"components/ui/feedback.tsx","content":"import { CircleCheck, CircleX, Info, LoaderCircle, TriangleAlert } from \"lucide-react\";\nimport \"./feedback.css\";\n\nexport type FeedbackVariant = \"neutral\" | \"success\" | \"warning\" | \"error\";\n\nconst icons = {\n  neutral: Info,\n  success: CircleCheck,\n  warning: TriangleAlert,\n  error: CircleX,\n};\n\nexport function FeedbackIcon({\n  variant,\n  loading = false,\n}: {\n  variant: FeedbackVariant;\n  loading?: boolean;\n}) {\n  const Icon = loading ? LoaderCircle : icons[variant];\n  return (\n    <span data-slot=\"feedback-icon\" aria-hidden=\"true\">\n      <span data-slot=\"feedback-symbol\" key={loading ? \"loading\" : variant}>\n        <Icon data-slot={loading ? \"loading-indicator\" : undefined} />\n      </span>\n    </span>\n  );\n}\n"},{"path":"ui/lib/cn.ts","type":"registry:ui","target":"components/ui/lib/cn.ts","content":"import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n  extend: { theme: { radius: [\"control\", \"surface\", \"overlay\"], shadow: [\"overlay\"] } },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"},{"path":"ui/toast.tsx","type":"registry:ui","target":"components/ui/toast.tsx","content":"\"use client\";\n\nimport * as Primitive from \"@radix-ui/react-toast\";\nimport { X } from \"lucide-react\";\nimport {\n  useId,\n  useEffect,\n  useLayoutEffect,\n  useRef,\n  useState,\n  type ComponentProps,\n  type CSSProperties,\n  type ReactNode,\n} from \"react\";\nimport { Button, type ButtonProps } from \"./button\";\nimport { FeedbackIcon, type FeedbackVariant } from \"./feedback\";\nimport { cn } from \"./lib/cn\";\nimport \"./shared/alert.css\";\nimport \"./toast.css\";\n\nexport type ToastProps = Omit<\n  ComponentProps<typeof Primitive.Root>,\n  \"title\" | \"children\" | \"asChild\"\n> & {\n  title: ReactNode;\n  variant?: FeedbackVariant;\n  loading?: boolean;\n  children?: ReactNode;\n  action?: {\n    label: string;\n    altText: string;\n    onClick: ButtonProps[\"onClick\"];\n    disabled?: boolean;\n  };\n};\n\nexport function ToastProvider({\n  duration = 6000,\n  label = \"Notification\",\n  swipeDirection = \"right\",\n  ...props\n}: ComponentProps<typeof Primitive.Provider>) {\n  return (\n    <Primitive.Provider\n      duration={duration}\n      label={label}\n      swipeDirection={swipeDirection}\n      {...props}\n    />\n  );\n}\n\nexport function Toast({\n  title,\n  variant = \"neutral\",\n  loading = false,\n  children,\n  action,\n  className,\n  style,\n  duration,\n  ...props\n}: ToastProps) {\n  const titleId = useId();\n  const descriptionId = useId();\n  const [content, setContent] = useState<HTMLDivElement | null>(null);\n  const [height, setHeight] = useState<number>();\n  const [instantLayout, setInstantLayout] = useState(false);\n  const previousMessage = useRef<{ node: HTMLDivElement; text: string } | null>(null);\n  const announcement = useRef<HTMLSpanElement>(null);\n  const messageKey = loading ? \"loading\" : variant;\n  useLayoutEffect(() => {\n    if (!content) return;\n    let previousWidth: number | undefined;\n    let previousDensity: string | undefined;\n    let previousHeight: number | undefined;\n    const measure = () => {\n      const bounds = content.getBoundingClientRect();\n      const density = getComputedStyle(content).getPropertyValue(\"--control-height\");\n      if (previousWidth !== undefined && (previousWidth !== bounds.width || previousDensity !== density)) {\n        setInstantLayout(true);\n      } else if (previousHeight !== bounds.height) {\n        setInstantLayout(false);\n      }\n      setHeight(bounds.height);\n      previousWidth = bounds.width;\n      previousDensity = density;\n      previousHeight = bounds.height;\n    };\n    measure();\n    const observer = new ResizeObserver(measure);\n    observer.observe(content);\n    return () => observer.disconnect();\n  }, [content]);\n  useEffect(() => {\n    if (!content) {\n      previousMessage.current = null;\n      if (announcement.current) announcement.current.textContent = \"\";\n      return;\n    }\n    const text = [\n      content.querySelector('[data-slot=\"feedback-title\"]')?.textContent,\n      content.querySelector('[data-slot=\"feedback-description\"]')?.textContent,\n    ].filter(Boolean).join(\" \");\n    if (\n      previousMessage.current?.node === content &&\n      previousMessage.current.text !== text &&\n      content.parentElement?.dataset.state === \"open\" &&\n      announcement.current\n    ) {\n      announcement.current.textContent = text;\n    }\n    previousMessage.current = { node: content, text };\n  }, [content, title, children]);\n\n  return (\n    <>\n    <Primitive.Root\n      data-slot=\"toast\"\n      data-variant={loading ? \"neutral\" : variant}\n      data-layout={instantLayout ? \"instant\" : undefined}\n      aria-busy={loading || undefined}\n      // Errors stay until dismissed; pending work never times out mid-way.\n      duration={duration ?? (variant === \"error\" || loading ? Infinity : undefined)}\n      aria-labelledby={titleId}\n      aria-describedby={children != null ? descriptionId : undefined}\n      className={cn(\n        \"block min-w-0 shrink-0 rounded-surface bg-elevated text-sm text-foreground shadow-feedback outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring [overflow-wrap:anywhere]\",\n        className,\n      )}\n      style={{\n        touchAction: \"var(--caliper-toast-touch-action, none)\",\n        \"--caliper-toast-block-size\": height === undefined ? undefined : `${height}px`,\n        ...style,\n      } as CSSProperties}\n      {...props}\n    >\n      <div\n        ref={setContent}\n        data-slot=\"toast-content\"\n        className=\"grid min-w-0 grid-cols-[2rem_minmax(0,1fr)_auto] items-start gap-3\"\n      >\n        <FeedbackIcon variant={variant} loading={loading} />\n        <div data-slot=\"feedback-copy\" className=\"min-w-0 pt-1\">\n          <Primitive.Title id={titleId} data-slot=\"feedback-title\" className=\"font-semibold leading-5\">\n            <span key={messageKey} data-slot=\"feedback-message\">{title}</span>\n          </Primitive.Title>\n          {children != null && (\n            <Primitive.Description\n              id={descriptionId}\n              data-slot=\"feedback-description\"\n              className=\"mt-1 text-sm leading-5 text-muted-foreground\"\n            >\n              <span key={messageKey} data-slot=\"feedback-message\">{children}</span>\n            </Primitive.Description>\n          )}\n          {action && (\n            <div data-slot=\"feedback-action\" className=\"mt-3\">\n              <Primitive.Action asChild altText={action.altText}>\n                <Button\n                  variant=\"secondary\"\n                  size=\"sm\"\n                  className=\"h-auto min-h-8 max-w-full py-1.5 whitespace-normal text-left\"\n                  disabled={action.disabled}\n                  onClick={action.onClick}\n                >\n                  {action.label}\n                </Button>\n              </Primitive.Action>\n            </div>\n          )}\n        </div>\n        <Primitive.Close asChild>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className=\"-mt-1 -mr-1\"\n            aria-label=\"Dismiss notification\"\n          >\n            <X aria-hidden=\"true\" />\n          </Button>\n        </Primitive.Close>\n      </div>\n    </Primitive.Root>\n    <span ref={announcement} data-slot=\"toast-update-announcement\" className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\" />\n    </>\n  );\n}\n\nexport function ToastStack({\n  className,\n  label = \"Notifications ({hotkey})\",\n  ...props\n}: ComponentProps<typeof Primitive.Viewport>) {\n  return (\n    <Primitive.Viewport\n      data-slot=\"toast-stack\"\n      label={label}\n      className={cn(\n        \"fixed right-0 bottom-0 z-[60] m-0 flex max-h-[100dvh] w-full max-w-[26rem] list-none flex-col-reverse overflow-y-auto p-4 outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n"},{"path":"ui/shared/loading-indicator.css","type":"registry:file","target":"components/ui/shared/loading-indicator.css","content":"/* Shared by button.tsx, confirm-morph.tsx, expanding-button-group.tsx, field.tsx; each imports it. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"loading-indicator\"] {\n    animation: caliper-spin var(--duration-loading) var(--ease-linear) infinite;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"loading-indicator\"] {\n      animation: none;\n    }\n  }\n}\n"},{"path":"ui/button.css","type":"registry:file","target":"components/ui/button.css","content":"/* button.tsx's styles; it imports this file. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"button\"] {\n    transition-property: background-color, color, border-color;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-out);\n  }\n\n  /* Button material. Raised to press: a lit top edge and a small lift; the\n     press travels 1px down and swaps the lift for an inner shade. Only\n     translate animates (release on the settle curve); shadows swap. */\n  [data-slot=\"button\"] {\n    --b-bg: var(--raised);\n    --b-bg-hover: var(--raised-hover);\n    --b-bg-press: var(--raised-press);\n    --b-fg: var(--foreground);\n    --b-shadow: var(--shadow-raised);\n    --b-shadow-press: var(--shadow-raised-press);\n    background-color: var(--b-bg);\n    color: var(--b-fg);\n    box-shadow: var(--b-shadow);\n    transition-property: background-color, color, border-color, translate, scale;\n    transition-duration:\n      var(--duration-fast), var(--duration-fast), var(--duration-fast),\n      var(--duration-normal), var(--duration-normal);\n    transition-timing-function:\n      var(--ease-out), var(--ease-out), var(--ease-out), var(--ease-settle),\n      var(--ease-settle);\n  }\n  [data-slot=\"button\"][data-variant=\"default\"] {\n    --b-bg: var(--primary);\n    --b-bg-hover: var(--primary-hover);\n    --b-bg-press: var(--primary-press);\n    --b-fg: var(--primary-foreground);\n    --b-shadow: var(--shadow-accent);\n    --b-shadow-press: var(--shadow-accent-press);\n  }\n  [data-slot=\"button\"][data-variant=\"destructive\"] {\n    --b-bg: var(--danger-fill);\n    --b-bg-hover: var(--danger-fill-hover);\n    --b-bg-press: var(--danger-fill-press);\n    --b-fg: var(--danger-fill-foreground);\n    --b-shadow: var(--shadow-danger);\n    --b-shadow-press: var(--shadow-danger-press);\n  }\n  [data-slot=\"button\"][data-variant=\"ghost\"] {\n    --b-bg: transparent;\n    --b-bg-hover: var(--muted);\n    --b-bg-press: var(--muted);\n    --b-fg: var(--muted-foreground);\n    --b-shadow: none;\n    --b-shadow-press: none;\n  }\n  @media (hover: hover) {\n    [data-slot=\"button\"]:hover {\n      background-color: var(--b-bg-hover);\n    }\n    [data-slot=\"button\"][data-variant=\"ghost\"]:hover {\n      color: var(--foreground);\n    }\n  }\n  [data-slot=\"button\"]:active:not(:disabled):not([aria-disabled=\"true\"]):not(\n      [aria-busy=\"true\"]\n    ) {\n    translate: 0 var(--motion-press-travel);\n    scale: var(--motion-press-scale);\n    background-color: var(--b-bg-press);\n    box-shadow: var(--b-shadow-press);\n    transition-duration:\n      var(--duration-fast), var(--duration-fast), var(--duration-fast), 90ms,\n      90ms;\n    transition-timing-function: var(--ease-out);\n  }\n  [data-slot=\"button\"]:is(:disabled, [aria-disabled=\"true\"]):not([aria-busy=\"true\"]) {\n    background-color: var(--sunken);\n    color: var(--muted-foreground);\n  }\n  [data-slot=\"button\"][data-variant=\"ghost\"]:is(:disabled, [aria-disabled=\"true\"]):not(\n      [aria-busy=\"true\"]\n    ) {\n    background-color: transparent;\n    box-shadow: none;\n  }\n  /* Loading keeps the exact width: the label stays in flow but invisible. */\n  [data-slot=\"button-label\"] {\n    display: inline-flex;\n    align-items: center;\n    gap: inherit;\n  }\n  /* Opacity, not visibility, so the label still names the button. */\n  [data-slot=\"button-label\"][data-hidden=\"true\"] {\n    opacity: 0;\n  }\n  [data-slot=\"button-busy\"] {\n    position: absolute;\n    inset: 0;\n    display: grid;\n    place-items: center;\n  }\n  [data-slot=\"button-feedback\"] {\n    display: inline-flex;\n    align-items: center;\n    gap: inherit;\n    overflow: clip;\n    transition: width var(--duration-normal) var(--ease-out);\n  }\n  [data-slot=\"button-feedback-label\"] {\n    display: inline-flex;\n    flex-shrink: 0;\n    align-items: center;\n    gap: inherit;\n    width: max-content;\n  }\n  [data-slot=\"button-feedback-label\"][data-enter=\"true\"] {\n    animation: caliper-feedback-enter var(--duration-normal) var(--ease-out);\n  }\n\n  [data-slot=\"button\"][aria-busy=\"true\"] {\n    pointer-events: none;\n  }\n  [data-slot=\"button\"][data-action-phase=\"error\"] {\n    color: var(--danger);\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"button\"],\n    [data-slot=\"button-feedback\"] {\n      transition: none;\n    }\n    [data-slot=\"button\"]:active:not(:disabled):not([aria-disabled=\"true\"]):not(\n        [aria-busy=\"true\"]\n      ) {\n      translate: none;\n    }\n    [data-slot=\"button-feedback-label\"],\n    [data-slot=\"button-feedback-label\"][data-enter=\"true\"] {\n      animation: none;\n    }\n  }\n\n  /* Toggle: pressed is recessed, as a toggled tool in a button group is. */\n  /* Four attributes, so it wins over the group and toolbar pressed rules in any stylesheet order. */\n  [data-slot=\"button\"][data-variant=\"ghost\"][data-toggle][aria-pressed=\"true\"] {\n    --b-bg: var(--raised-press);\n    --b-bg-hover: var(--raised-press);\n    --b-bg-press: var(--raised-press);\n    --b-fg: var(--foreground);\n    --b-shadow: var(--shadow-sunken);\n    --b-shadow-press: var(--shadow-sunken);\n  }\n}\n"},{"path":"ui/feedback.css","type":"registry:file","target":"components/ui/feedback.css","content":"/* feedback.tsx's styles; it imports this file. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"feedback-icon\"] {\n    display: flex;\n    width: 2rem;\n    height: 2rem;\n    flex-shrink: 0;\n    align-items: center;\n    justify-content: center;\n    border-radius: var(--radius-surface);\n    background: var(--muted);\n    color: var(--muted-foreground);\n    transition:\n      color var(--duration-fast) var(--ease-out),\n      background-color var(--duration-fast) var(--ease-out);\n  }\n  [data-slot=\"feedback-symbol\"] {\n    display: flex;\n    animation: caliper-feedback-symbol-enter var(--duration-normal) var(--ease-out);\n  }\n  [data-slot=\"feedback-icon\"] svg {\n    width: 1rem;\n    height: 1rem;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"feedback-icon\"] {\n      transition: none;\n      transform: none !important;\n    }\n    [data-slot=\"feedback-symbol\"] {\n      animation: none;\n    }\n  }\n}\n"},{"path":"ui/shared/alert.css","type":"registry:file","target":"components/ui/shared/alert.css","content":"/* Shared by alert.tsx, toast.tsx; each imports it. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"feedback-message\"] {\n    display: block;\n    animation: caliper-fade-in var(--duration-normal) var(--ease-out);\n  }\n  :is([data-slot=\"alert\"], [data-slot=\"toast\"])[data-variant=\"success\"]\n    [data-slot=\"feedback-icon\"] {\n    background: var(--success-subtle);\n    color: var(--success);\n  }\n  :is([data-slot=\"alert\"], [data-slot=\"toast\"])[data-variant=\"warning\"]\n    [data-slot=\"feedback-icon\"] {\n    background: var(--warning-subtle);\n    color: var(--warning);\n  }\n  :is([data-slot=\"alert\"], [data-slot=\"toast\"])[data-variant=\"error\"]\n    [data-slot=\"feedback-icon\"] {\n    background: var(--destructive-subtle);\n    color: var(--destructive);\n  }\n  @container (max-width: 22rem) {\n    [data-slot=\"feedback-copy\"] {\n      display: contents;\n    }\n    [data-slot=\"feedback-title\"] {\n      grid-column: 2;\n      grid-row: 1;\n      min-width: 0;\n      padding-top: 0.25rem;\n    }\n    [data-slot=\"feedback-description\"],\n    [data-slot=\"feedback-action\"] {\n      grid-column: 1 / -1;\n      margin-top: 0;\n    }\n    [data-slot=\"feedback-description\"] {\n      grid-row: 2;\n    }\n    [data-slot=\"feedback-action\"] {\n      grid-row: 3;\n    }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"feedback-message\"] {\n      animation: none;\n    }\n  }\n}\n"},{"path":"ui/toast.css","type":"registry:file","target":"components/ui/toast.css","content":"/* toast.tsx's styles; it imports this file. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"toast\"] {\n    --caliper-toast-touch-action: pan-y;\n    --caliper-toast-exit-x: 100%;\n    --caliper-toast-exit-y: 0px;\n    margin-block-start: 0.5rem;\n    container-type: inline-size;\n    block-size: var(--caliper-toast-block-size, 0px);\n    overflow: clip;\n    transition:\n      block-size var(--duration-normal) var(--ease-out),\n      margin-block-start var(--duration-normal) var(--ease-out);\n  }\n  [data-slot=\"toast-content\"] {\n    min-width: 0;\n    border-radius: inherit;\n    border: 1px solid var(--border);\n    padding: 1rem;\n  }\n  [data-slot=\"toast\"][data-layout=\"instant\"] {\n    transition: none;\n  }\n  [data-slot=\"toast\"][data-state=\"open\"] {\n    animation: caliper-feedback-enter var(--duration-normal) var(--ease-out);\n  }\n  [data-slot=\"toast\"][data-state=\"closed\"] {\n    animation: caliper-fade-out var(--duration-fast) var(--ease-in) forwards;\n    pointer-events: none;\n    block-size: 0;\n    margin-block-start: 0;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-in);\n  }\n  @starting-style {\n    [data-slot=\"toast\"][data-state=\"open\"] {\n      block-size: 0;\n      margin-block-start: 0;\n    }\n  }\n  @container (max-width: 22rem) {\n    [data-slot=\"toast-content\"] > [data-slot=\"button\"] {\n      grid-column: 3;\n      grid-row: 1;\n    }\n  }\n  [data-slot=\"toast\"][data-swipe-direction=\"left\"] {\n    --caliper-toast-exit-x: -100%;\n  }\n  [data-slot=\"toast\"][data-swipe-direction=\"up\"],\n  [data-slot=\"toast\"][data-swipe-direction=\"down\"] {\n    --caliper-toast-touch-action: pan-x;\n    --caliper-toast-exit-x: 0px;\n  }\n  [data-slot=\"toast\"][data-swipe-direction=\"up\"] {\n    --caliper-toast-exit-y: -100%;\n  }\n  [data-slot=\"toast\"][data-swipe-direction=\"down\"] {\n    --caliper-toast-exit-y: 100%;\n  }\n  [data-slot=\"toast\"][data-state=\"open\"]:is(\n      [data-swipe=\"start\"],\n      [data-swipe=\"move\"],\n      [data-swipe=\"cancel\"]\n    ) {\n    animation: none;\n  }\n  [data-slot=\"toast\"][data-swipe=\"move\"] {\n    transform: translate(\n      var(--radix-toast-swipe-move-x, 0px),\n      var(--radix-toast-swipe-move-y, 0px)\n    );\n  }\n  [data-slot=\"toast\"][data-swipe=\"cancel\"] {\n    transform: translate(0, 0);\n    transition: transform var(--duration-fast) var(--ease-out);\n  }\n  [data-slot=\"toast\"][data-state=\"closed\"][data-swipe=\"end\"] {\n    animation: caliper-toast-swipe-out var(--duration-fast) var(--ease-in) forwards;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"toast\"][data-state=\"open\"] {\n      animation: none;\n    }\n    [data-slot=\"toast\"] {\n      animation: none;\n    }\n    [data-slot=\"toast\"] {\n      transition: none;\n      transform: none !important;\n    }\n    /* Preserve the exit name for Radix Presence's completion matcher, including\n       a preference changed during exit. No visual motion or unmount timer. */\n    [data-slot=\"toast\"][data-state=\"closed\"] {\n      animation: caliper-fade-out var(--duration-instant) var(--ease-in) forwards !important;\n    }\n    [data-slot=\"toast\"][data-state=\"closed\"][data-swipe=\"end\"] {\n      animation: caliper-toast-swipe-out var(--duration-instant) var(--ease-in) forwards !important;\n    }\n  }\n}\n\n[data-slot=\"toast\"] {\n  background-color: var(--elevated-glass);\n  border-color: color-mix(in srgb, var(--edge-light) 45%, var(--border));\n  backdrop-filter: blur(var(--blur-overlay));\n  box-shadow:\n    var(--shadow-overlay),\n    0 0 40px var(--edge-glow),\n    inset 0 1px 0 var(--edge-light);\n}\n\n@keyframes caliper-toast-swipe-out {\n  from {\n    opacity: 1;\n    transform: translate(\n      var(--radix-toast-swipe-end-x, 0px),\n      var(--radix-toast-swipe-end-y, 0px)\n    );\n  }\n  to {\n    opacity: 0;\n    transform: translate(var(--caliper-toast-exit-x), var(--caliper-toast-exit-y));\n  }\n}\n"}],"categories":["feedback"],"meta":{"tier":"free","license":"MIT","family":"feedback","docs":"/docs/components/toast"}}