@almadar/ui 6.53.1 → 6.54.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.
Files changed (49) hide show
  1. package/dist/Typography-CFI7JUVE.js +5 -0
  2. package/dist/{UISlotRenderer-P7A4SZSK.js → UISlotRenderer-QUEG6WFM.js} +7 -7
  3. package/dist/avl/index.cjs +709 -970
  4. package/dist/avl/index.js +24 -20
  5. package/dist/{avl-3d-context-MAt_NuU9.d.ts → avl-3d-context-BpBKZIbc.d.ts} +1 -0
  6. package/dist/{chunk-DQTV6QVS.js → chunk-4HC5HRHB.js} +53 -2
  7. package/dist/{chunk-HB4C27KU.js → chunk-4UP6BZ4R.js} +1 -1
  8. package/dist/{chunk-UOTYAPV5.js → chunk-FJDS4SVD.js} +3 -3
  9. package/dist/{chunk-QVXLKFUQ.js → chunk-MCKFWPT2.js} +1 -1
  10. package/dist/{chunk-7KSLPY56.js → chunk-N2V4LHFQ.js} +1 -0
  11. package/dist/{chunk-HUG25TT3.js → chunk-U2FGMHQP.js} +448 -885
  12. package/dist/{chunk-53VTY5CC.js → chunk-U3CGKPOK.js} +253 -92
  13. package/dist/{chunk-7LM6I3NA.js → chunk-Z5IYJU44.js} +1 -0
  14. package/dist/{chunk-FUQASYEW.js → chunk-Z7JWXIRE.js} +2 -2
  15. package/dist/components/index.cjs +449 -879
  16. package/dist/components/index.d.ts +5 -1
  17. package/dist/components/index.js +15 -16
  18. package/dist/context/index.cjs +2 -0
  19. package/dist/context/index.js +3 -1
  20. package/dist/hooks/index.cjs +6 -0
  21. package/dist/hooks/index.d.ts +10 -1
  22. package/dist/hooks/index.js +3 -4
  23. package/dist/lib/drawable/three/index.cjs +2 -0
  24. package/dist/lib/drawable/three/index.d.ts +2 -2
  25. package/dist/lib/drawable/three/index.js +6 -6
  26. package/dist/lib/index.cjs +1 -0
  27. package/dist/lib/index.js +3 -3
  28. package/dist/locales/index.cjs +3 -0
  29. package/dist/locales/index.js +3 -1
  30. package/dist/providers/index.cjs +444 -879
  31. package/dist/providers/index.d.ts +1 -1
  32. package/dist/providers/index.js +8 -8
  33. package/dist/runtime/index.cjs +3992 -4237
  34. package/dist/runtime/index.d.ts +22 -4
  35. package/dist/runtime/index.js +15 -12
  36. package/dist/ssr/index.cjs +2 -1
  37. package/dist/ssr/index.js +2 -1
  38. package/locales/ar.json +1 -0
  39. package/locales/en.json +1 -0
  40. package/locales/sl.json +1 -0
  41. package/package.json +7 -6
  42. package/scripts/audit-tailwind-safelist.ts +21 -1
  43. package/tailwind-preset.cjs +5 -6
  44. package/themes/_fonts.css +6 -4
  45. package/themes/_presets.css +2 -0
  46. package/themes/almadar-heritage.css +373 -0
  47. package/themes/orb.css +373 -0
  48. package/dist/Typography-7QEWUTW3.js +0 -5
  49. package/dist/chunk-E37BYSXY.js +0 -51
@@ -1,6 +1,6 @@
1
- import { EventPayload, OrbitalDefinition, ServiceParams, TraitConfig, UserContext, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, EntityData } from '@almadar/core';
1
+ import { EventPayload, OrbitalDefinition, ServiceParams, TraitConfig, UserContext, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, EntityData, MessageCatalogs } from '@almadar/core';
2
2
  export { ResolvedEntity, ResolvedIR, ResolvedPage, ResolvedTrait, ResolvedTraitBinding } from '@almadar/core';
