@syncular/ui 0.0.4-25 → 0.0.4-32

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.
Files changed (48) hide show
  1. package/dist/console/api-keys-table.js +1 -1
  2. package/dist/console/api-keys-table.js.map +1 -1
  3. package/dist/console/danger-action-card.d.ts.map +1 -1
  4. package/dist/console/danger-action-card.js +1 -1
  5. package/dist/console/danger-action-card.js.map +1 -1
  6. package/dist/console/empty-state.js +1 -1
  7. package/dist/console/empty-state.js.map +1 -1
  8. package/dist/console/fleet-table.d.ts +14 -0
  9. package/dist/console/fleet-table.d.ts.map +1 -0
  10. package/dist/console/fleet-table.js +46 -0
  11. package/dist/console/fleet-table.js.map +1 -0
  12. package/dist/console/handlers-table.js +1 -1
  13. package/dist/console/handlers-table.js.map +1 -1
  14. package/dist/console/index.d.ts +1 -0
  15. package/dist/console/index.d.ts.map +1 -1
  16. package/dist/console/index.js +1 -0
  17. package/dist/console/index.js.map +1 -1
  18. package/dist/console/panel-shell.d.ts.map +1 -1
  19. package/dist/console/panel-shell.js +1 -1
  20. package/dist/console/panel-shell.js.map +1 -1
  21. package/dist/console/section-card.d.ts.map +1 -1
  22. package/dist/console/section-card.js +1 -1
  23. package/dist/console/section-card.js.map +1 -1
  24. package/dist/primitives/dialog.js +1 -1
  25. package/dist/primitives/dialog.js.map +1 -1
  26. package/dist/primitives/index.d.ts +1 -0
  27. package/dist/primitives/index.d.ts.map +1 -1
  28. package/dist/primitives/index.js +1 -0
  29. package/dist/primitives/index.js.map +1 -1
  30. package/dist/primitives/typography.d.ts +27 -0
  31. package/dist/primitives/typography.d.ts.map +1 -0
  32. package/dist/primitives/typography.js +36 -0
  33. package/dist/primitives/typography.js.map +1 -0
  34. package/dist/styles.css +2805 -0
  35. package/package.json +9 -6
  36. package/src/console/api-keys-table.tsx +1 -1
  37. package/src/console/danger-action-card.tsx +6 -2
  38. package/src/console/empty-state.tsx +1 -1
  39. package/src/console/fleet-table.tsx +147 -0
  40. package/src/console/handlers-table.tsx +1 -1
  41. package/src/console/index.ts +1 -0
  42. package/src/console/panel-shell.tsx +8 -2
  43. package/src/console/section-card.tsx +8 -2
  44. package/src/primitives/dialog.tsx +1 -1
  45. package/src/primitives/index.ts +1 -0
  46. package/src/primitives/typography.tsx +88 -0
  47. package/src/styles/styles.css +20 -16
  48. package/src/styles/tokens.css +94 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/ui",
3
- "version": "0.0.4-25",
3
+ "version": "0.0.4-32",
4
4
  "description": "Reusable Syncular UI components and styles",
5
5
  "license": "MIT",
6
6
  "author": "Benjamin Kniffler",
@@ -81,7 +81,8 @@
81
81
  "default": "./dist/navigation/index.js"
82
82
  }
83
83
  },
84
- "./styles.css": "./src/styles/styles.css",
84
+ "./styles.css": "./dist/styles.css",
85
+ "./styles.source.css": "./src/styles/styles.css",
85
86
  "./styles/tokens.css": "./src/styles/tokens.css",
86
87
  "./package.json": "./package.json"
87
88
  },
@@ -91,7 +92,8 @@
91
92
  ],
92
93
  "scripts": {
93
94
  "tsgo": "tsgo --noEmit",
94
- "build": "tsgo",
95
+ "build:css": "bunx @tailwindcss/cli -i src/styles/styles.css -o dist/styles.css",
96
+ "build": "tsgo && bun run build:css",
95
97
  "release": "bunx syncular-publish"
96
98
  },
