Back to buttons
"use client";

import * as React from "react";

export type ProgressFoldButtonVariant = "primary" | "secondary";
export type ProgressFoldButtonSize = "sm" | "md" | "lg";
export type ProgressFoldButtonStatus = "idle" | "loading";

export type ProgressFoldButtonProps =
  React.ButtonHTMLAttributes<HTMLButtonElement> & {
    variant?: ProgressFoldButtonVariant;
    size?: ProgressFoldButtonSize;
    /**
     * Loading lifecycle. `loading` folds the front face open and runs the
     * progress bar behind it. Fully controlled.
     */
    status?: ProgressFoldButtonStatus;
    /**
     * 0–100. With `status="loading"` a value makes the bar determinate (fills
     * to that percentage); omitting it makes the bar indeterminate (a segment
     * sweeps across).
     */
    progress?: number;
  };

// `group` drives the fold + progress state from the button's data-* attributes.
const BUTTON_BASE =
  "group relative inline-flex cursor-pointer select-none whitespace-nowrap border-none p-0 bg-border font-medium [perspective:800px] [transform-style:preserve-3d] [-webkit-tap-highlight-color:transparent] focus-visible:[outline:2px_solid_var(--ring)] focus-visible:[outline-offset:4px] disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none";

const LAYERS_BASE = "absolute inset-0 -z-[1] overflow-hidden";

// Folding front face — tilts back on hover / focus / while loading.
const FRONT_BASE =
  "relative grid w-full place-items-center rounded-[inherit] [transform:rotateX(0deg)] [transform-origin:top_center] [transition:transform_0.2s] group-hover:[transform:rotateX(35deg)] group-focus-visible:[transform:rotateX(35deg)] group-data-[status=loading]:[transform:rotateX(35deg)] motion-reduce:[transition:none]";

// Progress bar: determinate scales from the left to --progress-fold-fill
// (0–1, transition armed a frame after entering loading); indeterminate
// sweeps a fixed 40%-wide segment on a loop.
const BAR_BASE =
  "absolute top-0 left-0 h-full w-full origin-left [transform:scaleX(0)] group-data-[determinate=true]:[transform:scaleX(var(--progress-fold-fill,0))] group-[&[data-determinate=true][data-armed=true]]:[transition:transform_0.25s_ease] group-[&[data-status=loading]:not([data-determinate=true])]:w-[40%] group-[&[data-status=loading]:not([data-determinate=true])]:animate-progress-fold-indeterminate motion-reduce:group-[&[data-determinate=true][data-armed=true]]:[transition:none] motion-reduce:group-[&[data-status=loading]:not([data-determinate=true])]:animate-none";

// Outer button + clip layer share the per-size radius (--button-radius-*).
const radiusClasses: Record<ProgressFoldButtonSize, string> = {
  sm: "rounded-[var(--button-radius-sm)]",
  md: "rounded-[var(--button-radius-md)]",
  lg: "rounded-[var(--button-radius-lg)]",
};

const frontSizeClasses: Record<ProgressFoldButtonSize, string> = {
  sm: "px-[var(--button-px-sm)] py-[var(--button-py-sm)] text-[length:var(--button-text-sm)] leading-[var(--button-leading-sm)]",
  md: "px-[var(--button-px-md)] py-[var(--button-py-md)] text-[length:var(--button-text-md)] leading-[var(--button-leading-md)]",
  lg: "px-[var(--button-px-lg)] py-[var(--button-py-lg)] text-[length:var(--button-text-lg)] leading-[var(--button-leading-lg)]",
};

const frontClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary text-primary-foreground",
  secondary: "bg-secondary text-secondary-foreground",
};

// Fold side: a faint tint at rest (back), a stronger one while the progress
// bar runs. Alpha utilities blend with the surrounding background so the
// effect adapts to light and dark themes.
const backClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary/15",
  secondary: "bg-secondary-foreground/15",
};

const barClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary/40",
  secondary: "bg-secondary-foreground/35",
};

const clampPercent = (value: number) => Math.max(0, Math.min(100, value));

const ProgressFoldButton = React.forwardRef<
  HTMLButtonElement,
  ProgressFoldButtonProps
>(
  (
    {
      className,
      style,
      children,
      variant = "primary",
      size = "md",
      status = "idle",
      progress,
      ...props
    },
    ref,
  ) => {
    const isLoading = status === "loading";
    const isDeterminate = isLoading && progress != null;
    const clamped = progress != null ? clampPercent(progress) : undefined;

    // Snap the fill to 0 on entering loading, then arm the smooth transition a
    // frame later so progress animates without the entry flashing from full.
    const [armed, setArmed] = React.useState(false);
    React.useEffect(() => {
      if (!isLoading) {
        setArmed(false);
        return;
      }
      setArmed(false);
      const id = requestAnimationFrame(() => setArmed(true));
      return () => cancelAnimationFrame(id);
    }, [isLoading]);

    return (
      <button
        ref={ref}
        type="button"
        data-variant={variant}
        data-size={size}
        data-status={isLoading ? "loading" : undefined}
        data-determinate={isDeterminate ? "true" : undefined}
        data-armed={armed ? "true" : undefined}
        aria-busy={isLoading || undefined}
        className={`${BUTTON_BASE} ${radiusClasses[size]} ${className ?? ""}`}
        style={
          clamped != null
            ? ({
                ...style,
                "--progress-fold-fill": clamped / 100,
              } as React.CSSProperties)
            : style
        }
        {...props}
      >
        <span
          className={`${LAYERS_BASE} ${radiusClasses[size]}`}
          aria-hidden="true"
        >
          <span className={`absolute inset-0 ${backClasses[variant]}`} />
          <span className={`${BAR_BASE} ${barClasses[variant]}`} />
        </span>
        <span
          data-slot="progress-fold-front"
          className={`${FRONT_BASE} ${frontSizeClasses[size]} ${frontClasses[variant]}`}
        >
          {children}
        </span>
        {isLoading ? (
          <span
            className="sr-only"
            role="progressbar"
            aria-valuemin={0}
            aria-valuemax={100}
            aria-valuenow={isDeterminate ? clamped : undefined}
            aria-valuetext={isDeterminate ? `${clamped}%` : "Loading"}
          />
        ) : null}
      </button>
    );
  },
);
ProgressFoldButton.displayName = "ProgressFoldButton";

export { ProgressFoldButton };

Progress Fold Button

By Lucas Bassetti

Try the interaction, copy the React source files, or download the complete example.

About Progress Fold Button

Progress Fold Button is an animated React and Tailwind CSS button by Lucas Bassetti. Try the interaction, copy the React source, or download the example with creator credit.

Effects and categories
Hover effects, Animated
Using this example
Copy a TSX file or download the original source and standalone demo. Test keyboard focus, motion and contrast in your own project.

Usage, Tailwind and licensing questions

Read the source files

import-examples/progress-fold-button.tsx

import {useState} from "react";import {ProgressFoldButton} from "@/packages/lab/src/progress-fold-button/progress-fold-button";export default function Demo(){const[status,setStatus]=useState<"idle"|"loading">("idle");return <ProgressFoldButton status={status} onClick={()=>{setStatus("loading");setTimeout(()=>setStatus("idle"),1400)}}>Save changes</ProgressFoldButton>}

packages/lab/src/progress-fold-button/progress-fold-button.tsx

"use client";

import * as React from "react";

export type ProgressFoldButtonVariant = "primary" | "secondary";
export type ProgressFoldButtonSize = "sm" | "md" | "lg";
export type ProgressFoldButtonStatus = "idle" | "loading";

export type ProgressFoldButtonProps =
  React.ButtonHTMLAttributes<HTMLButtonElement> & {
    variant?: ProgressFoldButtonVariant;
    size?: ProgressFoldButtonSize;
    /**
     * Loading lifecycle. `loading` folds the front face open and runs the
     * progress bar behind it. Fully controlled.
     */
    status?: ProgressFoldButtonStatus;
    /**
     * 0–100. With `status="loading"` a value makes the bar determinate (fills
     * to that percentage); omitting it makes the bar indeterminate (a segment
     * sweeps across).
     */
    progress?: number;
  };

// `group` drives the fold + progress state from the button's data-* attributes.
const BUTTON_BASE =
  "group relative inline-flex cursor-pointer select-none whitespace-nowrap border-none p-0 bg-border font-medium [perspective:800px] [transform-style:preserve-3d] [-webkit-tap-highlight-color:transparent] focus-visible:[outline:2px_solid_var(--ring)] focus-visible:[outline-offset:4px] disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none";

const LAYERS_BASE = "absolute inset-0 -z-[1] overflow-hidden";

// Folding front face — tilts back on hover / focus / while loading.
const FRONT_BASE =
  "relative grid w-full place-items-center rounded-[inherit] [transform:rotateX(0deg)] [transform-origin:top_center] [transition:transform_0.2s] group-hover:[transform:rotateX(35deg)] group-focus-visible:[transform:rotateX(35deg)] group-data-[status=loading]:[transform:rotateX(35deg)] motion-reduce:[transition:none]";

// Progress bar: determinate scales from the left to --progress-fold-fill
// (0–1, transition armed a frame after entering loading); indeterminate
// sweeps a fixed 40%-wide segment on a loop.
const BAR_BASE =
  "absolute top-0 left-0 h-full w-full origin-left [transform:scaleX(0)] group-data-[determinate=true]:[transform:scaleX(var(--progress-fold-fill,0))] group-[&[data-determinate=true][data-armed=true]]:[transition:transform_0.25s_ease] group-[&[data-status=loading]:not([data-determinate=true])]:w-[40%] group-[&[data-status=loading]:not([data-determinate=true])]:animate-progress-fold-indeterminate motion-reduce:group-[&[data-determinate=true][data-armed=true]]:[transition:none] motion-reduce:group-[&[data-status=loading]:not([data-determinate=true])]:animate-none";

// Outer button + clip layer share the per-size radius (--button-radius-*).
const radiusClasses: Record<ProgressFoldButtonSize, string> = {
  sm: "rounded-[var(--button-radius-sm)]",
  md: "rounded-[var(--button-radius-md)]",
  lg: "rounded-[var(--button-radius-lg)]",
};

const frontSizeClasses: Record<ProgressFoldButtonSize, string> = {
  sm: "px-[var(--button-px-sm)] py-[var(--button-py-sm)] text-[length:var(--button-text-sm)] leading-[var(--button-leading-sm)]",
  md: "px-[var(--button-px-md)] py-[var(--button-py-md)] text-[length:var(--button-text-md)] leading-[var(--button-leading-md)]",
  lg: "px-[var(--button-px-lg)] py-[var(--button-py-lg)] text-[length:var(--button-text-lg)] leading-[var(--button-leading-lg)]",
};

const frontClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary text-primary-foreground",
  secondary: "bg-secondary text-secondary-foreground",
};

// Fold side: a faint tint at rest (back), a stronger one while the progress
// bar runs. Alpha utilities blend with the surrounding background so the
// effect adapts to light and dark themes.
const backClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary/15",
  secondary: "bg-secondary-foreground/15",
};

const barClasses: Record<ProgressFoldButtonVariant, string> = {
  primary: "bg-primary/40",
  secondary: "bg-secondary-foreground/35",
};

const clampPercent = (value: number) => Math.max(0, Math.min(100, value));

const ProgressFoldButton = React.forwardRef<
  HTMLButtonElement,
  ProgressFoldButtonProps