3
- import { TraitState, EventTransport, PersistenceAdapter, AccessTokenProvider } from '@almadar/runtime';
3
+ import { TraitState, EventTransport, PersistenceAdapter, AccessTokenProvider, SchemaLoader } from '@almadar/runtime';
4
4
  export { AccessTokenProvider, ClientEventBus, CreateClientEffectHandlersOptions, SlotSetter, createClientEffectHandlers } from '@almadar/runtime';
5
5
  import { E as EntityBindingSource, A as AwaitingSkeletonSource, S as ServerBridgeTransport } from '../AwaitingSkeletonContext-Bh399p1x.js';
6
6
  export { a as EntitySchemaContextValue, b as EntitySchemaProvider, c as EntitySchemaProviderProps, d as ServerBridgeContextValue, e as ServerBridgeProvider, T as TraitContext, f as TraitContextValue, g as TraitInstance, h as TraitProvider, i as TraitProviderProps, u as useEntitySchema, j as useEntitySchemaOptional, k as useServerBridge, l as useTrait, m as useTraitContext } from '../AwaitingSkeletonContext-Bh399p1x.js';
@@ -44,6 +44,8 @@ interface UseTraitStateMachineOptions {
44
44
  /** Hold every dispatch until the transport's topology is known. */
45
45
  awaitTopology?: boolean;
46
46
  persistence?: PersistenceAdapter;
47
+ /** The browser store for `[persistent: x, local]` entities (see `useCircuitKernel`). */
48
+ browserStore?: PersistenceAdapter;
47
49
  callService?: (service: string, action: string, params?: ServiceParams) => Promise<EventPayload>;
48
50
  traitConfigsByName?: Record<string, TraitConfig>;
49
51
  embeddedTraits?: ReadonlySet<string>;
@@ -232,6 +234,18 @@ interface OrbPreviewProps {
232
234
  * picker). Omitted → each page renders in its own orbital's theme.
233
235
  */
234
236
  themeOverride?: string;
237
+ /**
238
+ * Loads the behavior behind a `lazyPages` entry (`uses lazy`) when its page
239
+ * is opened. Without it, opening a lazy page shows a load error.
240
+ */
241
+ lazyLoader?: SchemaLoader;
242
+ /** Where `schema` was loaded from — a lazy page's `orbRef` resolves against it. */
243
+ schemaPath?: string;
244
+ /**
245
+ * Called with a path that matches none of this schema's pages — a lazily
246
+ * loaded behavior hands links back to the schema that imported it.
247
+ */
248
+ onUnmatchedNavigate?: (path: string) => void;
235
249
  }
236
250
  /**
237
251
  * Renders a live preview of an Orbital schema.
@@ -246,7 +260,7 @@ interface OrbPreviewProps {
246
260
  * <OrbPreview schema={schema} serverUrl="/api/orbitals" />
247
261
  * ```
248
262
  */
249
- declare function OrbPreview({ schema, mockData, autoMock, height, className, serverUrl, transport, getAccessToken, initialPagePath, isolated, fit, onPageChange, user, localFallbackTimeoutMs, themeOverride, }: OrbPreviewProps): React__default.ReactElement;
263
+ declare function OrbPreview({ schema, mockData, autoMock, height, className, serverUrl, transport, getAccessToken, initialPagePath, isolated, fit, onPageChange, user, localFallbackTimeoutMs, themeOverride, lazyLoader, schemaPath, onUnmatchedNavigate, }: OrbPreviewProps): React__default.ReactElement;
250
264
  declare namespace OrbPreview {
251
265
  var displayName: string;
252
266
  }
@@ -290,8 +304,12 @@ interface BrowserPlaygroundProps {
290
304
  onPageChange?: (path: string) => void;
291
305
  /** Who is viewing (`@user`). Default: the app's first seeded persona. */
292
306
  viewer?: UserContext;
307
+ /** The program's message catalogs (`orb resolve`'s `<stem>.<locale>.json`), for a schema that declares `locales`. */
308
+ messages?: MessageCatalogs;
309
+ /** The viewer's locale. Default: the schema's first declared locale. */
310
+ locale?: string;
293
311
  }
294
- declare function BrowserPlayground({ schema, mode, initialPagePath, height, className, paused, fit, onPageChange, viewer, }: BrowserPlaygroundProps): React__default.ReactElement;
312
+ declare function BrowserPlayground({ schema, mode, initialPagePath, height, className, paused, fit, onPageChange, viewer, messages, locale, }: BrowserPlaygroundProps): React__default.ReactElement;
295
313
 
