@spunto/design-system 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.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # @spunto/design-system
2
+
3
+ Spunto's shared design system — the warm/flame **tokens**, JS **color constants**,
4
+ and the base **UI primitives** used across Spunto apps (the dashboard and Spunto
5
+ Lite). One source of truth so replicated features stay visually consistent.
6
+
7
+ ## Usage
8
+
9
+ Import the tokens once in your app's entry CSS, right after Tailwind:
10
+
11
+ ```css
12
+ @import "tailwindcss";
13
+ @import "@spunto/design-system/styles.css";
14
+ @custom-variant dark (&:is(.dark *));
15
+ ```
16
+
17
+ Then use the primitives and helpers:
18
+
19
+ ```tsx
20
+ import { Button, Card, Badge, cn } from "@spunto/design-system"
21
+ import { chartColors } from "@spunto/design-system/colors"
22
+
23
+ <Button variant="outline" size="sm">Deploy</Button>
24
+ ```
25
+
26
+ In a Next.js app, add the package to `transpilePackages` (it ships TypeScript source):
27
+
28
+ ```ts
29
+ // next.config.ts
30
+ const nextConfig = { transpilePackages: ["@spunto/design-system"] }
31
+ ```
32
+
33
+ ## What's inside
34
+
35
+ - **`./styles.css`** — oklch token scale (light + warm dark), the `@theme inline`
36
+ → Tailwind color/radius mapping, a minimal base layer, and the `dot-grid` /
37
+ `grid-lines` background utilities. Brand color is **flame** (`--primary` ≈ `#ea5400`);
38
+ radius base is `0.25rem`; `Build`/`Ship`/`Run` are semantic (`bg-build`, `text-run`…).
39
+ - **`cn`** — `clsx` + `tailwind-merge`.
40
+ - **`./colors`** — `cssVar`, `chartColors`, `chartRamp`, `segColors` for JS/chart contexts.
41
+ - **Primitives** — `Button` (+`buttonVariants`), `Card` (+parts), `Input`, `Textarea`,
42
+ `Label`, `Badge` (+`badgeVariants`), `Switch`. Dependency-light (cva + clsx +
43
+ tailwind-merge), no component framework required.
44
+
45
+ ## Peer requirements
46
+
47
+ - React 19+, and a **Tailwind CSS v4** pipeline in the consuming app.
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@spunto/design-system",
3
+ "version": "0.1.0",
4
+ "description": "Spunto's shared design system — warm/flame tokens, color constants, and UI primitives.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "homepage": "https://design.spunto.net",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/coderhammer/spunto.git",
11
+ "directory": "packages/design-system"
12
+ },
13
+ "keywords": [
14
+ "design-system",
15
+ "react",
16
+ "tailwind",
17
+ "ui",
18
+ "spunto"
19
+ ],
20
+ "publishConfig": {
21
+ "registry": "https://registry.npmjs.org/",
22
+ "access": "public"
23
+ },
24
+ "sideEffects": [
25
+ "*.css"
26
+ ],
27
+ "exports": {
28
+ ".": {
29
+ "types": "./src/index.ts",
30
+ "import": "./src/index.ts"
31
+ },
32
+ "./colors": {
33
+ "types": "./src/colors.ts",
34
+ "import": "./src/colors.ts"
35
+ },
36
+ "./styles.css": "./styles.css"
37
+ },
38
+ "files": [
39
+ "src",
40
+ "styles.css",
41
+ "README.md"
42
+ ],
43
+ "scripts": {
44
+ "typecheck": "tsc --noEmit"
45
+ },
46
+ "dependencies": {
47
+ "class-variance-authority": "^0.7.1",
48
+ "clsx": "^2.1.1",
49
+ "tailwind-merge": "^3.6.0"
50
+ },
51
+ "peerDependencies": {
52
+ "react": ">=19",
53
+ "react-dom": ">=19"
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^19",
57
+ "typescript": "^5"
58
+ }
59
+ }
package/src/colors.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Color constants for JS contexts (charts, canvas, inline styles) where CSS
3
+ * classes don't reach. Prefer the Tailwind utilities (`text-primary`, `bg-build`…)
4
+ * in markup; use these only when you must pass a raw color to JS.
5
+ */
6
+
7
+ /** CSS variable references — resolve to the current (light/dark) theme value. */
8
+ export const cssVar = {
9
+ background: "var(--background)",
10
+ foreground: "var(--foreground)",
11
+ border: "var(--border)",
12
+ card: "var(--card)",
13
+ muted: "var(--muted)",
14
+ mutedForeground: "var(--muted-foreground)",
15
+ primary: "var(--primary)",
16
+ destructive: "var(--destructive)",
17
+ flame: "var(--flame)",
18
+ build: "var(--build)",
19
+ ship: "var(--ship)",
20
+ run: "var(--run)",
21
+ } as const
22
+
23
+ /** Fixed oklch line colors for time-series charts (recharts strokes, etc.). */
24
+ export const chartColors = {
25
+ cpu: "oklch(0.70 0.20 43)", // run / flame
26
+ memory: "oklch(0.83 0.15 72)", // build (amber)
27
+ ship: "oklch(0.76 0.18 53)",
28
+ } as const
29
+
30
+ /** Sequential warm ramp (Build → flame). Matches --chart-1..5. */
31
+ export const chartRamp = [
32
+ "oklch(0.79 0.155 70)",
33
+ "oklch(0.72 0.185 52)",
34
+ "oklch(0.66 0.205 42)",
35
+ "oklch(0.58 0.205 35)",
36
+ "oklch(0.52 0.19 28)",
37
+ ] as const
38
+
39
+ /** Categorical, CVD-validated slots for disk/segment breakdowns. */
40
+ export const segColors = {
41
+ workers: "var(--seg-workers)",
42
+ deployments: "var(--seg-deployments)",
43
+ images: "var(--seg-images)",
44
+ buildcache: "var(--seg-buildcache)",
45
+ } as const
@@ -0,0 +1,29 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cn } from "../utils"
4
+
5
+ export const badgeVariants = cva(
6
+ "inline-flex items-center gap-1 rounded-md border px-2 py-0.5 text-xs font-medium",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "border-transparent bg-primary/12 text-primary",
11
+ secondary: "border-transparent bg-secondary text-secondary-foreground",
12
+ outline: "border-border text-foreground",
13
+ success: "border-transparent bg-emerald-500/12 text-emerald-600 dark:text-emerald-400",
14
+ warning: "border-transparent bg-amber-500/15 text-amber-600 dark:text-amber-400",
15
+ destructive: "border-transparent bg-destructive/12 text-destructive",
16
+ muted: "border-transparent bg-muted text-muted-foreground",
17
+ },
18
+ },
19
+ defaultVariants: { variant: "default" },
20
+ },
21
+ )
22
+
23
+ export function Badge({
24
+ className,
25
+ variant,
26
+ ...props
27
+ }: React.HTMLAttributes<HTMLSpanElement> & VariantProps<typeof badgeVariants>) {
28
+ return <span className={cn(badgeVariants({ variant }), className)} {...props} />
29
+ }
@@ -0,0 +1,36 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cn } from "../utils"
4
+
5
+ export const buttonVariants = cva(
6
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-primary text-primary-foreground hover:opacity-90",
11
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
12
+ outline: "border border-border bg-transparent hover:bg-accent hover:text-accent-foreground",
13
+ ghost: "hover:bg-accent hover:text-accent-foreground",
14
+ destructive: "bg-destructive text-white hover:opacity-90",
15
+ },
16
+ size: {
17
+ default: "h-9 px-4 py-2",
18
+ sm: "h-8 px-3 text-xs",
19
+ lg: "h-10 px-6",
20
+ icon: "size-9",
21
+ },
22
+ },
23
+ defaultVariants: { variant: "default", size: "default" },
24
+ },
25
+ )
26
+
27
+ export interface ButtonProps
28
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
29
+ VariantProps<typeof buttonVariants> {}
30
+
31
+ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
32
+ ({ className, variant, size, ...props }, ref) => (
33
+ <button ref={ref} className={cn(buttonVariants({ variant, size }), className)} {...props} />
34
+ ),
35
+ )
36
+ Button.displayName = "Button"
@@ -0,0 +1,26 @@
1
+ import * as React from "react"
2
+ import { cn } from "../utils"
3
+
4
+ export function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
5
+ return <div className={cn("rounded-xl border border-border bg-card text-card-foreground", className)} {...props} />
6
+ }
7
+
8
+ export function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
9
+ return <div className={cn("flex flex-col gap-1.5 p-5", className)} {...props} />
10
+ }
11
+
12
+ export function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {
13
+ return <h3 className={cn("font-semibold leading-none tracking-tight", className)} {...props} />
14
+ }
15
+
16
+ export function CardDescription({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) {
17
+ return <p className={cn("text-sm text-muted-foreground", className)} {...props} />
18
+ }
19
+
20
+ export function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
21
+ return <div className={cn("p-5 pt-0", className)} {...props} />
22
+ }
23
+
24
+ export function CardFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
25
+ return <div className={cn("flex items-center p-5 pt-0", className)} {...props} />
26
+ }
@@ -0,0 +1,16 @@
1
+ import * as React from "react"
2
+ import { cn } from "../utils"
3
+
4
+ export const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLInputElement>>(
5
+ ({ className, ...props }, ref) => (
6
+ <input
7
+ ref={ref}
8
+ className={cn(
9
+ "flex h-9 w-full rounded-lg border border-input bg-background px-3 py-1 text-sm shadow-none transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
10
+ className,
11
+ )}
12
+ {...props}
13
+ />
14
+ ),
15
+ )
16
+ Input.displayName = "Input"
@@ -0,0 +1,9 @@
1
+ import * as React from "react"
2
+ import { cn } from "../utils"
3
+
4
+ export const Label = React.forwardRef<HTMLLabelElement, React.LabelHTMLAttributes<HTMLLabelElement>>(
5
+ ({ className, ...props }, ref) => (
6
+ <label ref={ref} className={cn("text-sm font-medium leading-none", className)} {...props} />
7
+ ),
8
+ )
9
+ Label.displayName = "Label"
@@ -0,0 +1,41 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "../utils"
5
+
6
+ export function Switch({
7
+ checked,
8
+ onCheckedChange,
9
+ className,
10
+ id,
11
+ disabled,
12
+ }: {
13
+ checked: boolean
14
+ onCheckedChange: (v: boolean) => void
15
+ className?: string
16
+ id?: string
17
+ disabled?: boolean
18
+ }) {
19
+ return (
20
+ <button
21
+ type="button"
22
+ role="switch"
23
+ id={id}
24
+ aria-checked={checked}
25
+ disabled={disabled}
26
+ onClick={() => onCheckedChange(!checked)}
27
+ className={cn(
28
+ "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50",
29
+ checked ? "bg-primary" : "bg-input",
30
+ className,
31
+ )}
32
+ >
33
+ <span
34
+ className={cn(
35
+ "inline-block size-4 rounded-full bg-white shadow-sm transition-transform",
36
+ checked ? "translate-x-4" : "translate-x-0.5",
37
+ )}
38
+ />
39
+ </button>
40
+ )
41
+ }
@@ -0,0 +1,16 @@
1
+ import * as React from "react"
2
+ import { cn } from "../utils"
3
+
4
+ export const Textarea = React.forwardRef<HTMLTextAreaElement, React.TextareaHTMLAttributes<HTMLTextAreaElement>>(
5
+ ({ className, ...props }, ref) => (
6
+ <textarea
7
+ ref={ref}
8
+ className={cn(
9
+ "flex min-h-[72px] w-full rounded-lg border border-input bg-background px-3 py-2 text-sm font-mono placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
10
+ className,
11
+ )}
12
+ {...props}
13
+ />
14
+ ),
15
+ )
16
+ Textarea.displayName = "Textarea"
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ // @spunto/design-system — shared UI primitives, helpers, and color constants.
2
+ // Tokens ship as a CSS file: `import "@spunto/design-system/styles.css"`.
3
+
4
+ export { cn } from "./utils"
5
+ export * from "./colors"
6
+
7
+ export { Button, buttonVariants, type ButtonProps } from "./components/button"
8
+ export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./components/card"
9
+ export { Input } from "./components/input"
10
+ export { Textarea } from "./components/textarea"
11
+ export { Label } from "./components/label"
12
+ export { Badge, badgeVariants } from "./components/badge"
13
+ export { Switch } from "./components/switch"
package/src/utils.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ /** Merge Tailwind class names, de-duplicating conflicting utilities. */
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
package/styles.css ADDED
@@ -0,0 +1,186 @@
1
+ /*
2
+ * @spunto/design-system — design tokens (warm / Mistral-inspired, brand: flame).
3
+ *
4
+ * Import AFTER `@import "tailwindcss"` in your app's entry CSS:
5
+ * @import "tailwindcss";
6
+ * @import "@spunto/design-system/styles.css";
7
+ *
8
+ * Provides the oklch token scale, the `@theme inline` → Tailwind color/radius
9
+ * mapping, a minimal base layer, and the warm dot-grid / blueprint-grid utilities.
10
+ * `@custom-variant dark` stays in the app (or add it there once).
11
+ */
12
+
13
+ @theme inline {
14
+ --color-background: var(--background);
15
+ --color-foreground: var(--foreground);
16
+ --font-sans: var(--font-geist-sans);
17
+ --font-mono: var(--font-geist-mono);
18
+ --font-syne: var(--font-syne);
19
+ --color-sidebar-ring: var(--sidebar-ring);
20
+ --color-sidebar-border: var(--sidebar-border);
21
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
22
+ --color-sidebar-accent: var(--sidebar-accent);
23
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
24
+ --color-sidebar-primary: var(--sidebar-primary);
25
+ --color-sidebar-foreground: var(--sidebar-foreground);
26
+ --color-sidebar: var(--sidebar);
27
+ --color-chart-5: var(--chart-5);
28
+ --color-chart-4: var(--chart-4);
29
+ --color-chart-3: var(--chart-3);
30
+ --color-chart-2: var(--chart-2);
31
+ --color-chart-1: var(--chart-1);
32
+ --color-ring: var(--ring);
33
+ --color-input: var(--input);
34
+ --color-border: var(--border);
35
+ --color-destructive: var(--destructive);
36
+ --color-accent-foreground: var(--accent-foreground);
37
+ --color-accent: var(--accent);
38
+ --color-muted-foreground: var(--muted-foreground);
39
+ --color-muted: var(--muted);
40
+ --color-secondary-foreground: var(--secondary-foreground);
41
+ --color-secondary: var(--secondary);
42
+ --color-primary-foreground: var(--primary-foreground);
43
+ --color-primary: var(--primary);
44
+ --color-popover-foreground: var(--popover-foreground);
45
+ --color-popover: var(--popover);
46
+ --color-card-foreground: var(--card-foreground);
47
+ --color-card: var(--card);
48
+ /* Brand warm palette — Build / Ship / Run + signature flame */
49
+ --color-build: var(--build);
50
+ --color-ship: var(--ship);
51
+ --color-run: var(--run);
52
+ --color-flame: var(--flame);
53
+ /* Square-leaning radius scale — driven by --radius (4px base) */
54
+ --radius-sm: calc(var(--radius) * 0.5);
55
+ --radius-md: calc(var(--radius) * 0.75);
56
+ --radius-lg: var(--radius);
57
+ --radius-xl: calc(var(--radius) * 1.5);
58
+ --radius-2xl: calc(var(--radius) * 2);
59
+ --radius-3xl: calc(var(--radius) * 2.75);
60
+ --radius-4xl: calc(var(--radius) * 3.5);
61
+ }
62
+
63
+ /* ─── Light mode — Warm cream, Mistral-inspired ─────────────────────────── */
64
+ :root {
65
+ --background: oklch(0.975 0.012 82);
66
+ --foreground: oklch(0.20 0.018 55);
67
+ --card: oklch(0.995 0.006 86);
68
+ --card-foreground: oklch(0.20 0.018 55);
69
+ --popover: oklch(0.995 0.006 86);
70
+ --popover-foreground: oklch(0.20 0.018 55);
71
+ --primary: oklch(0.64 0.205 41);
72
+ --primary-foreground: oklch(0.99 0.012 86);
73
+ --secondary: oklch(0.93 0.015 78);
74
+ --secondary-foreground: oklch(0.34 0.045 52);
75
+ --muted: oklch(0.955 0.012 80);
76
+ --muted-foreground: oklch(0.51 0.032 60);
77
+ --accent: oklch(0.935 0.024 72);
78
+ --accent-foreground: oklch(0.34 0.045 52);
79
+ --destructive: oklch(0.577 0.245 27.325);
80
+ --border: oklch(0.89 0.016 76);
81
+ --input: oklch(0.89 0.016 76);
82
+ --ring: oklch(0.64 0.205 41);
83
+ /* Brand warm scale — Build (amber) → Ship (orange) → Run (flame) */
84
+ --build: oklch(0.79 0.155 70);
85
+ --ship: oklch(0.72 0.185 52);
86
+ --run: oklch(0.66 0.205 42);
87
+ --flame: oklch(0.64 0.205 41);
88
+ --chart-1: oklch(0.79 0.155 70);
89
+ --chart-2: oklch(0.72 0.185 52);
90
+ --chart-3: oklch(0.66 0.205 42);
91
+ --chart-4: oklch(0.58 0.205 35);
92
+ --chart-5: oklch(0.52 0.19 28);
93
+ --seg-workers: #eb6834;
94
+ --seg-deployments: #256abf;
95
+ --seg-images: #1baf7a;
96
+ --seg-buildcache: #eda100;
97
+ --radius: 0.25rem;
98
+ --sidebar: oklch(0.96 0.014 80);
99
+ --sidebar-foreground: oklch(0.20 0.018 55);
100
+ --sidebar-primary: oklch(0.64 0.205 41);
101
+ --sidebar-primary-foreground: oklch(0.99 0.012 86);
102
+ --sidebar-accent: oklch(0.93 0.022 74);
103
+ --sidebar-accent-foreground: oklch(0.30 0.04 52);
104
+ --sidebar-border: oklch(0.89 0.016 76);
105
+ --sidebar-ring: oklch(0.64 0.205 41);
106
+ }
107
+
108
+ /* ─── Dark mode — Warm charcoal, golden undertone ───────────────────────── */
109
+ .dark {
110
+ --background: oklch(0.155 0.011 52);
111
+ --foreground: oklch(0.95 0.009 78);
112
+ --card: oklch(0.195 0.012 52);
113
+ --card-foreground: oklch(0.95 0.009 78);
114
+ --popover: oklch(0.195 0.012 52);
115
+ --popover-foreground: oklch(0.95 0.009 78);
116
+ --primary: oklch(0.70 0.20 43);
117
+ --primary-foreground: oklch(0.16 0.012 52);
118
+ --secondary: oklch(0.26 0.016 52);
119
+ --secondary-foreground: oklch(0.95 0.009 78);
120
+ --muted: oklch(0.23 0.014 52);
121
+ --muted-foreground: oklch(0.67 0.022 66);
122
+ --accent: oklch(0.28 0.018 54);
123
+ --accent-foreground: oklch(0.95 0.009 78);
124
+ --destructive: oklch(0.704 0.191 22.216);
125
+ --border: oklch(0.92 0.03 70 / 11%);
126
+ --input: oklch(0.92 0.03 70 / 14%);
127
+ --ring: oklch(0.70 0.20 43);
128
+ --build: oklch(0.83 0.15 72);
129
+ --ship: oklch(0.76 0.18 53);
130
+ --run: oklch(0.71 0.20 43);
131
+ --flame: oklch(0.71 0.20 43);
132
+ --chart-1: oklch(0.83 0.15 72);
133
+ --chart-2: oklch(0.76 0.18 53);
134
+ --chart-3: oklch(0.71 0.20 43);
135
+ --chart-4: oklch(0.64 0.20 36);
136
+ --chart-5: oklch(0.57 0.19 29);
137
+ --seg-workers: #d95926;
138
+ --seg-deployments: #3987e5;
139
+ --seg-images: #199e70;
140
+ --seg-buildcache: #c98500;
141
+ --sidebar: oklch(0.18 0.012 52);
142
+ --sidebar-foreground: oklch(0.95 0.009 78);
143
+ --sidebar-primary: oklch(0.70 0.20 43);
144
+ --sidebar-primary-foreground: oklch(0.16 0.012 52);
145
+ --sidebar-accent: oklch(0.26 0.016 52);
146
+ --sidebar-accent-foreground: oklch(0.95 0.009 78);
147
+ --sidebar-border: oklch(0.92 0.03 70 / 11%);
148
+ --sidebar-ring: oklch(0.70 0.20 43);
149
+ }
150
+
151
+ /* ─── Base layer ─────────────────────────────────────────────────────────── */
152
+ @layer base {
153
+ * {
154
+ border-color: var(--border);
155
+ outline-color: color-mix(in oklch, var(--ring) 50%, transparent);
156
+ }
157
+ body {
158
+ background-color: var(--background);
159
+ color: var(--foreground);
160
+ font-family: var(--font-sans);
161
+ }
162
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
163
+ ::-webkit-scrollbar-track { background: transparent; }
164
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 9999px; }
165
+ ::-webkit-scrollbar-thumb:hover { background: color-mix(in oklch, var(--muted-foreground) 30%, transparent); }
166
+ }
167
+
168
+ /* ─── Warm background utilities ──────────────────────────────────────────── */
169
+ .dot-grid {
170
+ background-image: radial-gradient(circle, oklch(0.45 0.05 50 / 0.08) 1px, transparent 1px);
171
+ background-size: 32px 32px;
172
+ }
173
+ .dark .dot-grid {
174
+ background-image: radial-gradient(circle, oklch(0.92 0.04 70 / 0.045) 1px, transparent 1px);
175
+ }
176
+ .grid-lines {
177
+ background-image:
178
+ linear-gradient(to right, oklch(0.45 0.05 50 / 0.055) 1px, transparent 1px),
179
+ linear-gradient(to bottom, oklch(0.45 0.05 50 / 0.055) 1px, transparent 1px);
180
+ background-size: 56px 56px;
181
+ }
182
+ .dark .grid-lines {
183
+ background-image:
184
+ linear-gradient(to right, oklch(0.92 0.04 70 / 0.04) 1px, transparent 1px),
185
+ linear-gradient(to bottom, oklch(0.92 0.04 70 / 0.04) 1px, transparent 1px);
186
+ }