>(
  (
    {
      className,
      style,
      children,
      variant = "primary",
      size = "md",
      status = "idle",
      progress,
      ...props
    },
    ref,
  ) => {
    const isLoading = status === "loading";
    const isDeterminate = isLoading && progress != null;
    const clamped = progress != null ? clampPercent(progress) : undefined;

    // Snap the fill to 0 on entering loading, then arm the smooth transition a
    // frame later so progress animates without the entry flashing from full.
    const [armed, setArmed] = React.useState(false);
    React.useEffect(() => {
      if (!isLoading) {
        setArmed(false);
        return;
      }
      setArmed(false);
      const id = requestAnimationFrame(() => setArmed(true));
      return () => cancelAnimationFrame(id);
    }, [isLoading]);

    return (
      <button
        ref={ref}
        type="button"
        data-variant={variant}
        data-size={size}
        data-status={isLoading ? "loading" : undefined}
        data-determinate={isDeterminate ? "true" : undefined}
        data-armed={armed ? "true" : undefined}
        aria-busy={isLoading || undefined}
        className={`${BUTTON_BASE} ${radiusClasses[size]} ${className ?? ""}`}
        style={
          clamped != null
            ? ({
                ...style,
                "--progress-fold-fill": clamped / 100,
              } as React.CSSProperties)
            : style
        }
        {...props}
      >
        <span
          className={`${LAYERS_BASE} ${radiusClasses[size]}`}
          aria-hidden="true"
        >
          <span className={`absolute inset-0 ${backClasses[variant]}`} />
          <span className={`${BAR_BASE} ${barClasses[variant]}`} />
        </span>
        <span
          data-slot="progress-fold-front"
          className={`${FRONT_BASE} ${frontSizeClasses[size]} ${frontClasses[variant]}`}
        >
          {children}
        </span>
        {isLoading ? (
          <span
            className="sr-only"
            role="progressbar"
            aria-valuemin={0}
            aria-valuemax={100}
            aria-valuenow={isDeterminate ? clamped : undefined}
            aria-valuetext={isDeterminate ? `${clamped}%` : "Loading"}
          />
        ) : null}
      </button>
    );
  },
);
ProgressFoldButton.displayName = "ProgressFoldButton";

export { ProgressFoldButton };

packages/components/theme/light.css

:root,
.light {
  /* shadcn default — neutral */
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);

  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);

  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.145 0 0);

  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);

  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);

  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);

  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);

  --destructive: oklch(0.577 0.245 27.325);

  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);

  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);

  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.145 0 0);

  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);

  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);

  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);

  /* Typography — set --font-geist-* in your app (see @godui/components/fonts) */
  --font-sans: var(
    --font-geist-sans,
    "Geist",
    ui-sans-serif,
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Helvetica Neue",
    Arial,
    "Noto Sans",
    sans-serif
  );

  --font-serif: var(
    --font-geist-sans,
    "Geist",
    ui-serif,
    Georgia,
    Cambria,
    "Times New Roman",
    Times,
    serif
  );

  --font-mono: var(
    --font-geist-mono,
    "Geist Mono",
    ui-monospace,
    SFMono-Regular,
    Menlo,
    Monaco,
    Consolas,
    "Liberation Mono",
    "Courier New",
    monospace
  );

  /* Radius */
  --radius: 0.625rem;

  /* Shadows */
  --shadow-2xs: 0 1px 2px rgb(0 0 0 / 0.02);

  --shadow-xs: 0 1px 3px rgb(0 0 0 / 0.04);

  --shadow-sm: 0 2px 6px rgb(0 0 0 / 0.05);

  --shadow: 0 4px 12px rgb(0 0 0 / 0.06);

  --shadow-md: 0 8px 20px rgb(0 0 0 / 0.08);

  --shadow-lg: 0 16px 32px rgb(0 0 0 / 0.1);

  --shadow-xl: 0 24px 48px rgb(0 0 0 / 0.12);

  --shadow-2xl: 0 40px 80px rgb(0 0 0 / 0.16);

  /* Syntax Highlighting */
  --syntax-plain: oklch(0.2 0.036 266);
  --syntax-punctuation: oklch(0.54 0.022 266);
  --syntax-keyword: oklch(0.52 0.19 302);
  --syntax-property: oklch(0.56 0.11 90);
  --syntax-string: oklch(0.52 0.106 168);
  --syntax-comment: oklch(0.63 0.016 266);
  --syntax-number: oklch(0.54 0.115 235);

  /* Inline code — track neutral theme tokens */
  --inline-code-bg: var(--muted);
  --inline-code-fg: var(--foreground);
  --inline-code-border: var(--border);

  /* Code blocks */
  --code-block: oklch(0.978 0 0);
  --code-block-foreground: oklch(0.205 0 0);
  --code-block-border: oklch(0.922 0 0);

  /* Search — track neutral theme tokens */
  --search-bg: var(--card);
  --search-fg: var(--muted-foreground);
  --search-border: var(--border);
  --search-kbd-bg: var(--muted);
  --search-kbd-fg: var(--muted-foreground);
  --search-placeholder: var(--muted-foreground);
  --search-highlight-bg: var(--primary);
  --search-highlight-fg: var(--primary-foreground);

  /* Theme panel — track neutral theme tokens */
  --theme-panel-bg: var(--card);
  --theme-panel-border: var(--border);
  --theme-panel-fg: var(--muted-foreground);
  --theme-panel-active-bg: var(--muted);
  --theme-panel-active-fg: var(--foreground);

  /* Z-index */
  --z-base: 0;
  --z-raised: 10;
  --z-overlay: 20;
  --z-sticky: 30;
  --z-popover: 40;
  --z-modal: 50;
  --z-toast: 60;

  /* GOD UI aliases */
  --color-bg: var(--background);
  --color-fg: var(--foreground);
  --color-border: var(--border);

  --color-primary: var(--primary);
  --color-primary-fg: var(--primary-foreground);

  --color-secondary-bg: var(--secondary);
  --color-secondary-fg: var(--secondary-foreground);

  --color-destructive: var(--destructive);
  --color-destructive-fg: oklch(1 0 0);

  /* Effects — sRGB triplets tracking --primary for rgba() consumers */
  --glow-highlight: 61, 102, 223;
  --color-primary-rgb: 61, 102, 223;

  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);

  /* GOD UI Brand — sapphire → light → divine gold */
  --god-gradient: linear-gradient(
    135deg,
    oklch(0.55 0.19 266) 0%,
    oklch(1 0 0) 50%,
    oklch(0.85 0.12 90) 100%
  );

  --god-glow:
    0 0 24px oklch(0.55 0.19 266 / 0.14), 0 0 80px oklch(0.85 0.12 90 / 0.06);

  /* Rainbow — sapphire, iris, aqua, rose, gold */
  --rainbow-1: oklch(0.55 0.19 266);
  --rainbow-2: oklch(0.68 0.16 305);
  --rainbow-3: oklch(0.82 0.1 185);
  --rainbow-4: oklch(0.78 0.12 14);
  --rainbow-5: oklch(0.8 0.13 90);

  --rainbow-speed: 2s;
}

/* Wide-gamut (P3) displays — restore the fuller chroma these tokens were
   authored with; the sRGB-clamped values above remain the fallback. */
@media (color-gamut: p3) {
  :root,
  .light {
    --syntax-string: oklch(0.52 0.13 168);
    --syntax-number: oklch(0.54 0.13 235);
  }
}

packages/components/theme/dark.css

@media (prefers-color-scheme: dark) {
  :root:not(.light) {
    /* shadcn default — neutral dark */
    --background: oklch(0.145 0 0);
    --foreground: oklch(0.985 0 0);

    --card: oklch(0.205 0 0);
    --card-foreground: oklch(0.985 0 0);

    --popover: oklch(0.205 0 0);
    --popover-foreground: oklch(0.985 0 0);

    --primary: oklch(0.922 0 0);
    --primary-foreground: oklch(0.205 0 0);

    --secondary: oklch(0.269 0 0);
    --secondary-foreground: oklch(0.985 0 0);

    --accent: oklch(0.269 0 0);
    --accent-foreground: oklch(0.985 0 0);

    --muted: oklch(0.269 0 0);
    --muted-foreground: oklch(0.708 0 0);

    --destructive: oklch(0.704 0.191 22.216);

    --border: oklch(1 0 0 / 10%);
    --input: oklch(1 0 0 / 15%);
    --ring: oklch(0.556 0 0);

    --chart-1: oklch(0.488 0.243 264.376);
    --chart-2: oklch(0.696 0.17 162.48);
    --chart-3: oklch(0.769 0.188 70.08);
    --chart-4: oklch(0.627 0.265 303.9);
    --chart-5: oklch(0.645 0.246 16.439);

    --sidebar: oklch(0.205 0 0);
    --sidebar-foreground: oklch(0.985 0 0);

    --sidebar-primary: oklch(0.488 0.243 264.376);
    --sidebar-primary-foreground: oklch(0.985 0 0);

    --sidebar-accent: oklch(0.269 0 0);
    --sidebar-accent-foreground: oklch(0.985 0 0);

    --sidebar-border: oklch(1 0 0 / 10%);
    --sidebar-ring: oklch(0.556 0 0);

    /* Syntax Highlighting */
    --syntax-plain: oklch(0.935 0.01 266);
    --syntax-punctuation: oklch(0.65 0.02 266);
    --syntax-keyword: oklch(0.78 0.135 302);
    --syntax-property: oklch(0.83 0.12 90);
    --syntax-string: oklch(0.8 0.13 168);
    --syntax-comment: oklch(0.58 0.02 266);
    --syntax-number: oklch(0.8 0.12 224);

    /* Code blocks */
    --code-block: oklch(0.185 0 0);
    --code-block-foreground: oklch(0.985 0 0);
    --code-block-border: oklch(0.27 0 0);

    /* Inline code — track neutral theme tokens */
    --inline-code-bg: var(--muted);
    --inline-code-fg: var(--foreground);
    --inline-code-border: var(--border);

    /* Search — track neutral theme tokens */
    --search-bg: var(--card);
    --search-fg: var(--muted-foreground);
    --search-border: var(--border);
    --search-kbd-bg: var(--muted);
    --search-kbd-fg: var(--muted-foreground);
    --search-placeholder: var(--muted-foreground);
    --search-highlight-bg: var(--primary);
    --search-highlight-fg: var(--primary-foreground);

    /* Theme panel — track neutral theme tokens */
    --theme-panel-bg: var(--card);
    --theme-panel-border: var(--border);
    --theme-panel-fg: var(--muted-foreground);
    --theme-panel-active-bg: var(--muted);
    --theme-panel-active-fg: var(--foreground);

    /* Shadows */
    --shadow-2xs: 0 1px 2px rgb(0 0 0 / 0.12);

    --shadow-xs: 0 1px 3px rgb(0 0 0 / 0.15);

    --shadow-sm: 0 2px 6px rgb(0 0 0 / 0.2);

    --shadow: 0 4px 12px rgb(0 0 0 / 0.25);

    --shadow-md: 0 8px 20px rgb(0 0 0 / 0.3);

    --shadow-lg: 0 16px 32px rgb(0 0 0 / 0.35);

    --shadow-xl: 0 24px 48px rgb(0 0 0 / 0.4);

    --shadow-2xl: 0 40px 80px rgb(0 0 0 / 0.5);

    /* GOD UI aliases */
    --color-bg: var(--background);
    --color-fg: var(--foreground);
    --color-border: var(--border);

    --color-primary: var(--primary);
    --color-primary-fg: var(--primary-foreground);

    --color-secondary-bg: var(--secondary);
    --color-secondary-fg: var(--secondary-foreground);

    --color-destructive: var(--destructive);
    --color-destructive-fg: oklch(1 0 0);

    /* Effects — sRGB triplets tracking --primary for rgba() consumers */
    --glow-highlight: 66, 108, 229;
    --color-primary-rgb: 66, 108, 229;

    --radius-md: calc(var(--radius) - 2px);
    --radius-lg: var(--radius);

    /* GOD UI Brand — sapphire → light → divine gold */
    --god-gradient: linear-gradient(
      135deg,
      oklch(0.57 0.19 266) 0%,
      oklch(1 0 0) 50%,
      oklch(0.86 0.12 90) 100%
    );

    --god-glow:
      0 0 24px oklch(0.57 0.19 266 / 0.28), 0 0 80px oklch(0.86 0.12 90 / 0.12);

    --rainbow-1: oklch(0.72 0.145 266);
    --rainbow-2: oklch(0.74 0.16 305);
    --rainbow-3: oklch(0.84 0.1 185);
    --rainbow-4: oklch(0.8 0.116 14);
    --rainbow-5: oklch(0.84 0.13 90);

    --rainbow-speed: 2s;
  }
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);

  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);

  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);

  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);

  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);

  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);

  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);

  --destructive: oklch(0.704 0.191 22.216);

  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.556 0 0);

  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);

  --sidebar: oklch(0.205 0 0);
  --sidebar-foreground: oklch(0.985 0 0);

  --sidebar-primary: oklch(0.488 0.243 264.376);
  --sidebar-primary-foreground: oklch(0.985 0 0);

  --sidebar-accent: oklch(0.269 0 0);
  --sidebar-accent-foreground: oklch(0.985 0 0);

  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.556 0 0);

  --syntax-plain: oklch(0.935 0.01 266);
  --syntax-punctuation: oklch(0.65 0.02 266);
  --syntax-keyword: oklch(0.78 0.135 302);
  --syntax-property: oklch(0.83 0.12 90);
  --syntax-string: oklch(0.8 0.13 168);
  --syntax-comment: oklch(0.58 0.02 266);
  --syntax-number: oklch(0.8 0.12 224);

  --code-block: oklch(0.185 0 0);
  --code-block-foreground: oklch(0.985 0 0);
  --code-block-border: oklch(0.27 0 0);

  --inline-code-bg: var(--muted);
  --inline-code-fg: var(--foreground);
  --inline-code-border: var(--border);

  --search-bg: var(--card);
  --search-fg: var(--muted-foreground);
  --search-border: var(--border);
  --search-kbd-bg: var(--muted);
  --search-kbd-fg: var(--muted-foreground);
  --search-placeholder: var(--muted-foreground);
  --search-highlight-bg: var(--primary);
  --search-highlight-fg: var(--primary-foreground);

  --theme-panel-bg: var(--card);
  --theme-panel-border: var(--border);
  --theme-panel-fg: var(--muted-foreground);
  --theme-panel-active-bg: var(--muted);
  --theme-panel-active-fg: var(--foreground);

  --shadow-2xs: 0 1px 2px rgb(0 0 0 / 0.12);
  --shadow-xs: 0 1px 3px rgb(0 0 0 / 0.15);
  --shadow-sm: 0 2px 6px rgb(0 0 0 / 0.2);
  --shadow: 0 4px 12px rgb(0 0 0 / 0.25);
  --shadow-md: 0 8px 20px rgb(0 0 0 / 0.3);
  --shadow-lg: 0 16px 32px rgb(0 0 0 / 0.35);
  --shadow-xl: 0 24px 48px rgb(0 0 0 / 0.4);
  --shadow-2xl: 0 40px 80px rgb(0 0 0 / 0.5);

  --color-bg: var(--background);
  --color-fg: var(--foreground);
  --color-border: var(--border);

  --color-primary: var(--primary);
  --color-primary-fg: var(--primary-foreground);

  --color-secondary-bg: var(--secondary);
  --color-secondary-fg: var(--secondary-foreground);

  --color-destructive: var(--destructive);
  --color-destructive-fg: oklch(1 0 0);

  --glow-highlight: 66, 108, 229;
  --color-primary-rgb: 66, 108, 229;

  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);

  --god-gradient: linear-gradient(
    135deg,
    oklch(0.57 0.19 266) 0%,
    oklch(1 0 0) 50%,
    oklch(0.86 0.12 90) 100%
  );

  --god-glow:
    0 0 24px oklch(0.57 0.19 266 / 0.28), 0 0 80px oklch(0.86 0.12 90 / 0.12);

  --rainbow-1: oklch(0.72 0.145 266);
  --rainbow-2: oklch(0.74 0.16 305);
  --rainbow-3: oklch(0.84 0.1 185);
  --rainbow-4: oklch(0.8 0.116 14);
  --rainbow-5: oklch(0.84 0.13 90);
  --rainbow-speed: 2s;
}