296
314
  /**
297
315
  * OrbitalPluginHost — runs an ordinary behavior headless against the
@@ -1,20 +1,20 @@
1
- export { BrowserPlayground, OrbPreview, adjustSchemaForMockData, buildMockData, clearSchemaCache, prepareSchemaForPreview, useResolvedSchema, useTraitStateMachine } from '../chunk-53VTY5CC.js';
1
+ export { BrowserPlayground, OrbPreview, adjustSchemaForMockData, buildMockData, clearSchemaCache, prepareSchemaForPreview, useResolvedSchema, useTraitStateMachine } from '../chunk-U3CGKPOK.js';
2
2
  export { assertUniqueSlotsPerHost } from '../chunk-O2EIWXWE.js';
3
- import '../chunk-DQTV6QVS.js';
3
+ import '../chunk-4HC5HRHB.js';
4
4
  import '../chunk-VHTJRS2N.js';
5
- export { wrapCallbackForEvent } from '../chunk-HUG25TT3.js';
6
- import '../chunk-PQKU62LK.js';
7
- import '../chunk-7LM6I3NA.js';
8
- import '../chunk-HB4C27KU.js';
5
+ export { wrapCallbackForEvent } from '../chunk-U2FGMHQP.js';
6
+ import '../chunk-Z5IYJU44.js';
7
+ import '../chunk-4UP6BZ4R.js';
9
8
  import '../chunk-JRW33U35.js';
10
9
  import '../chunk-XJTHMW4G.js';
11
10
  import { useEventBus } from '../chunk-6EV3OEBQ.js';
12
- import '../chunk-PEST66PN.js';
13
11
  export { PERF_NAMESPACE, clearPerf, perfEnd, perfStart, perfTime, profilerOnRender, usePerfBuffer } from '../chunk-KQXXO42S.js';
14
12
  import '../chunk-O7OLVVBR.js';
15
13
  import '../chunk-64WACXM7.js';
16
- import '../chunk-QVXLKFUQ.js';
17
- import '../chunk-7KSLPY56.js';
14
+ import '../chunk-MCKFWPT2.js';
15
+ import '../chunk-N2V4LHFQ.js';
16
+ import '../chunk-PQKU62LK.js';
17
+ import '../chunk-PEST66PN.js';
18
18
  import '../chunk-QPXIAUJD.js';
19
19
  export { EntitySchemaProvider, ServerBridgeProvider, TraitContext, TraitProvider, useEntitySchema, useEntitySchemaOptional, useServerBridge, useTrait, useTraitContext } from '@almadar/ui/providers';
20
20
  export { createClientEffectHandlers } from '@almadar/runtime';
@@ -22,6 +22,7 @@ import { createContext, useMemo, useState, useRef, useCallback, useContext, useE
22
22
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
23
23
  import { UI_SLOTS } from '@almadar/core';
24
24
  import { createLogger } from '@almadar/logger';
25
+ import { useTranslate } from '@almadar/ui/hooks';
25
26
  import { useUISlots } from '@almadar/ui/context';
26
27
  import { jsxs, jsx } from 'react/jsx-runtime';
27
28
 
@@ -145,6 +146,7 @@ function PluginRuntimeMount({
145
146
  onError
146
147
  }) {
147
148
  const bus = useEventBus();
149
+ const { locale } = useTranslate();
148
150
  const slots = useUISlots();
149
151
  const slotsRef = useRef(slots);
150
152
  slotsRef.current = slots;
@@ -271,10 +273,11 @@ function PluginRuntimeMount({
271
273
  response = await mockRuntime.processOrbitalEvent(row.orbital, {
272
274
  event: row.trigger,
273
275
  payload,
274
- targetTrait: row.trait
276
+ targetTrait: row.trait,
277
+ locale
275
278
  });
276
279
  } else if (mode === "server" && transport) {
277
- response = await transport.send(row.orbital, { event: row.trigger, payload });
280
+ response = await transport.send(row.orbital, { event: row.trigger, payload, locale });
278
281
  } else {
279
282
  return;
280
283
  }
@@ -298,7 +301,7 @@ function PluginRuntimeMount({
298
301
  }
299
302
  onDispatched(plugin.id, row.trigger, states);
300
303
  },
301
- [registrationReady, mockRuntime, mode, transport, plugin, bus, ownOrbitals, inboundBusEvents, onError, onTransition, onDispatched]
304
+ [registrationReady, mockRuntime, mode, transport, locale, plugin, bus, ownOrbitals, inboundBusEvents, onError, onTransition, onDispatched]
302
305
  );
303
306
  useEffect(() => {
304
307
  const unsubs = plugin.inbound.map(
@@ -3144,6 +3144,7 @@ var en_default = {
3144
3144
  "status.draft": "Draft",
3145
3145
  "status.archived": "Archived",
3146
3146
  "error.generic": "Something went wrong",
3147
+ "error.traitMountFailed": "{{trait}} failed to start",
3147
3148
  "error.retry": "Try again",
3148
3149
  "error.notFound": "Not found",
3149
3150
  "error.loadFailed": "Failed to load: {{message}}",
@@ -5193,7 +5194,7 @@ var Button = React17__namespace.default.forwardRef(
5193
5194
  const testId = dataTestId ?? (action ? `action-${action}` : void 0);
5194
5195
  const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5195
5196
  busy && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "almadar-busy-indicator absolute inset-0 flex items-center justify-center", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Loader2, { className: "h-icon-default w-icon-default animate-spin" }) }),
5196
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex items-center justify-center gap-2", busy && "almadar-busy-content"), children: [
5197
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex flex-1 min-w-0 items-center [justify-content:inherit] gap-2", busy && "almadar-busy-content"), children: [
5197
5198
  resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
5198
5199
  (Array.isArray(children) ? children.length > 0 : Boolean(children)) ? children : label ? /* @__PURE__ */ jsxRuntime.jsx("span", { ...{ [INLINE_TEXT_ATTR]: "label" }, children: label }) : label,