97
99
  "peerDependencies": {
@@ -102,13 +104,14 @@
102
104
  "@base-ui/react": "^1.2.0",
103
105
  "class-variance-authority": "^0.7.1",
104
106
  "clsx": "^2.1.1",
105
- "lucide-react": "^0.564.0",
107
+ "lucide-react": "^0.575.0",
106
108
  "recharts": "^3.7.0",
107
- "tailwind-merge": "^3.4.0",
108
- "tailwindcss": "^4.1.18"
109
+ "tailwind-merge": "^3.5.0",
110
+ "tailwindcss": "^4.2.0"
109
111
  },
110
112
  "devDependencies": {
111
113
  "@syncular/config": "0.0.0",
114
+ "@tailwindcss/cli": "^4.2.0",
112
115
  "@types/react": "^19.2.14"
113
116
  }
114
117
  }
@@ -56,7 +56,7 @@ const ApiKeysTable = forwardRef<HTMLDivElement, ApiKeysTableProps>(
56
56
  {/* Rows */}
57
57
  {keys.map((k, i) => (
58
58
  <div
59
- key={k.name}
59
+ key={`${k.name}:${k.prefix}:${i}`}
60
60
  className={cn(
61
61
  'font-mono text-[11px] leading-7 px-4 flex items-center gap-4 hover:bg-white/[0.015] transition-colors cursor-default',
62
62
  i < keys.length - 1 && 'border-b border-[#141414]'
@@ -24,9 +24,13 @@ export function DangerActionCard({
24
24
  return (
25
25
  <Card className={cn('border-offline/20', className)}>
26
26
  <CardContent className="flex flex-col gap-3">
27
- <h3 className="text-lg font-semibold text-offline">{title}</h3>
27
+ <h3 className="font-mono text-[10px] text-offline uppercase tracking-widest">
28
+ {title}
29
+ </h3>
28
30
  {description ? (
29
- <p className="text-sm text-neutral-500">{description}</p>
31
+ <p className="font-mono text-[10px] text-neutral-500">
32
+ {description}
33
+ </p>
30
34
  ) : null}
31
35
  {stats ? <div>{stats}</div> : null}
32
36
  {onAction ? (
@@ -24,7 +24,7 @@ export function EmptyState({
24
24
  )}
25
25
  >
26
26
  {icon ? <div className="text-neutral-500">{icon}</div> : null}
27
- <p className="text-sm text-neutral-500">{message}</p>
27
+ <p className="font-mono text-[10px] text-neutral-500">{message}</p>
28
28
  {action ? <div>{action}</div> : null}
29
29
  </div>
30
30
  );
@@ -0,0 +1,147 @@
1
+ 'use client';
2
+
3
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react';
4
+ import { cn } from '../lib/cn';
5
+ import type { SyncClientNode } from '../lib/types';
6
+ import { Badge } from '../primitives/badge';
7
+ import {
8
+ Table,
9
+ TableBody,
10
+ TableCell,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ } from '../primitives/table';
15
+
16
+ export type FleetTableProps = ComponentPropsWithoutRef<'div'> & {
17
+ clients: SyncClientNode[];
18
+ headSeq: number;
19
+ onEvict?: (clientId: string) => void;
20
+ };
21
+
22
+ function getLagColor(lag: number) {
23
+ if (lag === 0) return '#22c55e';
24
+ if (lag < 10) return '#f59e0b';
25
+ if (lag < 50) return '#f97316';
26
+ return '#ef4444';
27
+ }
28
+
29
+ const statusBadgeVariant = {
30
+ online: 'healthy',
31
+ syncing: 'syncing',
32
+ offline: 'offline',
33
+ } as const;
34
+
35
+ const FleetTable = forwardRef<HTMLDivElement, FleetTableProps>(
36
+ ({ className, clients, headSeq, onEvict, ...props }, ref) => {
37
+ return (
38
+ <div ref={ref} className={cn('w-full', className)} {...props}>
39
+ <Table>
40
+ <TableHeader>
41
+ <TableRow>
42
+ <TableHead>Client</TableHead>
43
+ <TableHead>Status</TableHead>
44
+ <TableHead>Type</TableHead>
45
+ <TableHead>Cursor</TableHead>
46
+ <TableHead>Lag</TableHead>
47
+ <TableHead>Dialect</TableHead>
48
+ <TableHead>Mode</TableHead>
49
+ {onEvict && <TableHead>Actions</TableHead>}
50
+ </TableRow>
51
+ </TableHeader>
52
+ <TableBody>
53
+ {clients.map((client) => {
54
+ const lag = Math.max(0, headSeq - client.cursor);
55
+ const pct =
56
+ headSeq > 0
57
+ ? Math.min(100, (client.cursor / headSeq) * 100)
58
+ : 100;
59
+ const lagColor = getLagColor(lag);
60
+
61
+ return (
62
+ <TableRow key={client.id}>
63
+ <TableCell>
64
+ <div className="flex items-center gap-2">
65
+ <span
66
+ className="w-1.5 h-1.5 rounded-full flex-shrink-0"
67
+ style={{
68
+ background: lagColor,
69
+ boxShadow: `0 0 4px ${lagColor}`,
70
+ }}
71
+ />
72
+ <span
73
+ className="font-mono text-[11px] text-white truncate"
74
+ title={client.id}
75
+ >
76
+ {client.id.length > 18
77
+ ? `${client.id.substring(0, 18)}\u2026`
78
+ : client.id}
79
+ </span>
80
+ </div>
81
+ </TableCell>
82
+ <TableCell>
83
+ <Badge variant={statusBadgeVariant[client.status]}>
84
+ {client.status}
85
+ </Badge>
86
+ </TableCell>
87
+ <TableCell>
88
+ <span className="font-mono text-[10px] text-neutral-400">
89
+ {client.type}
90
+ </span>
91
+ </TableCell>
92
+ <TableCell>
93
+ <span className="font-mono text-[11px] text-white font-medium">
94
+ #{client.cursor.toLocaleString()}
95
+ </span>
96
+ </TableCell>
97
+ <TableCell>
98
+ <div className="flex items-center gap-2">
99
+ <div className="w-[60px] h-[3px] rounded-full bg-surface overflow-hidden">
100
+ <div
101
+ className="h-full rounded-full transition-all"
102
+ style={{ width: `${pct}%`, background: lagColor }}
103
+ />
104
+ </div>
105
+ <span
106
+ className="font-mono text-[10px] font-medium"
107
+ style={{ color: lagColor }}
108
+ >
109
+ {lag === 0 ? '0' : `${lag}`}
110
+ </span>
111
+ </div>
112
+ </TableCell>
113
+ <TableCell>
114
+ <span className="font-mono text-[10px] text-neutral-400">
115
+ {client.dialect}
116
+ </span>
117
+ </TableCell>
118
+ <TableCell>
119
+ <Badge
120
+ variant={client.mode === 'realtime' ? 'flow' : 'ghost'}
121
+ >
122
+ {client.mode}
123
+ </Badge>
124
+ </TableCell>
125
+ {onEvict && (
126
+ <TableCell>
127
+ <button
128
+ type="button"
129
+ onClick={() => onEvict(client.id)}
130
+ className="inline-flex items-center gap-1 rounded-md font-mono text-[9px] px-2 py-1 border border-transparent text-neutral-600 hover:border-offline/50 hover:text-offline hover:bg-offline/[0.06] cursor-pointer transition-all opacity-0 group-hover:opacity-100"
131
+ >
132
+ evict
133
+ </button>
134
+ </TableCell>
135
+ )}
136
+ </TableRow>
137
+ );
138
+ })}
139
+ </TableBody>
140
+ </Table>
141
+ </div>
142
+ );
143
+ }
144
+ );
145
+ FleetTable.displayName = 'FleetTable';
146
+
147
+ export { FleetTable };
@@ -46,7 +46,7 @@ const HandlersTable = forwardRef<HTMLDivElement, HandlersTableProps>(
46
46
  {/* Rows */}
47
47
  {handlers.map((h, i) => (
48
48
  <div
49
- key={h.table}
49
+ key={`${h.table}:${i}`}
50
50
  className={cn(
51
51
  'font-mono text-[11px] leading-7 px-4 flex items-center gap-4 hover:bg-white/[0.015] transition-colors cursor-default',
52
52
  i < handlers.length - 1 && 'border-b border-[#141414]'
@@ -9,6 +9,7 @@ export * from './danger-action-card';
9
9
  export * from './empty-state';
10
10
  export * from './filter-bar';
11
11
  export * from './fleet-card';
12
+ export * from './fleet-table';
12
13
  export * from './handlers-table';
13
14
  export * from './kpi-card';
14
15
  export * from './kpi-strip';
@@ -26,9 +26,15 @@ export function PanelShell({
26
26
  {title || actions ? (
27
27
  <div className="flex items-start justify-between px-4 pt-4">
28
28
  <div>
29
- {title ? <h3 className="text-lg font-semibold">{title}</h3> : null}
29
+ {title ? (
30
+ <h3 className="font-mono text-[10px] text-neutral-500 uppercase tracking-widest">
31
+ {title}
32
+ </h3>
33
+ ) : null}
30
34
  {description ? (
31
- <p className="mt-1 text-sm text-neutral-500">{description}</p>
35
+ <p className="mt-1 font-mono text-[10px] text-neutral-500">
36
+ {description}
37
+ </p>
32
38
  ) : null}
33
39
  </div>
34
40
  {actions ? (
@@ -25,9 +25,15 @@ export function SectionCard({
25
25
  {title || actions ? (
26
26
  <div className="flex items-start justify-between px-4 pt-4">
27
27
  <div>
28
- {title ? <h3 className="text-lg font-semibold">{title}</h3> : null}
28
+ {title ? (
29
+ <h3 className="font-mono text-[10px] text-neutral-500 uppercase tracking-widest">
30
+ {title}
31
+ </h3>
32
+ ) : null}
29
33
  {description ? (
30
- <p className="mt-1 text-sm text-neutral-500">{description}</p>
34
+ <p className="mt-1 font-mono text-[10px] text-neutral-500">
35
+ {description}
36
+ </p>
31
37
  ) : null}
32
38
  </div>
33
39
  {actions ? (
@@ -94,7 +94,7 @@ const DialogDescription = forwardRef<
94
94
  >(({ className, ...props }, ref) => (
95
95
  <BaseDialog.Description
96
96
  ref={ref}
97
- className={cn('text-sm text-neutral-400', className)}
97
+ className={cn('font-mono text-[10px] text-neutral-500', className)}
98
98
  {...props}
99
99
  />
100
100
  ));
@@ -13,3 +13,4 @@ export * from './switch';
13
13
  export * from './table';
14
14
  export * from './tabs';
15
15
  export * from './tooltip';
16
+ export * from './typography';
@@ -0,0 +1,88 @@
1
+ 'use client';
2
+
3
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react';
4
+ import { cn } from '../lib/cn';
5
+
6
+ /**
7
+ * Dialog/panel body text — primary weight.
8
+ * `font-mono text-[11px] text-neutral-300`
9
+ */
10
+ const Text = forwardRef<HTMLParagraphElement, ComponentPropsWithoutRef<'p'>>(
11
+ ({ className, ...props }, ref) => (
12
+ <p
13
+ ref={ref}
14
+ className={cn('font-mono text-[11px] text-neutral-300', className)}
15
+ {...props}
16
+ />
17
+ )
18
+ );
19
+ Text.displayName = 'Text';
20
+
21
+ /**
22
+ * Secondary / meta text — smaller, muted.
23
+ * `font-mono text-[10px] text-neutral-500`
24
+ */
25
+ const TextMuted = forwardRef<
26
+ HTMLParagraphElement,
27
+ ComponentPropsWithoutRef<'p'>
28
+ >(({ className, ...props }, ref) => (
29
+ <p
30
+ ref={ref}
31
+ className={cn('font-mono text-[10px] text-neutral-500', className)}
32
+ {...props}
33
+ />
34
+ ));
35
+ TextMuted.displayName = 'TextMuted';
36
+
37
+ /**
38
+ * Inline code / monospace value.
39
+ * `font-mono text-[11px] text-white`
40
+ */
41
+ const TextCode = forwardRef<HTMLElement, ComponentPropsWithoutRef<'code'>>(
42
+ ({ className, ...props }, ref) => (
43
+ <code
44
+ ref={ref}
45
+ className={cn('font-mono text-[11px] text-white', className)}
46
+ {...props}
47
+ />
48
+ )
49
+ );
50
+ TextCode.displayName = 'TextCode';
51
+
52
+ /**
53
+ * Uppercase monospace label — section headers, code block labels.
54
+ * `font-mono text-[9px] uppercase tracking-wider text-neutral-500`
55
+ */
56
+ const TextLabel = forwardRef<HTMLSpanElement, ComponentPropsWithoutRef<'span'>>(
57
+ ({ className, ...props }, ref) => (
58
+ <span
59
+ ref={ref}
60
+ className={cn(
61
+ 'font-mono text-[9px] uppercase tracking-wider text-neutral-500',
62
+ className
63
+ )}
64
+ {...props}
65
+ />
66
+ )
67
+ );
68
+ TextLabel.displayName = 'TextLabel';
69
+
70
+ /**
71
+ * Pre-formatted code block.
72
+ * `font-mono text-[11px] text-neutral-300 p-3 rounded border border-border bg-panel-alt overflow-x-auto`
73
+ */
74
+ const CodeBlock = forwardRef<HTMLPreElement, ComponentPropsWithoutRef<'pre'>>(
75
+ ({ className, ...props }, ref) => (
76
+ <pre
77
+ ref={ref}
78
+ className={cn(
79
+ 'font-mono text-[11px] text-neutral-300 p-3 rounded border border-border bg-panel-alt overflow-x-auto',
80
+ className
81
+ )}
82
+ {...props}
83
+ />
84
+ )
85
+ );
86
+ CodeBlock.displayName = 'CodeBlock';
87
+
88
+ export { Text, TextMuted, TextCode, TextLabel, CodeBlock };
@@ -1,29 +1,33 @@
1
- @import 'tailwindcss';
1
+ @import 'tailwindcss' source(none);
2
2
  @import './tokens.css';
3
3
 
4
+ /* Explicitly scan UI component source files for Tailwind class usage */
5
+ @source "..";
6
+
4
7
  /* ── Base ── */
5
- body {
6
- background: var(--color-background);
7
- color: var(--color-foreground);
8
- font-family: var(--font-display), ui-sans-serif, system-ui, sans-serif;
8
+ :where(.syncular-console-root, .syncular-ui-root) {
9
+ background: var(--syncular-color-background);
10
+ color: var(--syncular-color-foreground);
11
+ font-family: var(--syncular-font-display), ui-sans-serif, system-ui,
12
+ sans-serif;
9
13
  margin: 0;
10
14
  -webkit-font-smoothing: antialiased;
11
15
  -moz-osx-font-smoothing: grayscale;
12
16
  }
13
17
 
14
- .font-mono {
15
- font-family: var(--font-mono), ui-monospace, monospace;
18
+ :where(.syncular-console-root, .syncular-ui-root) .font-mono {
19
+ font-family: var(--syncular-font-mono), ui-monospace, monospace;
16
20
  }
17
21
 
18
22
  /* ── Scrollbar ── */
19
- ::-webkit-scrollbar {
23
+ :where(.syncular-console-root, .syncular-ui-root) ::-webkit-scrollbar {
20
24
  width: 3px;
21
25
  height: 3px;
22
26
  }
23
- ::-webkit-scrollbar-track {
27
+ :where(.syncular-console-root, .syncular-ui-root) ::-webkit-scrollbar-track {
24
28
  background: transparent;
25
29
  }
26
- ::-webkit-scrollbar-thumb {
30
+ :where(.syncular-console-root, .syncular-ui-root) ::-webkit-scrollbar-thumb {
27
31
  background: #333;
28
32
  border-radius: 2px;
29
33
  }
@@ -112,16 +116,16 @@ body {
112
116
  }
113
117
  }
114
118
 
115
- .line-active {
119
+ :where(.syncular-console-root, .syncular-ui-root) .line-active {
116
120
  stroke-dasharray: 4 2;
117
121
  animation: dashFlow 1s linear infinite;
118
122
  }
119
123
 
120
- .stream-entry {
124
+ :where(.syncular-console-root, .syncular-ui-root) .stream-entry {
121
125
  animation: streamSlide 0.35s ease-out;
122
126
  }
123
127
 
124
- .dot-pulse {
128
+ :where(.syncular-console-root, .syncular-ui-root) .dot-pulse {
125
129
  animation: dotPulse 1.4s ease-in-out infinite;
126
130
  }
127
131
 
@@ -137,7 +141,7 @@ body {
137
141
  }
138
142
  }
139
143
 
140
- .flow-arrow {
144
+ :where(.syncular-console-root, .syncular-ui-root) .flow-arrow {
141
145
  animation: flowPulse 2s ease-in-out infinite;
142
146
  }
143
147
 
@@ -152,7 +156,7 @@ body {
152
156
  }
153
157
  }
154
158
 
155
- .dot-grid {
159
+ :where(.syncular-console-root, .syncular-ui-root) .dot-grid {
156
160
  background-image: radial-gradient(
157
161
  circle at 1px 1px,
158
162
  #1a1a1a 1px,
@@ -161,7 +165,7 @@ body {
161
165
  background-size: 24px 24px;
162
166
  }
163
167
 
164
- .scan-line {
168
+ :where(.syncular-console-root, .syncular-ui-root) .scan-line {
165
169
  position: absolute;
166
170
  left: 0;
167
171
  right: 0;
@@ -1,47 +1,110 @@
1
- @theme {
1
+ @theme inline {
2
+ --color-background: var(--syncular-color-background);
3
+ --color-surface: var(--syncular-color-surface);
4
+ --color-panel: var(--syncular-color-panel);
5
+ --color-panel-alt: var(--syncular-color-panel-alt);
6
+ --color-border: var(--syncular-color-border);
7
+ --color-border-bright: var(--syncular-color-border-bright);
8
+
9
+ --color-healthy: var(--syncular-color-healthy);
10
+ --color-syncing: var(--syncular-color-syncing);
11
+ --color-offline: var(--syncular-color-offline);
12
+
13
+ --color-flow: var(--syncular-color-flow);
14
+ --color-relay: var(--syncular-color-relay);
15
+ --color-encrypt: var(--syncular-color-encrypt);
16
+
17
+ --color-foreground: var(--syncular-color-foreground);
18
+ --color-foreground-muted: var(--syncular-color-foreground-muted);
19
+
20
+ --color-primary: var(--syncular-color-primary);
21
+ --color-destructive: var(--syncular-color-destructive);
22
+ --color-secondary: var(--syncular-color-secondary);
23
+
24
+ --font-display: var(--syncular-font-display);
25
+ --font-mono: var(--syncular-font-mono);
26
+
27
+ --radius-sm: var(--syncular-radius-sm);
28
+ --radius-md: var(--syncular-radius-md);
29
+ --radius-lg: var(--syncular-radius-lg);
30
+ --radius-xl: var(--syncular-radius-xl);
31
+ }
32
+
33
+ :where(.syncular-console-root, .syncular-ui-root) {
2
34
  /* ── Surface ── */
3
- --color-background: #0c0c0c;
4
- --color-surface: #0c0c0c;
5
- --color-panel: #111111;
6
- --color-panel-alt: #0e0e0e;
7
- --color-border: #1e1e1e;
8
- --color-border-bright: #2a2a2a;
35
+ --syncular-color-background: #0c0c0c;
36
+ --syncular-color-surface: #0c0c0c;
37
+ --syncular-color-panel: #111111;
38
+ --syncular-color-panel-alt: #0e0e0e;
39
+ --syncular-color-border: #1e1e1e;
40
+ --syncular-color-border-bright: #2a2a2a;
9
41
 
10
42
  /* ── Status ── */
11
- --color-healthy: #22c55e;
12
- --color-syncing: #f59e0b;
13
- --color-offline: #ef4444;
43
+ --syncular-color-healthy: #22c55e;
44
+ --syncular-color-syncing: #f59e0b;
45
+ --syncular-color-offline: #ef4444;
14
46
 
15
47
  /* ── Flow ── */
16
- --color-flow: #3b82f6;
17
- --color-relay: #8b5cf6;
18
- --color-encrypt: #f472b6;
48
+ --syncular-color-flow: #3b82f6;
49
+ --syncular-color-relay: #8b5cf6;
50
+ --syncular-color-encrypt: #f472b6;
19
51
 
20
52
  /* ── Text ── */
21
- --color-foreground: #e5e5e5;
22
- --color-foreground-muted: #737373;
53
+ --syncular-color-foreground: #e5e5e5;
54
+ --syncular-color-foreground-muted: #737373;
23
55
 
24
56
  /* ── Semantic ── */
25
- --color-primary: #22c55e;
26
- --color-destructive: #ef4444;
27
- --color-secondary: #1e1e1e;
57
+ --syncular-color-primary: #22c55e;
58
+ --syncular-color-destructive: #ef4444;
59
+ --syncular-color-secondary: #1e1e1e;
28
60
 
29
61
  /* ── Fonts ── */
30
- --font-display: 'Inter Tight', system-ui, sans-serif;
31
- --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco,
32
- Consolas, 'Liberation Mono', 'Courier New', monospace;
62
+ --syncular-font-display: 'Inter Tight', system-ui, sans-serif;
63
+ --syncular-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo,
64
+ Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
33
65
 
34
66
  /* ── Radii ── */
35
- --radius-sm: 4px;
36
- --radius-md: 6px;
37
- --radius-lg: 8px;
38
- --radius-xl: 10px;
67
+ --syncular-radius-sm: 4px;
68
+ --syncular-radius-md: 6px;
69
+ --syncular-radius-lg: 8px;
70
+ --syncular-radius-xl: 10px;
39
71
 
40
72
  /* ── Glows ── */
41
- --sync-glow-healthy: 0 0 6px #22c55e;
42
- --sync-glow-syncing: 0 0 6px #f59e0b;
43
- --sync-glow-offline: 0 0 6px #ef4444;
44
- --sync-glow-flow: 0 0 6px #3b82f6;
45
- --sync-glow-relay: 0 0 6px #8b5cf6;
46
- --sync-glow-encrypt: 0 0 6px #f472b6;
73
+ --syncular-glow-healthy: 0 0 6px #22c55e;
74
+ --syncular-glow-syncing: 0 0 6px #f59e0b;
75
+ --syncular-glow-offline: 0 0 6px #ef4444;
76
+ --syncular-glow-flow: 0 0 6px #3b82f6;
77
+ --syncular-glow-relay: 0 0 6px #8b5cf6;
78
+ --syncular-glow-encrypt: 0 0 6px #f472b6;
79
+
80
+ /* Backward token aliases used by chart primitives */
81
+ --color-background: var(--syncular-color-background);
82
+ --color-surface: var(--syncular-color-surface);
83
+ --color-panel: var(--syncular-color-panel);
84
+ --color-panel-alt: var(--syncular-color-panel-alt);
85
+ --color-border: var(--syncular-color-border);
86
+ --color-border-bright: var(--syncular-color-border-bright);
87
+ --color-healthy: var(--syncular-color-healthy);
88
+ --color-syncing: var(--syncular-color-syncing);
89
+ --color-offline: var(--syncular-color-offline);
90
+ --color-flow: var(--syncular-color-flow);
91
+ --color-relay: var(--syncular-color-relay);
92
+ --color-encrypt: var(--syncular-color-encrypt);
93
+ --color-foreground: var(--syncular-color-foreground);
94
+ --color-foreground-muted: var(--syncular-color-foreground-muted);
95
+ --color-primary: var(--syncular-color-primary);
96
+ --color-destructive: var(--syncular-color-destructive);
97
+ --color-secondary: var(--syncular-color-secondary);
98
+ --font-display: var(--syncular-font-display);
99
+ --font-mono: var(--syncular-font-mono);
100
+ --radius-sm: var(--syncular-radius-sm);
101
+ --radius-md: var(--syncular-radius-md);
102
+ --radius-lg: var(--syncular-radius-lg);
103
+ --radius-xl: var(--syncular-radius-xl);
104
+ --sync-glow-healthy: var(--syncular-glow-healthy);
105
+ --sync-glow-syncing: var(--syncular-glow-syncing);
106
+ --sync-glow-offline: var(--syncular-glow-offline);
107
+ --sync-glow-flow: var(--syncular-glow-flow);
108
+ --sync-glow-relay: var(--syncular-glow-relay);
109
+ --sync-glow-encrypt: var(--syncular-glow-encrypt);
47
110
  }