/* Wide-gamut (P3) displays — restore the fuller chroma these tokens were
   authored with; the sRGB-clamped values above remain the fallback. */
@media (color-gamut: p3) {
  @media (prefers-color-scheme: dark) {
    :root:not(.light) {
      --syntax-keyword: oklch(0.78 0.14 302);
      --rainbow-1: oklch(0.72 0.15 266);
      --rainbow-4: oklch(0.8 0.12 14);
    }
  }

  .dark {
    --syntax-keyword: oklch(0.78 0.14 302);
    --rainbow-1: oklch(0.72 0.15 266);
    --rainbow-4: oklch(0.8 0.12 14);
  }
}

packages/components/styles.css

@import "tailwindcss";
@import "./theme/light.css";
@import "./theme/dark.css";

@source "./src";

@custom-variant dark (&:where(.dark, .dark *));

@layer base {
  :is(code, kbd, samp, pre) {
    font-family: var(--font-mono);
  }
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-chart-1: var(--chart-1);
  --color-chart-2: var(--chart-2);
  --color-chart-3: var(--chart-3);
  --color-chart-4: var(--chart-4);
  --color-chart-5: var(--chart-5);
  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-ring: var(--sidebar-ring);

  --font-sans: var(--font-sans);
  --font-mono: var(--font-mono);
  --font-serif: var(--font-serif);

  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  /* Shared button size scale — single source of truth for all buttons (sm/md/lg) */
  --button-py-sm: 0.5rem;
  --button-px-sm: 1rem;
  --button-text-sm: 0.875rem;
  --button-leading-sm: 1.25rem;
  --button-radius-sm: var(--radius-md);

  --button-py-md: 0.75rem;
  --button-px-md: 1.5rem;
  --button-text-md: 0.875rem;
  --button-leading-md: 1.25rem;
  --button-radius-md: var(--radius-lg);

  --button-py-lg: 1rem;
  --button-px-lg: 2rem;
  --button-text-lg: 1rem;
  --button-leading-lg: 1.5rem;
  --button-radius-lg: var(--radius-xl);

  --shadow-2xs: var(--shadow-2xs);
  --shadow-xs: var(--shadow-xs);
  --shadow-sm: var(--shadow-sm);
  --shadow: var(--shadow);
  --shadow-md: var(--shadow-md);
  --shadow-lg: var(--shadow-lg);
  --shadow-xl: var(--shadow-xl);
  --shadow-2xl: var(--shadow-2xl);

  --z-index-base: var(--z-base);
  --z-index-raised: var(--z-raised);
  --z-index-overlay: var(--z-overlay);
  --z-index-sticky: var(--z-sticky);
  --z-index-popover: var(--z-popover);
  --z-index-modal: var(--z-modal);
  --z-index-toast: var(--z-toast);
}

/* ── godui-motion ─────────────────────────────────────────────────────────────
 * Shared motion tokens for core components. GPU-only: every keyframe animates
 * opacity / scale / translate. Mirrored in the `godui-motion` registry entry.
 * Springs are CSS linear() approximations (stiffness k / damping c noted). */
@theme inline {
  /* k=500 c=40, settles ≈374ms */
  --ease-spring-snappy: linear(
    0,
    0.0536,
    0.1667,
    0.3015,
    0.436,
    0.5582,
    0.663,
    0.7491,
    0.8194,
    0.8719,
    0.9113,
    0.9403,
    0.9612,
    0.9758,
    0.9857,
    0.9923,
    0.9967,
    0.9992,
    1.0006,
    1.0013,
    1.0016,
    1.0016,
    1.0014,
    1.0012,
    1
  );
  /* k=260 c=32, settles ≈563ms */
  --ease-spring-smooth: linear(
    0,
    0.0575,
    0.1789,
    0.3182,
    0.4518,
    0.5693,
    0.6676,
    0.747,
    0.8095,
    0.8579,
    0.8949,
    0.9227,
    0.9431,
    0.9586,
    0.9701,
    0.9784,
    0.9845,
    0.9889,
    0.9921,
    0.9943,
    0.996,
    0.9972,
    0.998,
    0.9986,
    1
  );
  /* k=380 c=18, settles ≈771ms, ~19% overshoot */
  --ease-spring-bouncy: linear(
    0,
    0.1642,
    0.4963,
    0.8272,
    1.0624,
    1.1772,
    1.1892,
    1.1415,
    1.0741,
    1.0143,
    0.9772,
    0.963,
    0.9656,
    0.9772,
    0.9902,
    1.0003,
    1.0058,
    1.0073,
    1.006,
    1.0035,
    1.0011,
    0.9995,
    0.9987,
    0.9986,
    1
  );
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);

  --animate-godui-fade-scale-in: godui-fade-scale-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
  --animate-godui-fade-scale-out: godui-fade-scale-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-slide-in-from-top: godui-slide-in-from-top
    var(--godui-duration-base) var(--ease-spring-snappy) backwards;
  --animate-godui-slide-in-from-right: godui-slide-in-from-right
    var(--godui-duration-slow) var(--ease-spring-smooth) backwards;
  --animate-godui-slide-in-from-bottom: godui-slide-in-from-bottom
    var(--godui-duration-base) var(--ease-spring-snappy) backwards;
  --animate-godui-slide-in-from-left: godui-slide-in-from-left
    var(--godui-duration-slow) var(--ease-spring-smooth) backwards;
  --animate-godui-slide-out-to-top: godui-slide-out-to-top
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-slide-out-to-right: godui-slide-out-to-right
    var(--godui-duration-base) var(--ease-out-expo) both;
  --animate-godui-slide-out-to-bottom: godui-slide-out-to-bottom
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-slide-out-to-left: godui-slide-out-to-left
    var(--godui-duration-base) var(--ease-out-expo) both;
  --animate-godui-pop: godui-pop var(--godui-duration-base)
    var(--ease-spring-bouncy);
  --animate-godui-fade-in: godui-fade-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
  --animate-godui-fade-out: godui-fade-out var(--godui-duration-fast)
    var(--ease-out-expo) both;
  --animate-godui-popover-in: godui-popover-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
  --animate-godui-popover-out: godui-popover-out var(--godui-duration-fast)
    var(--ease-out-expo) both;
  /* Holds a closing Accordion / Collapsible panel (see godui-reveal-hold). */
  --animate-godui-reveal-hold: godui-reveal-hold var(--godui-duration-base)
    linear;
}

:root {
  --godui-duration-fast: 150ms;
  --godui-duration-base: 260ms;
  --godui-duration-slow: 380ms;
  --godui-enter-scale: 0.96;
  --godui-enter-distance: 0.5rem;
  --godui-pop-scale: 0.96;
  /* Popover drift toward the trigger; components set these per Radix side. */
  --godui-enter-x: 0px;
  --godui-enter-y: 0px;
  /* Movement multiplier: 1 normally, 0 under reduced motion. Set only here, so
   * a component's local --godui-enter-distance can't outrank reduced motion. */
  --godui-motion: 1;
}

/* Reduced motion: nothing moves or scales; animations become short fades. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --godui-enter-scale: 1;
    --godui-enter-distance: 0px;
    --godui-pop-scale: 1;
    --godui-motion: 0;
    --godui-duration-base: 150ms;
    --godui-duration-slow: 150ms;
  }
}

@keyframes godui-fade-scale-in {
  from {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
  }
}
@keyframes godui-fade-scale-out {
  to {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-top {
  from {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * -1 * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-right {
  from {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-in-from-bottom {
  from {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-left {
  from {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * -1 * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-out-to-top {
  to {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * -1 * var(--godui-motion));
  }
}
@keyframes godui-slide-out-to-right {
  to {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-out-to-bottom {
  to {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * var(--godui-motion));
  }
}
@keyframes godui-slide-out-to-left {
  to {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * -1 * var(--godui-motion)) 0;
  }
}
@keyframes godui-pop {
  40% {
    scale: calc(1 - (1 - var(--godui-pop-scale)) * var(--godui-motion));
  }
}
@keyframes godui-fade-in {
  from {
    opacity: 0;
  }
}
@keyframes godui-fade-out {
  to {
    opacity: 0;
  }
}
@keyframes godui-popover-in {
  from {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
    translate: calc(var(--godui-enter-x) * var(--godui-motion))
      calc(var(--godui-enter-y) * var(--godui-motion));
  }
}
@keyframes godui-popover-out {
  to {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
    translate: calc(var(--godui-enter-x) * var(--godui-motion))
      calc(var(--godui-enter-y) * var(--godui-motion));
  }
}
/* Keeps Radix Presence from hiding a closing Accordion / Collapsible panel
 * until its clip edge (animated in JS by useReveal, on translate) has swept
 * up. 0.99, not 1: Chrome won't composite an animation with no visible
 * change; the panel is hidden when it ends. */
@keyframes godui-reveal-hold {
  to {
    opacity: 0.99;
  }
}