5199
5200
  resolvedRightIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: resolvedRightIcon })
package/dist/ssr/index.js CHANGED
@@ -3123,6 +3123,7 @@ var en_default = {
3123
3123
  "status.draft": "Draft",
3124
3124
  "status.archived": "Archived",
3125
3125
  "error.generic": "Something went wrong",
3126
+ "error.traitMountFailed": "{{trait}} failed to start",
3126
3127
  "error.retry": "Try again",
3127
3128
  "error.notFound": "Not found",
3128
3129
  "error.loadFailed": "Failed to load: {{message}}",
@@ -5172,7 +5173,7 @@ var Button = React17__default.forwardRef(
5172
5173
  const testId = dataTestId ?? (action ? `action-${action}` : void 0);
5173
5174
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
5174
5175
  busy && /* @__PURE__ */ jsx("span", { className: "almadar-busy-indicator absolute inset-0 flex items-center justify-center", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Loader2, { className: "h-icon-default w-icon-default animate-spin" }) }),
5175
- /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-center justify-center gap-2", busy && "almadar-busy-content"), children: [
5176
+ /* @__PURE__ */ jsxs("span", { className: cn("inline-flex flex-1 min-w-0 items-center [justify-content:inherit] gap-2", busy && "almadar-busy-content"), children: [
5176
5177
  resolvedLeftIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
5177
5178
  (Array.isArray(children) ? children.length > 0 : Boolean(children)) ? children : label ? /* @__PURE__ */ jsx("span", { ...{ [INLINE_TEXT_ATTR]: "label" }, children: label }) : label,
5178
5179
  resolvedRightIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedRightIcon })
package/locales/ar.json CHANGED
@@ -57,6 +57,7 @@
57
57
  "status.draft": "مسودة",
58
58
  "status.archived": "مؤرشف",
59
59
  "error.generic": "حدث خطأ ما",
60
+ "error.traitMountFailed": "تعذّر بدء {{trait}}",
60
61
  "error.retry": "حاول مرة أخرى",
61
62
  "error.notFound": "غير موجود",
62
63
  "error.loadFailed": "فشل التحميل: {{message}}",
package/locales/en.json CHANGED
@@ -58,6 +58,7 @@
58
58
  "status.draft": "Draft",
59
59
  "status.archived": "Archived",
60
60
  "error.generic": "Something went wrong",
61
+ "error.traitMountFailed": "{{trait}} failed to start",
61
62
  "error.retry": "Try again",
62
63
  "error.notFound": "Not found",
63
64
  "error.loadFailed": "Failed to load: {{message}}",
package/locales/sl.json CHANGED
@@ -57,6 +57,7 @@
57
57
  "status.draft": "Osnutek",
58
58
  "status.archived": "Arhivirano",
59
59
  "error.generic": "Nekaj je šlo narobe",
60
+ "error.traitMountFailed": "{{trait}} se ni zagnal",
60
61
  "error.retry": "Poskusite znova",
61
62
  "error.notFound": "Ni najdeno",
62
63
  "error.loadFailed": "Nalaganje ni uspelo: {{message}}",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "6.53.1",
3
+ "version": "6.54.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -126,11 +126,11 @@
126
126
  "access": "public"
127
127
  },
128
128
  "dependencies": {
129
- "@almadar/core": "^10.115.0",
130
- "@almadar/evaluator": "^2.53.0",
129
+ "@almadar/core": "^10.116.0",
130
+ "@almadar/evaluator": "^2.54.0",
131
131
  "@almadar/logger": "^1.15.0",
132
- "@almadar/runtime": "^6.101.0",
133
- "@almadar/std": "^16.239.0",
132
+ "@almadar/runtime": "^6.102.0",
133
+ "@almadar/std": "^16.241.0",
134
134
  "@almadar/syntax": "^1.19.0",
135
135
  "@dnd-kit/core": "^6.3.1",
136
136
  "@dnd-kit/sortable": "^10.0.0",
@@ -191,7 +191,7 @@
191
191
  }
192
192
  },
