@holaboss/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,202 @@
1
+ import * as React from "react"
2
+ import { Select as SelectPrimitive } from "@base-ui/react/select"
3
+
4
+ import { cn } from "../lib/utils"
5
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
6
+
7
+ const Select = SelectPrimitive.Root
8
+
9
+ function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
10
+ return (
11
+ <SelectPrimitive.Group
12
+ data-slot="select-group"
13
+ className={cn("scroll-my-1 p-1", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
20
+ return (
21
+ <SelectPrimitive.Value
22
+ data-slot="select-value"
23
+ className={cn("flex flex-1 text-left", className)}
24
+ {...props}
25
+ />
26
+ )
27
+ }
28
+
29
+ function SelectTrigger({
30
+ className,
31
+ size = "default",
32
+ children,
33
+ ...props
34
+ }: SelectPrimitive.Trigger.Props & {
35
+ size?: "sm" | "default"
36
+ }) {
37
+ return (
38
+ <SelectPrimitive.Trigger
39
+ data-slot="select-trigger"
40
+ data-size={size}
41
+ className={cn(
42
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ {children}
48
+ <SelectPrimitive.Icon
49
+ render={
50
+ <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
51
+ }
52
+ />
53
+ </SelectPrimitive.Trigger>
54
+ )
55
+ }
56
+
57
+ function SelectContent({
58
+ className,
59
+ children,
60
+ side = "bottom",
61
+ sideOffset = 4,
62
+ align = "center",
63
+ alignOffset = 0,
64
+ alignItemWithTrigger = true,
65
+ ...props
66
+ }: SelectPrimitive.Popup.Props &
67
+ Pick<
68
+ SelectPrimitive.Positioner.Props,
69
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
70
+ >) {
71
+ return (
72
+ <SelectPrimitive.Portal>
73
+ <SelectPrimitive.Positioner
74
+ side={side}
75
+ sideOffset={sideOffset}
76
+ align={align}
77
+ alignOffset={alignOffset}
78
+ alignItemWithTrigger={alignItemWithTrigger}
79
+ className="isolate z-50"
80
+ >
81
+ <SelectPrimitive.Popup
82
+ data-slot="select-content"
83
+ data-align-trigger={alignItemWithTrigger}
84
+ className={cn(
85
+ "dark isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg text-popover-foreground shadow-md ring-1 ring-border duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 animate-none! relative bg-popover/70 before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:rounded-[inherit] before:backdrop-blur-2xl before:backdrop-saturate-150 **:data-[slot$=-item]:focus:bg-foreground/10 **:data-[slot$=-item]:data-highlighted:bg-foreground/10 **:data-[slot$=-separator]:bg-fg-5 **:data-[slot$=-trigger]:focus:bg-foreground/10 **:data-[slot$=-trigger]:aria-expanded:bg-foreground/10! **:data-[variant=destructive]:focus:bg-foreground/10! **:data-[variant=destructive]:text-accent-foreground! **:data-[variant=destructive]:**:text-accent-foreground!",
86
+ className
87
+ )}
88
+ {...props}
89
+ >
90
+ <SelectScrollUpButton />
91
+ <SelectPrimitive.List>{children}</SelectPrimitive.List>
92
+ <SelectScrollDownButton />
93
+ </SelectPrimitive.Popup>
94
+ </SelectPrimitive.Positioner>
95
+ </SelectPrimitive.Portal>
96
+ )
97
+ }
98
+
99
+ function SelectLabel({
100
+ className,
101
+ ...props
102
+ }: SelectPrimitive.GroupLabel.Props) {
103
+ return (
104
+ <SelectPrimitive.GroupLabel
105
+ data-slot="select-label"
106
+ className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
107
+ {...props}
108
+ />
109
+ )
110
+ }
111
+
112
+ function SelectItem({
113
+ className,
114
+ children,
115
+ ...props
116
+ }: SelectPrimitive.Item.Props) {
117
+ return (
118
+ <SelectPrimitive.Item
119
+ data-slot="select-item"
120
+ className={cn(
121
+ "relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
122
+ className
123
+ )}
124
+ {...props}
125
+ >
126
+ <SelectPrimitive.ItemText className="flex flex-1 shrink-0 items-center gap-2 whitespace-nowrap">
127
+ {children}
128
+ </SelectPrimitive.ItemText>
129
+ <SelectPrimitive.ItemIndicator
130
+ render={
131
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
132
+ }
133
+ >
134
+ <CheckIcon className="pointer-events-none" />
135
+ </SelectPrimitive.ItemIndicator>
136
+ </SelectPrimitive.Item>
137
+ )
138
+ }
139
+
140
+ function SelectSeparator({
141
+ className,
142
+ ...props
143
+ }: SelectPrimitive.Separator.Props) {
144
+ return (
145
+ <SelectPrimitive.Separator
146
+ data-slot="select-separator"
147
+ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
148
+ {...props}
149
+ />
150
+ )
151
+ }
152
+
153
+ function SelectScrollUpButton({
154
+ className,
155
+ ...props
156
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
157
+ return (
158
+ <SelectPrimitive.ScrollUpArrow
159
+ data-slot="select-scroll-up-button"
160
+ className={cn(
161
+ "top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
162
+ className
163
+ )}
164
+ {...props}
165
+ >
166
+ <ChevronUpIcon
167
+ />
168
+ </SelectPrimitive.ScrollUpArrow>
169
+ )
170
+ }
171
+
172
+ function SelectScrollDownButton({
173
+ className,
174
+ ...props
175
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
176
+ return (
177
+ <SelectPrimitive.ScrollDownArrow
178
+ data-slot="select-scroll-down-button"
179
+ className={cn(
180
+ "bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
181
+ className
182
+ )}
183
+ {...props}
184
+ >
185
+ <ChevronDownIcon
186
+ />
187
+ </SelectPrimitive.ScrollDownArrow>
188
+ )
189
+ }
190
+
191
+ export {
192
+ Select,
193
+ SelectContent,
194
+ SelectGroup,
195
+ SelectItem,
196
+ SelectLabel,
197
+ SelectScrollDownButton,
198
+ SelectScrollUpButton,
199
+ SelectSeparator,
200
+ SelectTrigger,
201
+ SelectValue,
202
+ }
@@ -0,0 +1,85 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props"
2
+ import { useRender } from "@base-ui/react/use-render"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ /**
8
+ * StatusDot — small colored dot signalling a state (running, error,
9
+ * working, idle, etc.). Replaces ~18 hand-rolled
10
+ * `<span className="size-X rounded-full bg-X" />` instances across the
11
+ * shell so a single change here propagates everywhere.
12
+ *
13
+ * Default size = `sm` (6px) which matches the dominant existing usage
14
+ * (status pip alongside text). Use `md` (8px) for slightly more
15
+ * presence (sidebar entry status), `lg` (10px) for stand-alone
16
+ * notification-style indicators.
17
+ *
18
+ * `withRing` adds a card-colored ring — used for badge dots that sit on
19
+ * top of an icon and need to read against the underlying surface.
20
+ */
21
+ const statusDotVariants = cva("inline-block shrink-0 rounded-full", {
22
+ variants: {
23
+ variant: {
24
+ success: "bg-success",
25
+ destructive: "bg-destructive",
26
+ warning: "bg-warning",
27
+ info: "bg-info",
28
+ primary: "bg-primary",
29
+ muted: "bg-muted-foreground",
30
+ neutral: "bg-fg-24",
31
+ },
32
+ size: {
33
+ sm: "size-1.5",
34
+ md: "size-2",
35
+ lg: "size-2.5",
36
+ },
37
+ withRing: {
38
+ true: "border-2 border-card",
39
+ false: "",
40
+ },
41
+ pulse: {
42
+ true: "animate-pulse",
43
+ false: "",
44
+ },
45
+ },
46
+ defaultVariants: {
47
+ variant: "info",
48
+ size: "sm",
49
+ withRing: false,
50
+ pulse: false,
51
+ },
52
+ })
53
+
54
+ export type StatusDotProps = useRender.ComponentProps<"span"> &
55
+ VariantProps<typeof statusDotVariants>
56
+
57
+ export function StatusDot({
58
+ className,
59
+ variant,
60
+ size,
61
+ withRing,
62
+ pulse,
63
+ render,
64
+ ...props
65
+ }: StatusDotProps) {
66
+ return useRender({
67
+ defaultTagName: "span",
68
+ props: mergeProps<"span">(
69
+ {
70
+ className: cn(
71
+ statusDotVariants({ variant, size, withRing, pulse }),
72
+ className,
73
+ ),
74
+ "aria-hidden": true,
75
+ },
76
+ props,
77
+ ),
78
+ render,
79
+ state: {
80
+ slot: "status-dot",
81
+ variant,
82
+ size,
83
+ },
84
+ })
85
+ }
@@ -0,0 +1,19 @@
1
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
2
+
3
+ import { cn } from "../lib/utils";
4
+
5
+ function Switch({ className, ...props }: SwitchPrimitive.Root.Props) {
6
+ return (
7
+ <SwitchPrimitive.Root
8
+ className={cn(
9
+ "group/switch inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border border-transparent bg-input transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[checked]:bg-primary",
10
+ className,
11
+ )}
12
+ {...props}
13
+ >
14
+ <SwitchPrimitive.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-sm ring-0 transition-transform data-[checked]:translate-x-4 data-[unchecked]:translate-x-0" />
15
+ </SwitchPrimitive.Root>
16
+ );
17
+ }
18
+
19
+ export { Switch };
@@ -0,0 +1,80 @@
1
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+
4
+ import { cn } from "../lib/utils";
5
+
6
+ function Tabs({
7
+ className,
8
+ orientation = "horizontal",
9
+ ...props
10
+ }: TabsPrimitive.Root.Props) {
11
+ return (
12
+ <TabsPrimitive.Root
13
+ data-slot="tabs"
14
+ data-orientation={orientation}
15
+ className={cn(
16
+ "group/tabs flex gap-2 data-horizontal:flex-col",
17
+ className,
18
+ )}
19
+ {...props}
20
+ />
21
+ );
22
+ }
23
+
24
+ const tabsListVariants = cva(
25
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
26
+ {
27
+ variants: {
28
+ variant: {
29
+ default: "bg-muted",
30
+ line: "gap-1 bg-transparent",
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ variant: "default",
35
+ },
36
+ },
37
+ );
38
+
39
+ function TabsList({
40
+ className,
41
+ variant = "default",
42
+ ...props
43
+ }: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
44
+ return (
45
+ <TabsPrimitive.List
46
+ data-slot="tabs-list"
47
+ data-variant={variant}
48
+ className={cn(tabsListVariants({ variant }), className)}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+
54
+ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
55
+ return (
56
+ <TabsPrimitive.Tab
57
+ data-slot="tabs-trigger"
58
+ className={cn(
59
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground transition-colors group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
60
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
61
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
62
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
63
+ className,
64
+ )}
65
+ {...props}
66
+ />
67
+ );
68
+ }
69
+
70
+ function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
71
+ return (
72
+ <TabsPrimitive.Panel
73
+ data-slot="tabs-content"
74
+ className={cn("flex-1 text-sm outline-none", className)}
75
+ {...props}
76
+ />
77
+ );
78
+ }
79
+
80
+ export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
@@ -0,0 +1,64 @@
1
+ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
2
+
3
+ import { cn } from "../lib/utils"
4
+
5
+ function TooltipProvider({
6
+ delay = 0,
7
+ ...props
8
+ }: TooltipPrimitive.Provider.Props) {
9
+ return (
10
+ <TooltipPrimitive.Provider
11
+ data-slot="tooltip-provider"
12
+ delay={delay}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
19
+ return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
20
+ }
21
+
22
+ function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
23
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
24
+ }
25
+
26
+ function TooltipContent({
27
+ className,
28
+ side = "top",
29
+ sideOffset = 4,
30
+ align = "center",
31
+ alignOffset = 0,
32
+ children,
33
+ ...props
34
+ }: TooltipPrimitive.Popup.Props &
35
+ Pick<
36
+ TooltipPrimitive.Positioner.Props,
37
+ "align" | "alignOffset" | "side" | "sideOffset"
38
+ >) {
39
+ return (
40
+ <TooltipPrimitive.Portal>
41
+ <TooltipPrimitive.Positioner
42
+ align={align}
43
+ alignOffset={alignOffset}
44
+ side={side}
45
+ sideOffset={sideOffset}
46
+ className="isolate z-50"
47
+ >
48
+ <TooltipPrimitive.Popup
49
+ data-slot="tooltip-content"
50
+ className={cn(
51
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
52
+ className
53
+ )}
54
+ {...props}
55
+ >
56
+ {children}
57
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
58
+ </TooltipPrimitive.Popup>
59
+ </TooltipPrimitive.Positioner>
60
+ </TooltipPrimitive.Portal>
61
+ )
62
+ }
63
+
64
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
@@ -0,0 +1,121 @@
1
+ /* holaOS — the brand-native theme. Quiet near-neutral grays with a cool
2
+ undertone and the holaboss orange reserved for brand/CTA. Hairlines read
3
+ as page rhythm, not cell walls; surfaces (card, muted, accent) sit close
4
+ enough to background that elevation comes from structure rather than tint. */
5
+
6
+ /* Light mode */
7
+ [data-theme="holaos-light"] {
8
+ --background: oklch(1 0 0);
9
+ --foreground: oklch(0.18 0.003 250);
10
+ --card: oklch(0.985 0.002 250);
11
+ --card-foreground: oklch(0.18 0.003 250);
12
+ --popover: oklch(1 0 0);
13
+ --popover-foreground: oklch(0.18 0.003 250);
14
+ --primary: oklch(0.624 0.229 32);
15
+ --primary-foreground: oklch(0.98 0.01 32);
16
+ --secondary: oklch(0.97 0.002 250);
17
+ --secondary-foreground: oklch(0.21 0.003 250);
18
+ --muted: oklch(0.97 0.002 250);
19
+ --muted-foreground: oklch(0.56 0.005 250);
20
+ --accent: oklch(0.95 0.002 250);
21
+ --accent-foreground: oklch(0.18 0.003 250);
22
+ --destructive: oklch(0.577 0.245 27.325);
23
+ --destructive-foreground: oklch(1 0 0);
24
+ --border: oklch(0.92 0.003 250);
25
+ --input: oklch(0.92 0.003 250);
26
+ --ring: oklch(0.624 0.229 32);
27
+ --chart-1: oklch(0.646 0.222 41.116);
28
+ --chart-2: oklch(0.6 0.118 184.704);
29
+ --chart-3: oklch(0.398 0.07 227.392);
30
+ --chart-4: oklch(0.828 0.189 84.429);
31
+ --chart-5: oklch(0.769 0.188 70.08);
32
+ --radius: 0.675rem;
33
+ --sidebar: oklch(0.945 0.002 250);
34
+ --sidebar-foreground: oklch(0.18 0.003 250);
35
+ --sidebar-primary: oklch(0.624 0.229 32);
36
+ --sidebar-primary-foreground: oklch(0.98 0.01 32);
37
+ --sidebar-accent: oklch(0.92 0.002 250);
38
+ --sidebar-accent-foreground: oklch(0.21 0.003 250);
39
+ --sidebar-border: oklch(0.9 0.003 250);
40
+ --sidebar-ring: oklch(0.624 0.229 32);
41
+ --font-sans: 'Inter Variable', sans-serif;
42
+ --font-serif: Source Serif 4, serif;
43
+ --font-mono: JetBrains Mono, monospace;
44
+ --spacing: 0.25rem;
45
+ --shadow-2xs:
46
+ inset 0 0.5px 1px #ffffff30, 0 0.5px 1px #0000000a, 0 1px 2px #00000006;
47
+ --shadow-xs:
48
+ inset 0 0.5px 1px #ffffff35, 0 0.5px 1px #0000000c, 0 1px 2px #00000008;
49
+ --shadow-sm:
50
+ inset 0 1px 2px #ffffff40, 0 1px 2px #00000012, 0 2px 4px #0000000a;
51
+ --shadow: inset 0 1px 2px #ffffff50, 0 2px 4px #00000014, 0 4px 6px #0000000c;
52
+ --shadow-md:
53
+ inset 0 1px 2px #ffffff55, 0 3px 6px #00000016, 0 6px 10px #0000000d;
54
+ --shadow-lg:
55
+ inset 0 1px 2px #ffffff60, 0 4px 8px #00000018, 0 8px 15px #00000010;
56
+ --shadow-xl:
57
+ inset 0 1px 2px #ffffff65, 0 6px 12px #0000001a, 0 12px 20px #00000012;
58
+ --shadow-2xl:
59
+ inset 0 1px 2px #ffffff70, 0 8px 15px #0000001c, 0 18px 28px #00000014;
60
+ }
61
+
62
+ /* Dark mode */
63
+ [data-theme="holaos-dark"] {
64
+ --background: oklch(0.16 0.003 250);
65
+ --foreground: oklch(0.97 0.002 250);
66
+ --card: oklch(0.235 0.003 250);
67
+ --card-foreground: oklch(0.97 0.002 250);
68
+ --popover: oklch(0.235 0.003 250);
69
+ --popover-foreground: oklch(0.97 0.002 250);
70
+ --primary: oklch(0.624 0.229 32);
71
+ --primary-foreground: oklch(0.98 0.01 32);
72
+ --secondary: oklch(0.27 0.003 250);
73
+ --secondary-foreground: oklch(0.97 0.002 250);
74
+ /* Muted reads as a soft mid-tone above background so surfaces using
75
+ bg-muted — tab list rails, code blocks, disabled fields, the user
76
+ chat bubble base mix — actually read on a dark page. */
77
+ --muted: oklch(0.205 0.003 250);
78
+ --muted-foreground: oklch(0.66 0.005 250);
79
+ --accent: oklch(0.30 0.003 250);
80
+ --accent-foreground: oklch(0.97 0.002 250);
81
+ --destructive: oklch(0.653 0.232 25.964);
82
+ --destructive-foreground: oklch(1 0 0);
83
+ /* Border sits clearly above card (0.235) so hairlines on cards are
84
+ visible without being loud against the page surface. */
85
+ --border: oklch(0.32 0.003 250);
86
+ --input: oklch(0.32 0.003 250);
87
+ --ring: oklch(0.624 0.229 32);
88
+ --chart-1: oklch(0.44 0.004 250);
89
+ --chart-2: oklch(0.56 0.004 250);
90
+ --chart-3: oklch(0.71 0.004 250);
91
+ --chart-4: oklch(0.87 0.004 250);
92
+ --chart-5: oklch(0.92 0.004 250);
93
+ --radius: 0.675rem;
94
+ --sidebar: oklch(0.125 0.003 250);
95
+ --sidebar-foreground: oklch(0.97 0.002 250);
96
+ --sidebar-primary: oklch(0.624 0.229 32);
97
+ --sidebar-primary-foreground: oklch(0.97 0.002 250);
98
+ --sidebar-accent: oklch(0.20 0.003 250);
99
+ --sidebar-accent-foreground: oklch(0.97 0.002 250);
100
+ --sidebar-border: oklch(0.24 0.003 250);
101
+ --sidebar-ring: oklch(0.624 0.229 32);
102
+ --font-sans: 'Inter Variable', sans-serif;
103
+ --font-serif: Source Serif 4, serif;
104
+ --font-mono: JetBrains Mono, monospace;
105
+ --spacing: 0.25rem;
106
+ --shadow-2xs:
107
+ inset 0 0.5px 1px #ffffff0a, 0 0.5px 1px #00000050, 0 1px 2px #00000030;
108
+ --shadow-xs:
109
+ inset 0 0.5px 1px #ffffff0d, 0 0.5px 1px #00000050, 0 1px 2px #00000030;
110
+ --shadow-sm:
111
+ inset 0 1px 2px #ffffff15, 0 1px 2px #00000040, 0 2px 4px #00000025;
112
+ --shadow: inset 0 1px 2px #ffffff18, 0 1px 3px #00000045, 0 3px 6px #00000030;
113
+ --shadow-md:
114
+ inset 0 1px 2px #ffffff1a, 0 2px 4px #00000045, 0 4px 8px #00000028;
115
+ --shadow-lg:
116
+ inset 0 1px 2px #ffffff1c, 0 4px 6px #00000045, 0 6px 10px #00000030;
117
+ --shadow-xl:
118
+ inset 0 1px 2px #ffffff20, 0 6px 10px #00000045, 0 8px 15px #00000032;
119
+ --shadow-2xl:
120
+ inset 0 1px 2px #ffffff22, 0 10px 15px #00000045, 0 15px 25px #00000030;
121
+ }