/* ── calendar ────────────────────────────────────────────────────────────────
 * Component keyframes (also in the calendar registry entry). The --godui-
 * calendar-* tuning variables are set on the Calendar root; every distance
 * and delay is multiplied by --godui-motion. No blur: Chrome won't composite
 * a filter that moves pixels, so a blurred month change runs on the main
 * thread. Month change: the old weeks leave fast and short, the new ones
 * arrive a beat later from further away. The exit fades on
 * --godui-calendar-ease-out (an ease-out quad), not expo: expo empties the
 * old month before the new one shows (both together dip to 16% opacity, a
 * blink); quad keeps them above 65%. react-day-picker drops the old month on the old
 * caption's animationend, so the caption's exit (and the dropdown caption's
 * hide) last delay + base, the moment the new weeks land. The caption is
 * text on text, so it doesn't cross-fade like the grid: the old one is gone
 * by 30% of that, the new one starts --godui-calendar-caption-lag after the
 * weeks and ends with them. */
@theme inline {
  --animate-godui-calendar-in-from-end: godui-calendar-in-from-end
    var(--godui-duration-base) var(--ease-spring-snappy)
    calc(var(--godui-calendar-delay) * var(--godui-motion)) backwards;
  --animate-godui-calendar-in-from-start: godui-calendar-in-from-start
    var(--godui-duration-base) var(--ease-spring-snappy)
    calc(var(--godui-calendar-delay) * var(--godui-motion)) backwards;
  --animate-godui-calendar-out-to-start: godui-calendar-out-to-start
    var(--godui-duration-fast) var(--godui-calendar-ease-out) both;
  --animate-godui-calendar-out-to-end: godui-calendar-out-to-end
    var(--godui-duration-fast) var(--godui-calendar-ease-out) both;
  --animate-godui-calendar-caption-in-from-end: godui-calendar-caption-in-from-end
    calc(
      var(--godui-duration-base) -
      var(--godui-calendar-caption-lag) *
      var(--godui-motion)
    )
    var(--ease-spring-snappy)
    calc(
      (var(--godui-calendar-delay) + var(--godui-calendar-caption-lag)) *
      var(--godui-motion)
    )
    backwards;
  --animate-godui-calendar-caption-in-from-start: godui-calendar-caption-in-from-start
    calc(
      var(--godui-duration-base) -
      var(--godui-calendar-caption-lag) *
      var(--godui-motion)
    )
    var(--ease-spring-snappy)
    calc(
      (var(--godui-calendar-delay) + var(--godui-calendar-caption-lag)) *
      var(--godui-motion)
    )
    backwards;
  --animate-godui-calendar-caption-out-to-start: godui-calendar-caption-out-to-start
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
  --animate-godui-calendar-caption-out-to-end: godui-calendar-caption-out-to-end
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
  --animate-godui-calendar-caption-hide: godui-calendar-caption-hide
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
  --animate-godui-calendar-fill-in: godui-calendar-fill-in
    var(--godui-duration-base) var(--ease-spring-bouncy) backwards;
  --animate-godui-calendar-fade-out: godui-calendar-fade-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-calendar-fill-shrink: godui-calendar-fill-shrink
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-calendar-track-in: godui-calendar-track-in
    calc(
      var(--godui-calendar-track-span, 1) *
      var(--godui-calendar-sweep) *
      var(--godui-motion) +
      var(--godui-duration-fast) *
      (1 - var(--godui-motion))
    )
    linear
    calc(
      var(--godui-calendar-track-at, 0) *
      var(--godui-calendar-sweep) *
      var(--godui-motion)
    )
    backwards;
  --animate-godui-calendar-ghost-glide: godui-calendar-ghost-glide
    calc(var(--godui-calendar-preview-sweep) * var(--godui-motion))
    cubic-bezier(0.33, 1, 0.68, 1) backwards;
}
@keyframes godui-calendar-in-from-end {
  from {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-drift) *
        var(--godui-calendar-dir) *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-in-from-start {
  from {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-drift) *
        var(--godui-calendar-dir) *
        -1 *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-out-to-start {
  to {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-drift-out) *
        var(--godui-calendar-dir) *
        -1 *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-out-to-end {
  to {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-drift-out) *
        var(--godui-calendar-dir) *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-caption-in-from-end {
  from {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-caption-drift) *
        var(--godui-calendar-dir) *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-caption-in-from-start {
  from {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-caption-drift) *
        var(--godui-calendar-dir) *
        -1 *
        var(--godui-motion)
      )
      0;
  }
}
/* The caption exits' curve is --godui-calendar-ease-out written out: Chrome
 * doesn't resolve var() in a keyframe's animation-timing-function (it falls
 * back to linear). */
@keyframes godui-calendar-caption-out-to-start {
  0% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }
  30%,
  100% {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-caption-drift) *
        var(--godui-calendar-dir) *
        -0.5 *
        var(--godui-motion)
      )
      0;
  }
}
@keyframes godui-calendar-caption-out-to-end {
  0% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }
  30%,
  100% {
    opacity: 0;
    translate: calc(
        var(--godui-calendar-caption-drift) *
        var(--godui-calendar-dir) *
        0.5 *
        var(--godui-motion)
      )
      0;
  }
}
/* The old dropdown caption, hidden for the whole change: 0 → 0.01, not 0
 * throughout — Chrome won't composite an animation with no visible change. */
@keyframes godui-calendar-caption-hide {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.01;
  }
}
/* A picked day's fill (and its copy of the number) grows from 60% while it
 * fades in over the first third; the spring overshoots to ≈108%. */
@keyframes godui-calendar-fill-in {
  0% {
    opacity: 0;
    scale: calc(1 - 0.4 * var(--godui-motion));
  }
  35% {
    opacity: 1;
  }
}
/* A layer leaving (a deselected day's fill, a range track half): from 1,
 * explicitly — its resting style is already opacity 0, so it stays hidden
 * once the fade ends and inside rdp's clone of the old month. */
@keyframes godui-calendar-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
/* …while a deselected day's fill (the layer's ::before) shrinks. */
@keyframes godui-calendar-fill-shrink {
  to {
    scale: calc(1 - 0.15 * var(--godui-motion));
  }
}
/* A range track half grows across from the side its sweep comes from, in its
 * slice of the sweep (linear: the halves run back to back, one continuous
 * front); under reduced motion every half fades in at once, in fast. */
@keyframes godui-calendar-track-in {
  from {
    opacity: var(--godui-motion);
    scale: calc(1 - var(--godui-motion)) 1;
  }
}
/* A range preview's ghost end moving along a row slides in from the previous
 * end (--godui-calendar-ghost-from days away; a column is the pill's own
 * width) on the ease-out cubic the track's front follows, over the same
 * --godui-calendar-preview-sweep: the pill rides the front. Under reduced
 * motion it takes no time: it snaps. */
@keyframes godui-calendar-ghost-glide {
  from {
    translate: calc(
        var(--godui-calendar-ghost-from, 0) *
        100% *
        var(--godui-calendar-dir) *
        var(--godui-motion)
      )
      0;
  }
}

/* ── checkbox ────────────────────────────────────────────────────────────────
 * Component keyframes (also in the checkbox registry entry). Scale, translate
 * and opacity. The disc rests at scale 1.42 (a circle the box's diagonal
 * wide), so it grows from and drains to 1.42 × (1 - motion): a dot, or under
 * reduced motion no scale and a fade instead. The check's window slides in
 * from -100% while the mark slides back from +100% on the same clock, so the
 * stroke holds still; it starts 70ms in and ends with the disc and the
 * box's pop (staggered ends would each cost a layout frame). The hold keeps Presence from removing the indicator
 * until the ink has drained (godui-reveal-hold, from godui-motion). */
@theme inline {
  --animate-godui-checkbox-fill-in: godui-checkbox-fill-in
    var(--godui-duration-base) var(--ease-spring-smooth) backwards;
  --animate-godui-checkbox-fill-out: godui-checkbox-fill-out
    var(--godui-duration-fast) var(--ease-spring-smooth) both;
  --animate-godui-checkbox-draw: godui-checkbox-draw
    calc(var(--godui-duration-base) - 70ms * var(--godui-motion))
    var(--ease-spring-smooth) calc(70ms * var(--godui-motion)) backwards;
  --animate-godui-checkbox-ink: godui-checkbox-ink
    calc(var(--godui-duration-base) - 70ms * var(--godui-motion))
    var(--ease-spring-smooth) calc(70ms * var(--godui-motion)) backwards;
  --animate-godui-checkbox-check-out: godui-checkbox-check-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
  --animate-godui-checkbox-hold: godui-reveal-hold var(--godui-duration-fast)
    linear;
}
@keyframes godui-checkbox-fill-in {
  from {
    opacity: var(--godui-motion);
    scale: calc(1.42 * (1 - var(--godui-motion)));
  }
}
@keyframes godui-checkbox-fill-out {
  to {
    opacity: var(--godui-motion);
    scale: calc(1.42 * (1 - var(--godui-motion)));
  }
}
@keyframes godui-checkbox-draw {
  from {
    translate: calc(-100% * var(--godui-motion)) 0;
  }
}
@keyframes godui-checkbox-ink {
  from {
    opacity: var(--godui-motion);
    translate: calc(100% * var(--godui-motion)) 0;
  }
}
@keyframes godui-checkbox-check-out {
  to {
    opacity: 0;
    scale: calc(1 - 0.3 * var(--godui-motion));
  }
}

/* ── input-otp ───────────────────────────────────────────────────────────────
 * Component keyframe (also in the input-otp registry entry). Opacity only. */
@theme inline {
  --animate-godui-caret-blink: godui-caret-blink 1.25s ease-out infinite;
}
@keyframes godui-caret-blink {
  0%,
  70%,
  100% {
    opacity: 1;
  }
  20%,
  50% {
    opacity: 0;
  }
}

/* ── progress ────────────────────────────────────────────────────────────────
 * Component keyframe (also in the progress registry entry). Transform only:
 * the indeterminate bar sweeps across the track on a symmetric ease-in-out.
 * An animation beats the indicator's inline transform. */
@theme inline {
  --animate-godui-progress-indeterminate: godui-progress-indeterminate 1.4s
    cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes godui-progress-indeterminate {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(250%);
  }
}

/* ── skeleton ────────────────────────────────────────────────────────────────
 * Component keyframe (also in the skeleton registry entry). Transform only:
 * the ::after band starts fully outside the block on the left
 * (-translate-x-full) and the animation moves it fully outside on the right. */
@theme inline {
  --animate-godui-shimmer: godui-shimmer 1.6s cubic-bezier(0.65, 0, 0.35, 1)
    infinite;
}
@keyframes godui-shimmer {
  to {
    translate: 100% 0;
  }
}

packages/lab/styles.css

/* GodUI Lab — per-component animation tokens + keyframes.
 * Import AFTER @godui/components/styles.css. Tokens stay in `@theme inline`
 * because they reference per-element vars (e.g. --speed). */

@source "./src";