193
193
  "devDependencies": {
194
- "@almadar-io/behaviors": "^0.16.186",
194
+ "@almadar-io/behaviors": "^0.16.187",
195
195
  "@almadar/eslint-plugin": "^2.21.0",
196
196
  "@react-three/drei": "^10.7.7",
197
197
  "@react-three/fiber": "^9.6.0",
@@ -217,6 +217,7 @@
217
217
  "babel-plugin-react-compiler": "19.0.0-beta-af1b7da-20250417",
218
218
  "eslint": "10.0.0",
219
219
  "eslint-plugin-react-compiler": "19.1.0-rc.2",
220
+ "fake-indexeddb": "6.2.5",
220
221
  "jsdom": "^24.0.0",
221
222
  "katex": "^0.16.0",
222
223
  "postcss": "^8.4.35",
@@ -26,8 +26,15 @@
26
26
  */
27
27
 
28
28
  import { readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
29
+ import { createRequire } from 'module';
29
30
  import { join, relative } from 'path';
30
31
 
32
+ const requireCjs = createRequire(import.meta.url);
33
+ const { compileTailwindClasses } = requireCjs('../tailwind-compile.cjs') as {
34
+ compileTailwindClasses: (classes: string[]) => Promise<string>;
35
+ };
36
+ const { safelist: loadedSafelist } = requireCjs('../tailwind-preset.cjs') as { safelist: Array<string | { pattern: RegExp }> };
37
+
31
38
  const ROOT = join(import.meta.dirname, '..');
32
39
  const PRESET_PATH = join(ROOT, 'tailwind-preset.cjs');
33
40
  const SCAN_DIRS = ['components', 'runtime', 'renderer', 'context', 'providers', 'hooks'];
@@ -38,7 +45,8 @@ const SCAN_DIRS = ['components', 'runtime', 'renderer', 'context', 'providers',
38
45
 
39
46
  // Matches arbitrary value classes: bg-[var(...)], min-h-[200px], w-[300px], etc.
40
47
  // Requires a hyphen before the bracket to avoid matching JS array access like arr[0]
41
- const ARBITRARY_RE = /(?:^|\s|["'`])([a-z][a-z0-9]*(?::[a-z][a-z0-9-]*)+-\[[^\]]+\]|[a-z][a-z0-9]*-[a-z0-9-]*-\[[^\]]+\]|[a-z][a-z0-9]*-\[[^\]]+\])/g;
48
+ // A bracket followed by `:` is a variant (`data-[active=true]:`), not a class.
49
+ const ARBITRARY_RE = /(?:^|\s|["'`])([a-z][a-z0-9]*(?::[a-z][a-z0-9-]*)+-\[[^\]]+\]|[a-z][a-z0-9]*-[a-z0-9-]*-\[[^\]]+\]|[a-z][a-z0-9]*-\[[^\]]+\])(?!:)/g;
42
50
 
43
51
  // Matches opacity modifiers on semantic colors: bg-primary/10, text-foreground/60
44
52
  const OPACITY_RE = /(?:^|\s|["'`])((?:bg|text|border|ring|from|to|via|hover:bg|hover:text|hover:border|dark:bg|dark:hover:bg|group-hover:bg|group-hover:text|peer-focus:ring|focus:ring)-(?:primary|secondary|muted|accent|foreground|card|surface|background|border|error|success|warning|info|ring|input|muted-foreground|card-foreground|primary-foreground|secondary-foreground|error-foreground|success-foreground|warning-foreground|info-foreground)\/\d+)/g;
@@ -184,6 +192,18 @@ const skipped = missing.filter(m => !needsSafelist(m.cls));
184
192
  missing.length = 0;
185
193
  missing.push(...filtered);
186
194
 
195
+ // A class Tailwind generates no CSS for paints nothing whether or not it is safelisted
196
+ // (`justify-[inherit]`: Tailwind 3 has no arbitrary justify-content) — fail on it.
197
+ const dead: Array<{ cls: string; files: string[] }> = [];
198
+ for (const cls of new Set([...loadedSafelist.filter((e): e is string => typeof e === 'string'), ...missing.map((m) => m.cls)])) {
199
+ if ((await compileTailwindClasses([cls])) === '') dead.push({ cls, files: Array.from(allCandidates.get(cls) ?? []) });
200
+ }
201
+ if (dead.length > 0) {
202
+ console.log('Classes that generate no CSS (fix the class at its source, or drop the safelist entry):');
203
+ for (const { cls, files } of dead) console.log(` ${cls}${files.length > 0 ? ` <- ${files.join(', ')}` : ' (safelist only)'}`);
204
+ process.exit(1);
205
+ }
206
+
187
207
  // Report
188
208
  console.log(`Current safelist: ${currentSafelist.size} entries`);
189
209
  console.log(`Already safelisted: ${alreadySafe.length}`);
@@ -73,10 +73,8 @@ module.exports = {
73
73
  'hover:border-[var(--color-border-hover)]',
74
74
  'hover:border-l-[var(--color-muted)]',
75
75
  // Gradient partials with opacity
76
- 'from-[var(--color-primary)]/5',
77
- 'to-[var(--color-secondary)]/5',
78
76
  // Opacity variants on semantic colors (used in components)
79
- 'bg-primary/10', 'bg-primary/8', 'bg-accent/10',
77
+ 'bg-primary/10', 'bg-accent/10',
80
78
  'bg-muted/20', 'bg-muted/30', 'bg-muted/50', 'bg-muted/60',
81
79
  'bg-surface/60', 'bg-surface/80',
82
80
  'bg-background/10', 'bg-background/80',
@@ -150,7 +148,6 @@ module.exports = {
150
148
  'bg-muted/60',
151
149
  'bg-primary/10',
152
150
  'bg-primary/20',
153
- 'bg-primary/8',
154
151
  'bg-success/10',
155
152
  'bg-success/20',
156
153
  'bg-surface/60',
@@ -177,7 +174,6 @@ module.exports = {
177
174
  'border-x-[length:var(--border-width)]',
178
175
  'dark:bg-foreground/70',
179
176
  'dark:hover:bg-error/20',
180
- 'data-[active=true]',
181
177
  'duration-[var(--transition-fast)]',
182
178
  'duration-[var(--transition-normal)]',
183
179
  'focus:ring-[length:var(--focus-ring-width)]',
@@ -332,7 +328,6 @@ module.exports = {
332
328
  'border-warning/60',
333
329
  'border-y-[length:var(--border-width)]',
334
330
  'bottom-[15%]',
335
- 'data-[empty=true]',
336
331
  'focus-visible:ring-[length:var(--focus-ring-width)]',
337
332
  'focus-visible:ring-offset-[length:var(--focus-ring-offset)]',
338
333
  'focus-within:border-[var(--color-primary)]',
@@ -460,6 +455,10 @@ module.exports = {
460
455
  'shadow-[var(--shadow-lg)]',
461
456
  'text-[var(--color-primary-foreground)]',
462
457
  'z-[850]',
458
+
459
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-03)
460
+ '[justify-content:inherit]',
461
+ 'bg-primary/[0.08]',
463
462
  ],
464
463
  theme: {
465
464
  fontFamily: {
package/themes/_fonts.css CHANGED
@@ -4,7 +4,9 @@
4
4
  * Regenerate: node tools/almadar-pattern-sync/dist/index.js themes (or `almadar-sync themes`)
5
5
  */
6
6
 
7
- @import url("https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&family=Anton&family=Archivo:wght@400;500;700;800&family=Archivo+Black&family=Baloo+2:wght@500;600;700;800&family=Bangers&family=Bungee&family=Cairo:wght@300;400;500;600;700&family=Cinzel:wght@400;600;700;900&family=Cinzel+Decorative:wght@400;700&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,700;1,500;1,700&family=Crimson+Pro:wght@500;600;700&family=DM+Sans:wght@400;500;700&family=DM+Serif+Display&family=DotGothic16&family=EB+Garamond:wght@400;500;600;700&family=Exo+2:wght@300;400;500;600;700&family=Fraunces:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&family=Fredoka:wght@400;500;600;700&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&family=Hanken+Grotesk:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap");
8
- @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:wght@400;500;600;700&family=IM+Fell+English&family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@400;500;700;800&family=JetBrains+Mono:wght@400;500;700&family=Josefin+Sans:wght@400;500;700&family=Jost:wght@300;400;500;700;800&family=Kalam:wght@300;400;700&family=Karla:wght@400;500;700&family=Libre+Baskerville:wght@400;700&family=Lilita+One&family=Limelight&family=Lora:wght@400;500;600;700&family=M+PLUS+Rounded+1c:wght@400;500;700;800&family=Ma+Shan+Zheng&family=Manrope:wght@400;500;600;700;800&family=MedievalSharp&family=Newsreader:wght@400;500;600&family=Noto+Naskh+Arabic:wght@400;500;700&family=Noto+Sans:wght@400;500;700;800&family=Noto+Sans+Arabic:wght@400;500;600;700&family=Noto+Sans+Mono:wght@400;500&family=Noto+Serif+JP:wght@400;500;700&family=Noto+Serif+SC:wght@400;500;700&display=swap");
9
- @import url("https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800&family=Nunito+Sans:wght@400;600;700&family=Old+Standard+TT&family=Orbitron:wght@500;700;900&family=Oswald:wght@500;700&family=Outfit:wght@300;400;500;600&family=Patrick+Hand&family=Pixelify+Sans:wght@400;500;700&family=Playfair+Display:ital,wght@0,400;0,500;0,700;0,900;1,500;1,700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=Poiret+One&family=Poppins:wght@500;600;700&family=Press+Start+2P&family=Quicksand:wght@500;600;700&family=Rajdhani:wght@400;500;600;700&family=Reem+Kufi:wght@400;500;600;700&family=Roboto:wght@400;500;700&family=Roboto+Condensed:wght@400;500;700&family=Roboto+Flex:wght@400;500;600;700&family=Roboto+Mono:wght@400;500&family=Rubik:wght@400;500;700&family=Rubik+Mono+One&family=Russo+One&family=Schibsted+Grotesk:wght@400;500;600;700&display=swap");
10
- @import url("https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Shippori+Mincho:wght@400;500&family=Shrikhand&family=Silkscreen:wght@400;700&family=Sora:wght@400;600;700&family=Source+Serif+4:wght@400;600;700&family=Space+Mono:wght@400;700&family=Special+Elite&family=Tilt+Neon&family=UnifrakturCook:wght@700&family=VT323&family=Work+Sans:wght@400;500;600;700&family=Zen+Antique&family=Zen+Kaku+Gothic+New:wght@300;400;500;700&display=swap");
7
+ @import url("https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&family=Anton&family=Archivo:wght@400;500;700;800&family=Archivo+Black&family=Baloo+2:wght@500;600;700;800&family=Bangers&family=Bungee&family=Cairo:wght@300;400;500;600;700&family=Cinzel:wght@400;600;700;900&family=Cinzel+Decorative:wght@400;700&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,700;1,500;1,700&family=Crimson+Pro:wght@500;600;700&family=DM+Sans:wght@400;500;700&family=DM+Serif+Display&family=DotGothic16&family=EB+Garamond:wght@400;500;600;700&family=Exo+2:wght@300;400;500;600;700&family=Fraunces:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&family=Fredoka:wght@400;500;600;700&family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&family=Hanken+Grotesk:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap");
8
+ @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&family=IBM+Plex+Sans+Condensed:wght@400;500;600;700&family=IM+Fell+English&family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@400;500;700;800&family=JetBrains+Mono:wght@400;500;700&family=Josefin+Sans:wght@400;500;700&family=Jost:wght@300;400;500;700;800&family=Kalam:wght@300;400;700&family=Karla:wght@400;500;700&family=Libre+Baskerville:wght@400;700&family=Lilita+One&family=Limelight&family=Lora:wght@400;500;600;700&family=M+PLUS+Rounded+1c:wght@400;500;700;800&family=Ma+Shan+Zheng&family=Manrope:wght@400;500;600;700;800&family=MedievalSharp&family=Newsreader:wght@400;500;600&family=Noto+Naskh+Arabic:wght@400;500;700&family=Noto+Sans:wght@400;500;700;800&family=Noto+Sans+Arabic:wght@400;500;600;700&family=Noto+Sans+Mono:wght@400;500&family=Noto+Serif+JP:wght@400;500;700&display=swap");
9
+ @import url("https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;700&family=Nunito:wght@400;500;600;700;800&family=Nunito+Sans:wght@400;600;700&family=Old+Standard+TT&family=Orbitron:wght@500;700;900&family=Oswald:wght@500;700&family=Outfit:wght@300;400;500;600&family=Patrick+Hand&family=Pixelify+Sans:wght@400;500;700&family=Playfair+Display:ital,wght@0,400;0,500;0,700;0,900;1,500;1,700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Poiret+One&family=Poppins:wght@500;600;700&family=Press+Start+2P&family=Quicksand:wght@500;600;700&family=Rajdhani:wght@400;500;600;700&family=Reem+Kufi:wght@400;500;600;700&family=Roboto:wght@400;500;700&family=Roboto+Condensed:wght@400;500;700&family=Roboto+Flex:wght@400;500;600;700&family=Roboto+Mono:wght@400;500&family=Rubik:wght@400;500;700&family=Rubik+Mono+One&family=Russo+One&display=swap");
10
+ @import url("https://fonts.googleapis.com/css2?family=Schibsted+Grotesk:wght@400;500;600;700&family=Share+Tech+Mono&family=Shippori+Mincho:wght@400;500&family=Shrikhand&family=Silkscreen:wght@400;700&family=Sora:wght@400;600;700&family=Space+Mono:wght@400;700&family=Special+Elite&family=Tilt+Neon&family=UnifrakturCook:wght@700&family=VT323&family=Work+Sans:wght@400;500;600;700&family=Zen+Antique&family=Zen+Kaku+Gothic+New:wght@300;400;500;700&display=swap");
11
+ @import url("https://fonts.googleapis.com/css2?family=Source+Serif+4:wght@400;600;700&display=swap");
12
+ @import url("https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz,wght@8..60,500;8..60,600;8..60,700&display=swap");
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  @import "./almadar.css";
8
+ @import "./almadar-heritage.css";
8
9
  @import "./almadar-website.css";
9
10
  @import "./aqua.css";
10
11
  @import "./arabesque.css";
@@ -42,6 +43,7 @@
42
43
  @import "./neumorphic.css";
43
44
  @import "./newsprint.css";
44
45
  @import "./notion-editorial.css";
46
+ @import "./orb.css";
45
47
  @import "./pixel.css";
46
48
  @import "./prism.css";
47
49
  @import "./retro.css";