@theme inline {
  --animate-shimmer-slide: shimmer-slide var(--speed) ease-in-out infinite
    alternate;
  --animate-spin-around: spin-around calc(var(--speed) * 2) infinite linear;

  --animate-aurora-text: aurora-text var(--aurora-text-speed, 10s) infinite
    linear;

  --animate-magic-rainbow: magic-rainbow var(--rainbow-speed, 2s) infinite
    linear;
  --animate-magic-input-indeterminate: magic-input-indeterminate 1.2s
    ease-in-out infinite alternate;
  --animate-magic-input-sweep: magic-input-sweep 220ms ease-out;
  --animate-magic-input-spin: magic-input-spin 0.8s linear infinite;
  --animate-progress-fold-indeterminate: progress-fold-indeterminate 1.2s
    ease-in-out infinite;

  /* Blueprint grid: a light band sweeps across the lattice */
  --animate-blueprint-sweep: blueprint-sweep var(--blueprint-speed, 8s) linear
    infinite;

  /* Light rays: god-rays rotate and breathe */
  --animate-light-rays-sweep: light-rays-sweep var(--rays-speed, 14s)
    ease-in-out infinite alternate;

  /* Marquee: seamless track scroll (duration driven by the `--duration` var) */
  --animate-marquee: marquee var(--duration, 40s) linear infinite;
  --animate-marquee-vertical: marquee-vertical var(--duration, 40s) linear
    infinite;

  /* App showcase: the phone screen auto-scrolls its screenshot on a loop */
  --animate-app-showcase-scroll: app-showcase-scroll var(--as-loop, 24s) linear
    infinite;

  /* Mask flipbook — one token per sprite (step counts differ) */
  --animate-mask-nature-in: mask-button-in 0.7s steps(22) forwards;
  --animate-mask-nature-out: mask-button-out 0.7s steps(22) forwards;
  --animate-mask-urban-in: mask-button-in 0.7s steps(29) forwards;
  --animate-mask-urban-out: mask-button-out 0.7s steps(29) forwards;
  --animate-mask-forest-in: mask-button-in 0.7s steps(70) forwards;
  --animate-mask-forest-out: mask-button-out 0.7s steps(70) forwards;

  /* Voice orb: corona rotation, idle breathing, and the listening ring pulse */
  --animate-voice-orb-spin: voice-orb-spin 8s linear infinite;
  --animate-voice-orb-breathe: voice-orb-breathe 4s ease-in-out infinite;
  --animate-voice-orb-ring: voice-orb-ring 1.6s ease-out infinite;

  /* Split-flap: the old top leaf falls away, then the new bottom leaf rises */
  --animate-split-flap-fall: split-flap-fall 0.12s
    cubic-bezier(0.3, 0.7, 0.4, 1) forwards;
  --animate-split-flap-rise: split-flap-rise 0.12s
    cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes voice-orb-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes voice-orb-breathe {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.04);
  }
}

@keyframes voice-orb-ring {
  0% {
    transform: scale(0.85);
    opacity: 0.6;
  }
  100% {
    transform: scale(1.4);
    opacity: 0;
  }
}

/* Split-flap: top leaf hinges down and away (front carries the old glyph top) */
@keyframes split-flap-fall {
  from {
    transform: rotateX(0deg);
  }
  to {
    transform: rotateX(-90deg);
  }
}

/* Split-flap: bottom leaf hinges up into place (front carries the new glyph bottom) */
@keyframes split-flap-rise {
  from {
    transform: rotateX(90deg);
  }
  to {
    transform: rotateX(0deg);
  }
}

@keyframes shimmer-slide {
  to {
    transform: translate(calc(100cqw - 100%), 0);
  }
}

@keyframes spin-around {
  0% {
    transform: translateZ(0) rotate(0);
  }
  15%,
  35% {
    transform: translateZ(0) rotate(90deg);
  }
  65%,
  85% {
    transform: translateZ(0) rotate(270deg);
  }
  100% {
    transform: translateZ(0) rotate(360deg);
  }
}

/* Aurora text: gradient drifts back and forth across the clipped text */
@keyframes aurora-text {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

@keyframes magic-rainbow {
  0% {
    background-position: 0% 50%;
  }
  100% {
    background-position: 200% 50%;
  }
}

/* Magic input: indeterminate fill segment bouncing end to end (right→left) */
@keyframes magic-input-indeterminate {
  from {
    background-position: 110% center;
  }
  to {
    background-position: -10% center;
  }
}

/* Magic input: success / error fill sweeping in from the left */
@keyframes magic-input-sweep {
  from {
    background-size: 0% 100%;
  }
  to {
    background-size: 100% 100%;
  }
}

/* Magic input: spinner rotation */
@keyframes magic-input-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Mask button: flipbook reveal driven by a sprite-sheet mask-position */
@keyframes mask-button-in {
  from {
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
  }
  to {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
  }
}

@keyframes mask-button-out {
  from {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
  }
  to {
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
  }
}

/* Marquee: track scrolls one full copy (plus the gap) then loops seamlessly */
@keyframes marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% - var(--gap)));
  }
}

@keyframes marquee-vertical {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(calc(-100% - var(--gap)));
  }
}

/* App showcase: track holds two stacked copies; scroll one full copy up */
@keyframes app-showcase-scroll {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}

/* Progress fold button: indeterminate segment sweeping left→right */
@keyframes progress-fold-indeterminate {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}

/* Blueprint grid: a diagonal light band travels across the lattice */
@keyframes blueprint-sweep {
  0% {
    transform: translate(-50%, -50%) rotate(var(--blueprint-angle, 25deg));
    opacity: 0;
  }
  15%,
  85% {
    opacity: 1;
  }
  100% {
    transform: translate(150%, 150%) rotate(var(--blueprint-angle, 25deg));
    opacity: 0;
  }
}

/* Light rays: the ray fan slowly rotates and breathes in intensity */
@keyframes light-rays-sweep {
  0% {
    transform: rotate(calc(var(--rays-angle, 0deg) - 6deg)) scale(1);
    opacity: calc(var(--rays-intensity, 0.6) * 0.7);
  }
  100% {
    transform: rotate(calc(var(--rays-angle, 0deg) + 6deg)) scale(1.08);
    opacity: var(--rays-intensity, 0.6);
  }
}

demo.tsx

import "@/packages/components/styles.css";
import "@/packages/lab/styles.css";
export { default as default } from "@/import-examples/progress-fold-button";

CSS

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
  :root, :host {
    --font-sans: var(--font-sans);
    --font-serif: var(--font-serif);
    --font-mono: var(--font-mono);
    --font-weight-medium: 500;
    --radius-sm: calc(var(--radius) - 4px);
    --radius-md: calc(var(--radius) - 2px);
    --radius-lg: var(--radius);
    --radius-xl: calc(var(--radius) + 4px);
    --shadow-2xs: var(--shadow-2xs);
    --shadow-xs: var(--shadow-xs);
    --shadow-sm: var(--shadow-sm);
    --shadow-md: var(--shadow-md);
    --shadow-lg: var(--shadow-lg);
    --shadow-xl: var(--shadow-xl);
    --shadow-2xl: var(--shadow-2xl);
    --ease-out: cubic-bezier(0, 0, 0.2, 1);
    --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
    --default-transition-duration: 150ms;
    --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    --default-font-family: var(--font-sans);
    --default-mono-font-family: var(--font-mono);
    --shadow: var(--shadow);
    --color-background: var(--background);
    --color-foreground: var(--foreground);
    --color-primary: var(--primary);
    --color-primary-foreground: var(--primary-foreground);
    --color-secondary: var(--secondary);
    --color-secondary-foreground: var(--secondary-foreground);
    --color-muted: var(--muted);
    --color-muted-foreground: var(--muted-foreground);
    --color-accent: var(--accent);
    --color-accent-foreground: var(--accent-foreground);
    --color-border: var(--border);
    --color-input: var(--input);
    --color-ring: var(--ring);
    --color-destructive: var(--destructive);
    --color-popover: var(--popover);
    --color-popover-foreground: var(--popover-foreground);
    --color-card: var(--card);
    --color-card-foreground: var(--card-foreground);
    --color-chart-1: var(--chart-1);
    --color-chart-2: var(--chart-2);
    --color-chart-3: var(--chart-3);
    --color-chart-4: var(--chart-4);
    --color-chart-5: var(--chart-5);
    --color-sidebar: var(--sidebar);
    --color-sidebar-foreground: var(--sidebar-foreground);
    --color-sidebar-primary: var(--sidebar-primary);
    --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
    --color-sidebar-accent: var(--sidebar-accent);
    --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
    --color-sidebar-border: var(--sidebar-border);
    --color-sidebar-ring: var(--sidebar-ring);
    --button-py-sm: 0.5rem;
    --button-px-sm: 1rem;
    --button-text-sm: 0.875rem;
    --button-leading-sm: 1.25rem;
    --button-radius-sm: var(--radius-md);
    --button-py-md: 0.75rem;
    --button-px-md: 1.5rem;
    --button-text-md: 0.875rem;
    --button-leading-md: 1.25rem;
    --button-radius-md: var(--radius-lg);
    --button-py-lg: 1rem;
    --button-px-lg: 2rem;
    --button-text-lg: 1rem;
    --button-leading-lg: 1.5rem;
    --button-radius-lg: var(--radius-xl);
    --z-index-base: var(--z-base);
    --z-index-raised: var(--z-raised);
    --z-index-overlay: var(--z-overlay);
    --z-index-sticky: var(--z-sticky);
    --z-index-popover: var(--z-popover);
    --z-index-modal: var(--z-modal);
    --z-index-toast: var(--z-toast);
    --ease-spring-snappy: linear(
    0,
    0.0536,
    0.1667,
    0.3015,
    0.436,
    0.5582,
    0.663,
    0.7491,
    0.8194,
    0.8719,
    0.9113,
    0.9403,
    0.9612,
    0.9758,
    0.9857,
    0.9923,
    0.9967,
    0.9992,
    1.0006,
    1.0013,
    1.0016,
    1.0016,
    1.0014,
    1.0012,
    1
  );
    --ease-spring-smooth: linear(
    0,
    0.0575,
    0.1789,
    0.3182,
    0.4518,
    0.5693,
    0.6676,
    0.747,
    0.8095,
    0.8579,
    0.8949,
    0.9227,
    0.9431,
    0.9586,
    0.9701,
    0.9784,
    0.9845,
    0.9889,
    0.9921,
    0.9943,
    0.996,
    0.9972,
    0.998,
    0.9986,
    1
  );
    --ease-spring-bouncy: linear(
    0,
    0.1642,
    0.4963,
    0.8272,
    1.0624,
    1.1772,
    1.1892,
    1.1415,
    1.0741,
    1.0143,
    0.9772,
    0.963,
    0.9656,
    0.9772,
    0.9902,
    1.0003,
    1.0058,
    1.0073,
    1.006,
    1.0035,
    1.0011,
    0.9995,
    0.9987,
    0.9986,
    1
  );
    --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
    --animate-godui-fade-scale-in: godui-fade-scale-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
    --animate-godui-fade-scale-out: godui-fade-scale-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-slide-in-from-top: godui-slide-in-from-top
    var(--godui-duration-base) var(--ease-spring-snappy) backwards;
    --animate-godui-slide-in-from-right: godui-slide-in-from-right
    var(--godui-duration-slow) var(--ease-spring-smooth) backwards;
    --animate-godui-slide-in-from-bottom: godui-slide-in-from-bottom
    var(--godui-duration-base) var(--ease-spring-snappy) backwards;
    --animate-godui-slide-in-from-left: godui-slide-in-from-left
    var(--godui-duration-slow) var(--ease-spring-smooth) backwards;
    --animate-godui-slide-out-to-top: godui-slide-out-to-top
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-slide-out-to-right: godui-slide-out-to-right
    var(--godui-duration-base) var(--ease-out-expo) both;
    --animate-godui-slide-out-to-bottom: godui-slide-out-to-bottom
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-slide-out-to-left: godui-slide-out-to-left
    var(--godui-duration-base) var(--ease-out-expo) both;
    --animate-godui-pop: godui-pop var(--godui-duration-base)
    var(--ease-spring-bouncy);
    --animate-godui-fade-in: godui-fade-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
    --animate-godui-fade-out: godui-fade-out var(--godui-duration-fast)
    var(--ease-out-expo) both;
    --animate-godui-popover-in: godui-popover-in var(--godui-duration-base)
    var(--ease-spring-snappy) backwards;
    --animate-godui-popover-out: godui-popover-out var(--godui-duration-fast)
    var(--ease-out-expo) both;
    --animate-godui-reveal-hold: godui-reveal-hold var(--godui-duration-base)
    linear;
    --animate-godui-calendar-in-from-end: godui-calendar-in-from-end
    var(--godui-duration-base) var(--ease-spring-snappy)
    calc(var(--godui-calendar-delay) * var(--godui-motion)) backwards;
    --animate-godui-calendar-in-from-start: godui-calendar-in-from-start
    var(--godui-duration-base) var(--ease-spring-snappy)
    calc(var(--godui-calendar-delay) * var(--godui-motion)) backwards;
    --animate-godui-calendar-out-to-start: godui-calendar-out-to-start
    var(--godui-duration-fast) var(--godui-calendar-ease-out) both;
    --animate-godui-calendar-out-to-end: godui-calendar-out-to-end
    var(--godui-duration-fast) var(--godui-calendar-ease-out) both;
    --animate-godui-calendar-caption-in-from-end: godui-calendar-caption-in-from-end
    calc(
      var(--godui-duration-base) -
      var(--godui-calendar-caption-lag) *
      var(--godui-motion)
    )
    var(--ease-spring-snappy)
    calc(
      (var(--godui-calendar-delay) + var(--godui-calendar-caption-lag)) *
      var(--godui-motion)
    )
    backwards;
    --animate-godui-calendar-caption-in-from-start: godui-calendar-caption-in-from-start
    calc(
      var(--godui-duration-base) -
      var(--godui-calendar-caption-lag) *
      var(--godui-motion)
    )
    var(--ease-spring-snappy)
    calc(
      (var(--godui-calendar-delay) + var(--godui-calendar-caption-lag)) *
      var(--godui-motion)
    )
    backwards;
    --animate-godui-calendar-caption-out-to-start: godui-calendar-caption-out-to-start
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
    --animate-godui-calendar-caption-out-to-end: godui-calendar-caption-out-to-end
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
    --animate-godui-calendar-caption-hide: godui-calendar-caption-hide
    calc(
      var(--godui-duration-base) +
      var(--godui-calendar-delay) *
      var(--godui-motion)
    )
    linear both;
    --animate-godui-calendar-fill-in: godui-calendar-fill-in
    var(--godui-duration-base) var(--ease-spring-bouncy) backwards;
    --animate-godui-calendar-fade-out: godui-calendar-fade-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-calendar-fill-shrink: godui-calendar-fill-shrink
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-calendar-track-in: godui-calendar-track-in
    calc(
      var(--godui-calendar-track-span, 1) *
      var(--godui-calendar-sweep) *
      var(--godui-motion) +
      var(--godui-duration-fast) *
      (1 - var(--godui-motion))
    )
    linear
    calc(
      var(--godui-calendar-track-at, 0) *
      var(--godui-calendar-sweep) *
      var(--godui-motion)
    )
    backwards;
    --animate-godui-calendar-ghost-glide: godui-calendar-ghost-glide
    calc(var(--godui-calendar-preview-sweep) * var(--godui-motion))
    cubic-bezier(0.33, 1, 0.68, 1) backwards;
    --animate-godui-checkbox-fill-in: godui-checkbox-fill-in
    var(--godui-duration-base) var(--ease-spring-smooth) backwards;
    --animate-godui-checkbox-fill-out: godui-checkbox-fill-out
    var(--godui-duration-fast) var(--ease-spring-smooth) both;
    --animate-godui-checkbox-draw: godui-checkbox-draw
    calc(var(--godui-duration-base) - 70ms * var(--godui-motion))
    var(--ease-spring-smooth) calc(70ms * var(--godui-motion)) backwards;
    --animate-godui-checkbox-ink: godui-checkbox-ink
    calc(var(--godui-duration-base) - 70ms * var(--godui-motion))
    var(--ease-spring-smooth) calc(70ms * var(--godui-motion)) backwards;
    --animate-godui-checkbox-check-out: godui-checkbox-check-out
    var(--godui-duration-fast) var(--ease-out-expo) both;
    --animate-godui-checkbox-hold: godui-reveal-hold var(--godui-duration-fast)
    linear;
    --animate-godui-caret-blink: godui-caret-blink 1.25s ease-out infinite;
    --animate-godui-progress-indeterminate: godui-progress-indeterminate 1.4s
    cubic-bezier(0.65, 0, 0.35, 1) infinite;
    --animate-godui-shimmer: godui-shimmer 1.6s cubic-bezier(0.65, 0, 0.35, 1)
    infinite;
    --animate-shimmer-slide: shimmer-slide var(--speed) ease-in-out infinite
    alternate;
    --animate-spin-around: spin-around calc(var(--speed) * 2) infinite linear;
    --animate-aurora-text: aurora-text var(--aurora-text-speed, 10s) infinite
    linear;
    --animate-magic-rainbow: magic-rainbow var(--rainbow-speed, 2s) infinite
    linear;
    --animate-magic-input-indeterminate: magic-input-indeterminate 1.2s
    ease-in-out infinite alternate;
    --animate-magic-input-sweep: magic-input-sweep 220ms ease-out;
    --animate-magic-input-spin: magic-input-spin 0.8s linear infinite;
    --animate-progress-fold-indeterminate: progress-fold-indeterminate 1.2s
    ease-in-out infinite;
    --animate-blueprint-sweep: blueprint-sweep var(--blueprint-speed, 8s) linear
    infinite;
    --animate-light-rays-sweep: light-rays-sweep var(--rays-speed, 14s)
    ease-in-out infinite alternate;
    --animate-marquee: marquee var(--duration, 40s) linear infinite;
    --animate-marquee-vertical: marquee-vertical var(--duration, 40s) linear
    infinite;
    --animate-app-showcase-scroll: app-showcase-scroll var(--as-loop, 24s) linear
    infinite;
    --animate-mask-nature-in: mask-button-in 0.7s steps(22) forwards;
    --animate-mask-nature-out: mask-button-out 0.7s steps(22) forwards;
    --animate-mask-urban-in: mask-button-in 0.7s steps(29) forwards;
    --animate-mask-urban-out: mask-button-out 0.7s steps(29) forwards;
    --animate-mask-forest-in: mask-button-in 0.7s steps(70) forwards;
    --animate-mask-forest-out: mask-button-out 0.7s steps(70) forwards;
    --animate-voice-orb-spin: voice-orb-spin 8s linear infinite;
    --animate-voice-orb-breathe: voice-orb-breathe 4s ease-in-out infinite;
    --animate-voice-orb-ring: voice-orb-ring 1.6s ease-out infinite;
    --animate-split-flap-fall: split-flap-fall 0.12s
    cubic-bezier(0.3, 0.7, 0.4, 1) forwards;
    --animate-split-flap-rise: split-flap-rise 0.12s
    cubic-bezier(0.22, 1, 0.36, 1) both;
  }
}
@layer base {
  *, ::after, ::before, ::backdrop, ::file-selector-button {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0 solid;
  }
  html, :host {
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
    font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
    font-feature-settings: var(--default-font-feature-settings, normal);
    font-variation-settings: var(--default-font-variation-settings, normal);
    -webkit-tap-highlight-color: transparent;
  }
  hr {
    height: 0;
    color: inherit;
    border-top-width: 1px;
  }
  abbr:where([title]) {
    -webkit-text-decoration: underline dotted;
    text-decoration: underline dotted;
  }
  h1, h2, h3, h4, h5, h6 {
    font-size: inherit;
    font-weight: inherit;
  }
  a {
    color: inherit;
    -webkit-text-decoration: inherit;
    text-decoration: inherit;
  }
  b, strong {
    font-weight: bolder;
  }
  code, kbd, samp, pre {
    font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
    font-feature-settings: var(--default-mono-font-feature-settings, normal);
    font-variation-settings: var(--default-mono-font-variation-settings, normal);
    font-size: 1em;
  }
  small {
    font-size: 80%;
  }
  sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
  }
  sub {
    bottom: -0.25em;
  }
  sup {
    top: -0.5em;
  }
  table {
    text-indent: 0;
    border-color: inherit;
    border-collapse: collapse;
  }
  :-moz-focusring:where(:not(iframe)) {
    outline: auto;
  }
  progress {
    vertical-align: baseline;
  }
  summary {
    display: list-item;
  }
  ol, ul, menu {
    list-style: none;
  }
  img, svg, video, canvas, audio, iframe, embed, object {
    display: block;
    vertical-align: middle;
  }
  img, video {
    max-width: 100%;
    height: auto;
  }
  button, input, select, optgroup, textarea, ::file-selector-button {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    border-radius: 0;
    background-color: transparent;
    opacity: 1;
  }
  :where(select:is([multiple], [size])) optgroup {
    font-weight: bolder;
  }
  :where(select:is([multiple], [size])) optgroup option {
    padding-inline-start: 20px;
  }
  ::file-selector-button {
    margin-inline-end: 4px;
  }
  ::placeholder {
    opacity: 1;
  }
  @supports (not (-webkit-appearance: -apple-pay-button))  or (contain-intrinsic-size: 1px) {
    ::placeholder {
      color: currentcolor;
      @supports (color: color-mix(in lab, red, red)) {
        color: color-mix(in oklab, currentcolor 50%, transparent);
      }
    }
  }
  textarea {
    resize: vertical;
  }
  ::-webkit-search-decoration {
    -webkit-appearance: none;
  }
  ::-webkit-date-and-time-value {
    min-height: 1lh;
    text-align: inherit;
  }
  ::-webkit-datetime-edit {
    display: inline-flex;
  }
  ::-webkit-datetime-edit-fields-wrapper {
    padding: 0;
  }
  ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
    padding-block: 0;
  }
  ::-webkit-calendar-picker-indicator {
    line-height: 1;
  }
  :-moz-ui-invalid {
    box-shadow: none;
  }
  button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
    appearance: button;
  }
  ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
    height: auto;
  }
  [hidden]:where(:not([hidden="until-found"])) {
    display: none !important;
  }
}
@layer utilities {
  .visible {
    visibility: visible;
  }
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border-width: 0;
  }
  .absolute {
    position: absolute;
  }
  .fixed {
    position: fixed;
  }
  .relative {
    position: relative;
  }
  .inset-0 {
    inset: 0px;
  }
  .top-0 {
    top: 0px;
  }
  .left-0 {
    left: 0px;
  }
  .-z-\[1\] {
    z-index: calc(1 * -1);
  }
  .block {
    display: block;
  }
  .grid {
    display: grid;
  }
  .hidden {
    display: none;
  }
  .inline {
    display: inline;
  }
  .inline-flex {
    display: inline-flex;
  }
  .h-full {
    height: 100%;
  }
  .w-full {
    width: 100%;
  }
  .\[transform-origin\:top_center\] {
    transform-origin: top center;
  }
  .origin-left {
    transform-origin: 0;
  }
  .\[transform\:rotateX\(0deg\)\] {
    transform: rotateX(0deg);
  }
  .\[transform\:scaleX\(0\)\] {
    transform: scaleX(0);
  }
  .transform {
    transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
  }
  .cursor-pointer {
    cursor: pointer;
  }
  .place-items-center {
    place-items: center;
  }
  .overflow-hidden {
    overflow: hidden;
  }
  .rounded-\[inherit\] {
    border-radius: inherit;
  }
  .rounded-\[var\(--button-radius-lg\)\] {
    border-radius: var(--button-radius-lg);
  }
  .rounded-\[var\(--button-radius-md\)\] {
    border-radius: var(--button-radius-md);
  }
  .rounded-\[var\(--button-radius-sm\)\] {
    border-radius: var(--button-radius-sm);
  }
  .border-none {
    --tw-border-style: none;
    border-style: none;
  }
  .bg-border {
    background-color: var(--border);
  }
  .bg-primary {
    background-color: var(--primary);
  }
  .bg-primary\/15 {
    background-color: var(--primary);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--primary) 15%, transparent);
    }
  }
  .bg-primary\/40 {
    background-color: var(--primary);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--primary) 40%, transparent);
    }
  }
  .bg-secondary {
    background-color: var(--secondary);
  }
  .bg-secondary-foreground\/15 {
    background-color: var(--secondary-foreground);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--secondary-foreground) 15%, transparent);
    }
  }
  .bg-secondary-foreground\/35 {
    background-color: var(--secondary-foreground);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--secondary-foreground) 35%, transparent);
    }
  }
  .p-0 {
    padding: 0px;
  }
  .px-\[var\(--button-px-lg\)\] {
    padding-inline: var(--button-px-lg);
  }
  .px-\[var\(--button-px-md\)\] {
    padding-inline: var(--button-px-md);
  }
  .px-\[var\(--button-px-sm\)\] {
    padding-inline: var(--button-px-sm);
  }
  .py-\[var\(--button-py-lg\)\] {
    padding-block: var(--button-py-lg);
  }
  .py-\[var\(--button-py-md\)\] {
    padding-block: var(--button-py-md);
  }
  .py-\[var\(--button-py-sm\)\] {
    padding-block: var(--button-py-sm);
  }
  .text-\[length\:var\(--button-text-lg\)\] {
    font-size: var(--button-text-lg);
  }
  .text-\[length\:var\(--button-text-md\)\] {
    font-size: var(--button-text-md);
  }
  .text-\[length\:var\(--button-text-sm\)\] {
    font-size: var(--button-text-sm);
  }
  .leading-\[var\(--button-leading-lg\)\] {
    --tw-leading: var(--button-leading-lg);
    line-height: var(--button-leading-lg);
  }
  .leading-\[var\(--button-leading-md\)\] {
    --tw-leading: var(--button-leading-md);
    line-height: var(--button-leading-md);
  }
  .leading-\[var\(--button-leading-sm\)\] {
    --tw-leading: var(--button-leading-sm);
    line-height: var(--button-leading-sm);
  }
  .font-medium {
    --tw-font-weight: var(--font-weight-medium);
    font-weight: var(--font-weight-medium);
  }
  .whitespace-nowrap {
    white-space: nowrap;
  }
  .text-primary-foreground {
    color: var(--primary-foreground);
  }
  .text-secondary-foreground {
    color: var(--secondary-foreground);
  }
  .ring {
    --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }
  .blur {
    --tw-blur: blur(8px);
    filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
  }
  .filter {
    filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
  }
  .transition {
    transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }
  .ease-in-out {
    --tw-ease: var(--ease-in-out);
    transition-timing-function: var(--ease-in-out);
  }
  .ease-out {
    --tw-ease: var(--ease-out);
    transition-timing-function: var(--ease-out);
  }
  .select-none {
    -webkit-user-select: none;
    user-select: none;
  }
  .\[-webkit-tap-highlight-color\:transparent\] {
    -webkit-tap-highlight-color: transparent;
  }
  .\[perspective\:800px\] {
    perspective: 800px;
  }
  .\[transform-style\:preserve-3d\] {
    transform-style: preserve-3d;
  }
  .\[transition\:transform_0\.2s\] {
    transition: transform 0.2s;
  }
  @media (hover: hover) {
    .group-hover\:\[transform\:rotateX\(35deg\)\]:is(:where(.group):hover *) {
      transform: rotateX(35deg);
    }
  }
  .group-focus-visible\:\[transform\:rotateX\(35deg\)\]:is(:where(.group):focus-visible *) {
    transform: rotateX(35deg);
  }
  .group-data-\[determinate\=true\]\:\[transform\:scaleX\(var\(--progress-fold-fill\,0\)\)\]:is(:where(.group)[data-determinate="true"] *) {
    transform: scaleX(var(--progress-fold-fill,0));
  }
  .group-data-\[status\=loading\]\:\[transform\:rotateX\(35deg\)\]:is(:where(.group)[data-status="loading"] *) {
    transform: rotateX(35deg);
  }
  .group-\[\&\[data-determinate\=true\]\[data-armed\=true\]\]\:\[transition\:transform_0\.25s_ease\]:is(:where(.group)[data-determinate=true][data-armed=true] *) {
    transition: transform 0.25s ease;
  }
  .group-\[\&\[data-status\=loading\]\:not\(\[data-determinate\=true\]\)\]\:w-\[40\%\]:is(:where(.group)[data-status=loading]:not([data-determinate=true]) *) {
    width: 40%;
  }
  .group-\[\&\[data-status\=loading\]\:not\(\[data-determinate\=true\]\)\]\:animate-progress-fold-indeterminate:is(:where(.group)[data-status=loading]:not([data-determinate=true]) *) {
    animation: progress-fold-indeterminate 1.2s
    ease-in-out infinite;
  }
  .focus-visible\:\[outline\:2px_solid_var\(--ring\)\]:focus-visible {
    outline: 2px solid var(--ring);
  }
  .focus-visible\:\[outline-offset\:4px\]:focus-visible {
    outline-offset: 4px;
  }
  .disabled\:pointer-events-none:disabled {
    pointer-events: none;
  }
  .disabled\:cursor-not-allowed:disabled {
    cursor: not-allowed;
  }
  .disabled\:opacity-50:disabled {
    opacity: 50%;
  }
  @media (prefers-reduced-motion: reduce) {
    .motion-reduce\:\[transition\:none\] {
      transition: none;
    }
    .motion-reduce\:group-\[\&\[data-determinate\=true\]\[data-armed\=true\]\]\:\[transition\:none\]:is(:where(.group)[data-determinate=true][data-armed=true] *) {
      transition: none;
    }
    .motion-reduce\:group-\[\&\[data-status\=loading\]\:not\(\[data-determinate\=true\]\)\]\:animate-none:is(:where(.group)[data-status=loading]:not([data-determinate=true]) *) {
      animation: none;
    }
  }
}
:root {
  --background: #fff;
  --foreground: #111;
  --primary: #171717;
  --primary-foreground: #fff;
  --secondary: #eee;
  --secondary-foreground: #171717;
  --muted: #eee;
  --muted-foreground: #666;
  --accent: #eee;
  --accent-foreground: #171717;
  --border: #ddd;
  --input: #ddd;
  --ring: #777;
  --destructive: #dc2626;
  --destructive-foreground: #fff;
  --popover: #fff;
  --popover-foreground: #111;
  --success: #15803d;
  --success-foreground: #fff;
  --radius: .625rem;
  --hairline: 1px;
}
.dark {
  --background: #090909;
  --foreground: #fafafa;
  --primary: #fafafa;
  --primary-foreground: #171717;
  --secondary: #262626;
  --secondary-foreground: #fafafa;
  --muted: #262626;
  --muted-foreground: #a3a3a3;
  --accent: #262626;
  --accent-foreground: #fafafa;
  --border: #333;
  --input: #333;
  --popover: #171717;
  --popover-foreground: #fafafa;
}
:root, .light {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.145 0 0);
  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);
  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);
  --font-sans: var(
    --font-geist-sans,
    "Geist",
    ui-sans-serif,
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Helvetica Neue",
    Arial,
    "Noto Sans",
    sans-serif
  );
  --font-serif: var(
    --font-geist-sans,
    "Geist",
    ui-serif,
    Georgia,
    Cambria,
    "Times New Roman",
    Times,
    serif
  );
  --font-mono: var(
    --font-geist-mono,
    "Geist Mono",
    ui-monospace,
    SFMono-Regular,
    Menlo,
    Monaco,
    Consolas,
    "Liberation Mono",
    "Courier New",
    monospace
  );
  --radius: 0.625rem;
  --shadow-2xs: 0 1px 2px rgb(0 0 0 / 0.02);
  --shadow-xs: 0 1px 3px rgb(0 0 0 / 0.04);
  --shadow-sm: 0 2px 6px rgb(0 0 0 / 0.05);
  --shadow: 0 4px 12px rgb(0 0 0 / 0.06);
  --shadow-md: 0 8px 20px rgb(0 0 0 / 0.08);
  --shadow-lg: 0 16px 32px rgb(0 0 0 / 0.1);
  --shadow-xl: 0 24px 48px rgb(0 0 0 / 0.12);
  --shadow-2xl: 0 40px 80px rgb(0 0 0 / 0.16);
  --syntax-plain: oklch(0.2 0.036 266);
  --syntax-punctuation: oklch(0.54 0.022 266);
  --syntax-keyword: oklch(0.52 0.19 302);
  --syntax-property: oklch(0.56 0.11 90);
  --syntax-string: oklch(0.52 0.106 168);
  --syntax-comment: oklch(0.63 0.016 266);
  --syntax-number: oklch(0.54 0.115 235);
  --inline-code-bg: var(--muted);
  --inline-code-fg: var(--foreground);
  --inline-code-border: var(--border);
  --code-block: oklch(0.978 0 0);
  --code-block-foreground: oklch(0.205 0 0);
  --code-block-border: oklch(0.922 0 0);
  --search-bg: var(--card);
  --search-fg: var(--muted-foreground);
  --search-border: var(--border);
  --search-kbd-bg: var(--muted);
  --search-kbd-fg: var(--muted-foreground);
  --search-placeholder: var(--muted-foreground);
  --search-highlight-bg: var(--primary);
  --search-highlight-fg: var(--primary-foreground);
  --theme-panel-bg: var(--card);
  --theme-panel-border: var(--border);
  --theme-panel-fg: var(--muted-foreground);
  --theme-panel-active-bg: var(--muted);
  --theme-panel-active-fg: var(--foreground);
  --z-base: 0;
  --z-raised: 10;
  --z-overlay: 20;
  --z-sticky: 30;
  --z-popover: 40;
  --z-modal: 50;
  --z-toast: 60;
  --color-bg: var(--background);
  --color-fg: var(--foreground);
  --color-border: var(--border);
  --color-primary: var(--primary);
  --color-primary-fg: var(--primary-foreground);
  --color-secondary-bg: var(--secondary);
  --color-secondary-fg: var(--secondary-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-fg: oklch(1 0 0);
  --glow-highlight: 61, 102, 223;
  --color-primary-rgb: 61, 102, 223;
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --god-gradient: linear-gradient(
    135deg,
    oklch(0.55 0.19 266) 0%,
    oklch(1 0 0) 50%,
    oklch(0.85 0.12 90) 100%
  );
  --god-glow: 0 0 24px oklch(0.55 0.19 266 / 0.14), 0 0 80px oklch(0.85 0.12 90 / 0.06);
  --rainbow-1: oklch(0.55 0.19 266);
  --rainbow-2: oklch(0.68 0.16 305);
  --rainbow-3: oklch(0.82 0.1 185);
  --rainbow-4: oklch(0.78 0.12 14);
  --rainbow-5: oklch(0.8 0.13 90);
  --rainbow-speed: 2s;
}
.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);
  --destructive: oklch(0.704 0.191 22.216);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.556 0 0);
  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);
  --sidebar: oklch(0.205 0 0);
  --sidebar-foreground: oklch(0.985 0 0);
  --sidebar-primary: oklch(0.488 0.243 264.376);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.269 0 0);
  --sidebar-accent-foreground: oklch(0.985 0 0);
  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.556 0 0);
  --syntax-plain: oklch(0.935 0.01 266);
  --syntax-punctuation: oklch(0.65 0.02 266);
  --syntax-keyword: oklch(0.78 0.135 302);
  --syntax-property: oklch(0.83 0.12 90);
  --syntax-string: oklch(0.8 0.13 168);
  --syntax-comment: oklch(0.58 0.02 266);
  --syntax-number: oklch(0.8 0.12 224);
  --code-block: oklch(0.185 0 0);
  --code-block-foreground: oklch(0.985 0 0);
  --code-block-border: oklch(0.27 0 0);
  --inline-code-bg: var(--muted);
  --inline-code-fg: var(--foreground);
  --inline-code-border: var(--border);
  --search-bg: var(--card);
  --search-fg: var(--muted-foreground);
  --search-border: var(--border);
  --search-kbd-bg: var(--muted);
  --search-kbd-fg: var(--muted-foreground);
  --search-placeholder: var(--muted-foreground);
  --search-highlight-bg: var(--primary);
  --search-highlight-fg: var(--primary-foreground);
  --theme-panel-bg: var(--card);
  --theme-panel-border: var(--border);
  --theme-panel-fg: var(--muted-foreground);
  --theme-panel-active-bg: var(--muted);
  --theme-panel-active-fg: var(--foreground);
  --shadow-2xs: 0 1px 2px rgb(0 0 0 / 0.12);
  --shadow-xs: 0 1px 3px rgb(0 0 0 / 0.15);
  --shadow-sm: 0 2px 6px rgb(0 0 0 / 0.2);
  --shadow: 0 4px 12px rgb(0 0 0 / 0.25);
  --shadow-md: 0 8px 20px rgb(0 0 0 / 0.3);
  --shadow-lg: 0 16px 32px rgb(0 0 0 / 0.35);
  --shadow-xl: 0 24px 48px rgb(0 0 0 / 0.4);
  --shadow-2xl: 0 40px 80px rgb(0 0 0 / 0.5);
  --color-bg: var(--background);
  --color-fg: var(--foreground);
  --color-border: var(--border);
  --color-primary: var(--primary);
  --color-primary-fg: var(--primary-foreground);
  --color-secondary-bg: var(--secondary);
  --color-secondary-fg: var(--secondary-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-fg: oklch(1 0 0);
  --glow-highlight: 66, 108, 229;
  --color-primary-rgb: 66, 108, 229;
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --god-gradient: linear-gradient(
    135deg,
    oklch(0.57 0.19 266) 0%,
    oklch(1 0 0) 50%,
    oklch(0.86 0.12 90) 100%
  );
  --god-glow: 0 0 24px oklch(0.57 0.19 266 / 0.28), 0 0 80px oklch(0.86 0.12 90 / 0.12);
  --rainbow-1: oklch(0.72 0.145 266);
  --rainbow-2: oklch(0.74 0.16 305);
  --rainbow-3: oklch(0.84 0.1 185);
  --rainbow-4: oklch(0.8 0.116 14);
  --rainbow-5: oklch(0.84 0.13 90);
  --rainbow-speed: 2s;
}
:root {
  --godui-duration-fast: 150ms;
  --godui-duration-base: 260ms;
  --godui-duration-slow: 380ms;
  --godui-enter-scale: 0.96;
  --godui-enter-distance: 0.5rem;
  --godui-pop-scale: 0.96;
  --godui-enter-x: 0px;
  --godui-enter-y: 0px;
  --godui-motion: 1;
}
@keyframes godui-fade-scale-in {
  from {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
  }
}
@keyframes godui-fade-scale-out {
  to {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-top {
  from {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * -1 * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-right {
  from {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-in-from-bottom {
  from {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * var(--godui-motion));
  }
}
@keyframes godui-slide-in-from-left {
  from {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * -1 * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-out-to-top {
  to {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * -1 * var(--godui-motion));
  }
}
@keyframes godui-slide-out-to-right {
  to {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * var(--godui-motion)) 0;
  }
}
@keyframes godui-slide-out-to-bottom {
  to {
    opacity: 0;
    translate: 0 calc(var(--godui-enter-distance) * var(--godui-motion));
  }
}
@keyframes godui-slide-out-to-left {
  to {
    opacity: 0;
    translate: calc(var(--godui-enter-distance) * -1 * var(--godui-motion)) 0;
  }
}
@keyframes godui-pop {
  40% {
    scale: calc(1 - (1 - var(--godui-pop-scale)) * var(--godui-motion));
  }
}
@keyframes godui-fade-in {
  from {
    opacity: 0;
  }
}
@keyframes godui-fade-out {
  to {
    opacity: 0;
  }
}
@keyframes godui-popover-in {
  from {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
    translate: calc(var(--godui-enter-x) * var(--godui-motion)) calc(var(--godui-enter-y) * var(--godui-motion));
  }
}
@keyframes godui-popover-out {
  to {
    opacity: 0;
    scale: calc(1 - (1 - var(--godui-enter-scale)) * var(--godui-motion));
    translate: calc(var(--godui-enter-x) * var(--godui-motion)) calc(var(--godui-enter-y) * var(--godui-motion));
  }
}
@keyframes godui-reveal-hold {
  to {
    opacity: 0.99;
  }
}
@keyframes godui-calendar-in-from-end {
  from {
    opacity: 0;
    translate: calc( var(--godui-calendar-drift) * var(--godui-calendar-dir) * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-in-from-start {
  from {
    opacity: 0;
    translate: calc( var(--godui-calendar-drift) * var(--godui-calendar-dir) * -1 * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-out-to-start {
  to {
    opacity: 0;
    translate: calc( var(--godui-calendar-drift-out) * var(--godui-calendar-dir) * -1 * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-out-to-end {
  to {
    opacity: 0;
    translate: calc( var(--godui-calendar-drift-out) * var(--godui-calendar-dir) * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-caption-in-from-end {
  from {
    opacity: 0;
    translate: calc( var(--godui-calendar-caption-drift) * var(--godui-calendar-dir) * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-caption-in-from-start {
  from {
    opacity: 0;
    translate: calc( var(--godui-calendar-caption-drift) * var(--godui-calendar-dir) * -1 * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-caption-out-to-start {
  0% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }
  30%, 100% {
    opacity: 0;
    translate: calc( var(--godui-calendar-caption-drift) * var(--godui-calendar-dir) * -0.5 * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-caption-out-to-end {
  0% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }
  30%, 100% {
    opacity: 0;
    translate: calc( var(--godui-calendar-caption-drift) * var(--godui-calendar-dir) * 0.5 * var(--godui-motion) ) 0;
  }
}
@keyframes godui-calendar-caption-hide {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.01;
  }
}
@keyframes godui-calendar-fill-in {
  0% {
    opacity: 0;
    scale: calc(1 - 0.4 * var(--godui-motion));
  }
  35% {
    opacity: 1;
  }
}
@keyframes godui-calendar-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes godui-calendar-fill-shrink {
  to {
    scale: calc(1 - 0.15 * var(--godui-motion));
  }
}
@keyframes godui-calendar-track-in {
  from {
    opacity: var(--godui-motion);
    scale: calc(1 - var(--godui-motion)) 1;
  }
}
@keyframes godui-calendar-ghost-glide {
  from {
    translate: calc( var(--godui-calendar-ghost-from, 0) * 100% * var(--godui-calendar-dir) * var(--godui-motion) ) 0;
  }
}
@keyframes godui-checkbox-fill-in {
  from {
    opacity: var(--godui-motion);
    scale: calc(1.42 * (1 - var(--godui-motion)));
  }
}
@keyframes godui-checkbox-fill-out {
  to {
    opacity: var(--godui-motion);
    scale: calc(1.42 * (1 - var(--godui-motion)));
  }
}
@keyframes godui-checkbox-draw {
  from {
    translate: calc(-100% * var(--godui-motion)) 0;
  }
}
@keyframes godui-checkbox-ink {
  from {
    opacity: var(--godui-motion);
    translate: calc(100% * var(--godui-motion)) 0;
  }
}
@keyframes godui-checkbox-check-out {
  to {
    opacity: 0;
    scale: calc(1 - 0.3 * var(--godui-motion));
  }
}
@keyframes godui-caret-blink {
  0%, 70%, 100% {
    opacity: 1;
  }
  20%, 50% {
    opacity: 0;
  }
}
@keyframes godui-progress-indeterminate {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(250%);
  }
}
@keyframes godui-shimmer {
  to {
    translate: 100% 0;
  }
}
@keyframes voice-orb-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes voice-orb-breathe {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.04);
  }
}
@keyframes voice-orb-ring {
  0% {
    transform: scale(0.85);
    opacity: 0.6;
  }
  100% {
    transform: scale(1.4);
    opacity: 0;
  }
}
@keyframes split-flap-fall {
  from {
    transform: rotateX(0deg);
  }
  to {
    transform: rotateX(-90deg);
  }
}
@keyframes split-flap-rise {
  from {
    transform: rotateX(90deg);
  }
  to {
    transform: rotateX(0deg);
  }
}
@keyframes shimmer-slide {
  to {
    transform: translate(calc(100cqw - 100%), 0);
  }
}
@keyframes spin-around {
  0% {
    transform: translateZ(0) rotate(0);
  }
  15%, 35% {
    transform: translateZ(0) rotate(90deg);
  }
  65%, 85% {
    transform: translateZ(0) rotate(270deg);
  }
  100% {
    transform: translateZ(0) rotate(360deg);
  }
}
@keyframes aurora-text {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}
@keyframes magic-rainbow {
  0% {
    background-position: 0% 50%;
  }
  100% {
    background-position: 200% 50%;
  }
}
@keyframes magic-input-indeterminate {
  from {
    background-position: 110% center;
  }
  to {
    background-position: -10% center;
  }
}
@keyframes magic-input-sweep {
  from {
    background-size: 0% 100%;
  }
  to {
    background-size: 100% 100%;
  }
}
@keyframes magic-input-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes mask-button-in {
  from {
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
  }
  to {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
  }
}
@keyframes mask-button-out {
  from {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
  }
  to {
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
  }
}
@keyframes marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% - var(--gap)));
  }
}
@keyframes marquee-vertical {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(calc(-100% - var(--gap)));
  }
}
@keyframes app-showcase-scroll {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}
@keyframes progress-fold-indeterminate {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}
@keyframes blueprint-sweep {
  0% {
    transform: translate(-50%, -50%) rotate(var(--blueprint-angle, 25deg));
    opacity: 0;
  }
  15%, 85% {
    opacity: 1;
  }
  100% {
    transform: translate(150%, 150%) rotate(var(--blueprint-angle, 25deg));
    opacity: 0;
  }
}
@keyframes light-rays-sweep {
  0% {
    transform: rotate(calc(var(--rays-angle, 0deg) - 6deg)) scale(1);
    opacity: calc(var(--rays-intensity, 0.6) * 0.7);
  }
  100% {
    transform: rotate(calc(var(--rays-angle, 0deg) + 6deg)) scale(1.08);
    opacity: var(--rays-intensity, 0.6);
  }
}
@property --tw-rotate-x {
  syntax: "*";
  inherits: false;
}
@property --tw-rotate-y {
  syntax: "*";
  inherits: false;
}
@property --tw-rotate-z {
  syntax: "*";
  inherits: false;
}
@property --tw-skew-x {
  syntax: "*";
  inherits: false;
}
@property --tw-skew-y {
  syntax: "*";
  inherits: false;
}
@property --tw-leading {
  syntax: "*";
  inherits: false;
}
@property --tw-font-weight {
  syntax: "*";
  inherits: false;
}
@property --tw-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}
@property --tw-shadow-color {
  syntax: "*";
  inherits: false;
}
@property --tw-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}
@property --tw-inset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}
@property --tw-inset-shadow-color {
  syntax: "*";
  inherits: false;
}
@property --tw-inset-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}
@property --tw-ring-color {
  syntax: "*";
  inherits: false;
}
@property --tw-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}
@property --tw-inset-ring-color {
  syntax: "*";
  inherits: false;
}
@property --tw-inset-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}
@property --tw-ring-inset {
  syntax: "*";
  inherits: false;
}
@property --tw-ring-offset-width {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --tw-ring-offset-color {
  syntax: "*";
  inherits: false;
  initial-value: #fff;
}
@property --tw-ring-offset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}
@property --tw-blur {
  syntax: "*";
  inherits: false;
}
@property --tw-brightness {
  syntax: "*";
  inherits: false;
}
@property --tw-contrast {
  syntax: "*";
  inherits: false;
}
@property --tw-grayscale {
  syntax: "*";
  inherits: false;
}
@property --tw-hue-rotate {
  syntax: "*";
  inherits: false;
}
@property --tw-invert {
  syntax: "*";
  inherits: false;
}
@property --tw-opacity {
  syntax: "*";
  inherits: false;
}
@property --tw-saturate {
  syntax: "*";
  inherits: false;
}
@property --tw-sepia {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow-color {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}
@property --tw-drop-shadow-size {
  syntax: "*";
  inherits: false;
}
@property --tw-ease {
  syntax: "*";
  inherits: false;
}
@layer properties {
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
    *, ::before, ::after, ::backdrop {
      --tw-rotate-x: initial;
      --tw-rotate-y: initial;
      --tw-rotate-z: initial;
      --tw-skew-x: initial;
      --tw-skew-y: initial;
      --tw-leading: initial;
      --tw-font-weight: initial;
      --tw-shadow: 0 0 #0000;
      --tw-shadow-color: initial;
      --tw-shadow-alpha: 100%;
      --tw-inset-shadow: 0 0 #0000;
      --tw-inset-shadow-color: initial;
      --tw-inset-shadow-alpha: 100%;
      --tw-ring-color: initial;
      --tw-ring-shadow: 0 0 #0000;
      --tw-inset-ring-color: initial;
      --tw-inset-ring-shadow: 0 0 #0000;
      --tw-ring-inset: initial;
      --tw-ring-offset-width: 0px;
      --tw-ring-offset-color: #fff;
      --tw-ring-offset-shadow: 0 0 #0000;
      --tw-blur: initial;
      --tw-brightness: initial;
      --tw-contrast: initial;
      --tw-grayscale: initial;
      --tw-hue-rotate: initial;
      --tw-invert: initial;
      --tw-opacity: initial;
      --tw-saturate: initial;
      --tw-sepia: initial;
      --tw-drop-shadow: initial;
      --tw-drop-shadow-color: initial;
      --tw-drop-shadow-alpha: 100%;
      --tw-drop-shadow-size: initial;
      --tw-ease: initial;
    }
  }
}