@tangle-network/brand 1.11.0 → 1.13.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.
@@ -15,11 +15,11 @@ import {
15
15
  /**
16
16
  * The named-theme contract.
17
17
  *
18
- * A named theme re-skins the SURFACE ladder and nothing else — the Tangle accent
19
- * (primary / ring / accent-text) stays put, so a product carries its identity in
20
- * its planes, not by inventing a second brand colour. These assertions live here
21
- * rather than in the consuming app because the palette lives here: an app's job
22
- * is only to opt in.
18
+ * A named theme re-skins the surface ladder and may carry a product accent
19
+ * (primary / ring / accent-text), as Arena, Aubergine and Super do. It never
20
+ * changes what a status or category tone means. Intelligence is surface-only and
21
+ * keeps the Tangle accent. These assertions live here rather than in the
22
+ * consuming app because the palette lives here: an app's job is only to opt in.
23
23
  */
24
24
  const themes = readFileSync(
25
25
  path.resolve(import.meta.dirname, "named-themes.css"),
@@ -284,3 +284,372 @@ describe('named theme: [data-theme="tangle-dark"]', () => {
284
284
  }
285
285
  });
286
286
  });
287
+
288
+ describe("named themes: secondary text tiers are readable text", () => {
289
+ // --text-muted and --text-dim carry hints, subtitles and timestamps. They are
290
+ // still TEXT, so each clears the AA body floor on every plane text renders on
291
+ // (canvas, card, panel, elevated and highest container), and muted stays
292
+ // stronger than dim.
293
+ const scopes = [
294
+ "aubergine",
295
+ "aubergine-light",
296
+ "arena",
297
+ "arena-light",
298
+ "super",
299
+ "super-light",
300
+ "tangle-dark",
301
+ "tangle-light",
302
+ ];
303
+ for (const scope of scopes) {
304
+ it(`[data-theme="${scope}"] holds AA for --text-muted and --text-dim`, () => {
305
+ const css = blocksIn(themes, `[data-theme="${scope}"]`).find((b) =>
306
+ /--text-dim:/.test(b),
307
+ );
308
+ expect(css, `${scope} declares its text ladder`).toBeDefined();
309
+ const resolve = (token: string): ReturnType<typeof hexIn> => {
310
+ const ref = css!.match(new RegExp(`--${token}:\\s*var\\(--([a-z0-9-]+)\\)`));
311
+ return ref ? resolve(ref[1]) : hexIn(css!, token);
312
+ };
313
+ const planes = {
314
+ canvas: resolve("bg-root"),
315
+ card: resolve("bg-card"),
316
+ panel: resolve("depth-2"),
317
+ elevated: resolve("depth-4"),
318
+ highest: resolve("md3-surface-container-highest"),
319
+ };
320
+ const muted = resolve("text-muted");
321
+ const dim = resolve("text-dim");
322
+ for (const [plane, rgb] of Object.entries(planes)) {
323
+ expect(contrastRatio(muted, rgb), `text-muted on ${plane}`).toBeGreaterThanOrEqual(4.5);
324
+ expect(contrastRatio(dim, rgb), `text-dim on ${plane}`).toBeGreaterThanOrEqual(4.5);
325
+ expect(contrastRatio(muted, rgb), `muted outranks dim on ${plane}`).toBeGreaterThan(
326
+ contrastRatio(dim, rgb),
327
+ );
328
+ }
329
+ });
330
+ }
331
+ });
332
+ for (const [name, mode] of [
333
+ ["agents", "dark"],
334
+ ["agents-light", "light"],
335
+ ] as const) {
336
+ describe(`named theme: [data-theme="${name}"]`, () => {
337
+ // The generated block, not the shared named-light ink rule that also lists it.
338
+ const css = blocksIn(themes, `[data-theme="${name}"]`).find((b) => b.includes("--hsl-background:")) ?? "";
339
+
340
+ it("retints surfaces, text and borders only", () => {
341
+ // The accent, status and category tokens stay canonical, so the theme can
342
+ // never change what the brand colour, a state or a category looks like.
343
+ expect(css).not.toMatch(
344
+ /--(hsl-(primary|ring|destructive|success|warning|info)|sidebar-(primary|ring)|md3-(primary|on-primary|error)|btn-|accent-|brand-|surface-|status-|tone-)[a-z0-9-]*:/,
345
+ );
346
+ });
347
+
348
+ it("declares only canonical spine names", () => {
349
+ for (const [, token] of css.matchAll(/--([a-z0-9-]+):/g)) {
350
+ expect(tokens, `--${token} must be a tokens.css token`).toContain(`--${token}:`);
351
+ }
352
+ });
353
+
354
+ it("keeps ink readable on every plane", () => {
355
+ for (const plane of ["hsl-background", "hsl-card", "hsl-popover", "hsl-muted"]) {
356
+ const bg = hslToRgb(hslIn(css, plane));
357
+ expect(
358
+ contrastRatio(hslToRgb(hslIn(css, "hsl-foreground")), bg),
359
+ `foreground on ${plane}`,
360
+ ).toBeGreaterThanOrEqual(7);
361
+ expect(
362
+ contrastRatio(hslToRgb(hslIn(css, "hsl-muted-foreground")), bg),
363
+ `muted foreground on ${plane}`,
364
+ ).toBeGreaterThanOrEqual(4.5);
365
+ }
366
+ });
367
+
368
+ if (mode === "light") {
369
+ it("is a white page whose cards separate by shadow", () => {
370
+ expect(declIn(css, "hsl-background")).toBe("0 0% 100%");
371
+ expect(declIn(css, "hsl-card")).toBe("0 0% 100%");
372
+ expect(declIn(css, "shadow-card")).toMatch(/rgb\(/);
373
+ });
374
+ }
375
+ });
376
+ }
377
+
378
+ describe("data-tone scopes", () => {
379
+ it("re-resolve each category alias on every nested mode boundary", () => {
380
+ for (const name of ["violet", "orange", "teal", "blue", "pink", "brown", "cyan", "lime"]) {
381
+ const rule = tokens.match(new RegExp(`\\[data-tone="${name}"\\],\\n\\[data-tone="${name}"\\] :is\\(([^)]*)\\) \\{([^}]*)\\}`));
382
+ expect(rule, `data-tone="${name}" rule`).not.toBeNull();
383
+ for (const boundary of [".light", ".dark", "[data-theme]", "[data-sandbox-ui]", "[data-sandbox-theme]"]) {
384
+ expect(rule![1], `${name} boundary list`).toContain(boundary);
385
+ }
386
+ for (const role of ["bg", "bg-hover", "bg-selected", "border", "border-selected", "text", "icon"]) {
387
+ expect(rule![2]).toContain(`--tone-${role}: var(--tone-${name}-${role});`);
388
+ }
389
+ }
390
+ });
391
+ });
392
+
393
+ describe("named themes: the base surface follows the retint", () => {
394
+ // `bg-surface` (and `--md3-surface-*`/`--md3-on-surface*`) paint page chrome
395
+ // such as a mobile top bar. A retinted scope that leaves them at the neutral
396
+ // spine renders a grey bar on a purple or green page.
397
+ for (const scope of ["aubergine", "aubergine-light", "arena", "arena-light", "super", "super-light"]) {
398
+ it(`[data-theme="${scope}"] retints the base surface tokens`, () => {
399
+ const css = blocksIn(themes, `[data-theme="${scope}"]`).find((b) => /--text-dim:/.test(b));
400
+ for (const token of [
401
+ "md3-surface",
402
+ "md3-surface-dim",
403
+ "md3-surface-bright",
404
+ "md3-surface-variant",
405
+ "md3-on-surface",
406
+ "md3-on-surface-variant",
407
+ ]) {
408
+ expect(css, `${scope} declares --${token}`).toMatch(new RegExp(`--${token}:`));
409
+ }
410
+ expect(css).toMatch(/--md3-surface:\s*var\(--bg-root\)/);
411
+ });
412
+ }
413
+ });
414
+
415
+ describe('named theme: [data-theme="hospitality"]', () => {
416
+ const rules = themes.replace(/\/\*[\s\S]*?\*\//g, "");
417
+ const light = block('[data-theme="hospitality"]:where(:not(.dark))');
418
+ const dark = block('.dark[data-theme="hospitality"]');
419
+ const props = (css: string) =>
420
+ [...css.matchAll(/(--[\w-]+)\s*:/g)].map((match) => match[1]).sort();
421
+
422
+ it("takes its dark mode from the .dark class, never from a second attribute", () => {
423
+ expect(rules).toMatch(/^\[data-theme="hospitality"\]:where\(:not\(\.dark\)\) \{/m);
424
+ expect(rules).toMatch(/^\.dark\[data-theme="hospitality"\] \{/m);
425
+ expect(rules).not.toContain('[data-theme="hospitality-light"]');
426
+ expect(rules).not.toContain('[data-theme="hospitality-dark"]');
427
+ });
428
+
429
+ it("starts from a complete canonical baseline in either mode, before hydration too", () => {
430
+ // Without the seed, a classless <html data-theme="hospitality"> would keep
431
+ // the dark-default :root syntax, status and color-scheme under light paper.
432
+ const header = (anchor: string) => {
433
+ const end = tokens.indexOf(anchor);
434
+ return tokens.slice(tokens.lastIndexOf("}", end) + 1, tokens.indexOf("{", end));
435
+ };
436
+ expect(header("color-scheme: dark")).toContain('[data-theme="hospitality"],');
437
+ expect(header("color-scheme: light")).toContain('[data-theme="hospitality"]:where(:not(.dark)),');
438
+ });
439
+
440
+ it("lets nothing from the light identity survive into dark", () => {
441
+ // `.dark[data-theme]` outranks `[data-theme]`, but only for what it declares;
442
+ // a property the dark block omits would keep its light value in dark mode.
443
+ expect(props(dark)).toEqual(props(light));
444
+ });
445
+
446
+ it("never redefines what a status or category color means", () => {
447
+ for (const css of [light, dark]) {
448
+ expect(css).not.toMatch(
449
+ /--(hsl-)?(success|warning|destructive|info|error)\b|--surface-(success|warning|danger|info|neutral)-|--status-|--tone-|--run-mix-|--syntax-/,
450
+ );
451
+ }
452
+ });
453
+
454
+ it("keeps the canonical ladder roles: paper cards on a tinted canvas in light, rising planes in dark", () => {
455
+ expect(hslIn(light, "hsl-card")).toEqual({ h: 0, s: 0, l: 100 });
456
+ // As in canonical light, the canvas sits BELOW the wells and the paper.
457
+ for (const plane of ["md3-surface-container-low", "md3-surface-container", "md3-surface-container-high"]) {
458
+ expect(hexRelativeLuminanceIn(light, "md3-surface"), `canvas below ${plane}`).toBeLessThan(
459
+ hexRelativeLuminanceIn(light, plane),
460
+ );
461
+ }
462
+ const steps = [
463
+ "md3-surface-container-lowest",
464
+ "md3-surface-container-low",
465
+ "md3-surface-container",
466
+ "md3-surface-container-high",
467
+ "md3-surface-container-highest",
468
+ ].map((token) => hexRelativeLuminanceIn(dark, token));
469
+ for (let i = 1; i < steps.length; i++) {
470
+ expect(steps[i], `dark step ${i} must rise`).toBeGreaterThan(steps[i - 1]);
471
+ }
472
+ });
473
+
474
+ it.each([
475
+ ["light", light],
476
+ ["dark", dark],
477
+ ])("holds AA text and 3:1 focus contrast in %s", (_mode, css) => {
478
+ const canvas = hslToRgb(hslIn(css, "hsl-background"));
479
+ const card = hslToRgb(hslIn(css, "hsl-card"));
480
+ const muted = hslToRgb(hslIn(css, "hsl-muted"));
481
+ const fg = hslToRgb(hslIn(css, "hsl-foreground"));
482
+ expect(contrastRatio(fg, canvas), "ink on canvas").toBeGreaterThanOrEqual(7);
483
+ expect(contrastRatio(fg, card), "ink on card").toBeGreaterThanOrEqual(7);
484
+ const mutedInk = hslToRgb(hslIn(css, "hsl-muted-foreground"));
485
+ const planes = [
486
+ ["canvas", canvas],
487
+ ["card", card],
488
+ ["muted", muted],
489
+ ["elevated", hexIn(css, "depth-4")],
490
+ ["highest", hexIn(css, "md3-surface-container-highest")],
491
+ ] as const;
492
+ for (const [name, plane] of planes) {
493
+ expect(contrastRatio(mutedInk, plane), `muted ink on ${name}`).toBeGreaterThanOrEqual(4.5);
494
+ expect(contrastRatio(hexIn(css, "accent-text"), plane), `accent text on ${name}`).toBeGreaterThanOrEqual(4.5);
495
+ expect(contrastRatio(hexIn(css, "text-dim"), plane), `text-dim on ${name}`).toBeGreaterThanOrEqual(4.5);
496
+ }
497
+ expect(
498
+ contrastRatio(hslToRgb(hslIn(css, "hsl-primary-foreground")), hslToRgb(hslIn(css, "hsl-primary"))),
499
+ "primary label on the primary fill",
500
+ ).toBeGreaterThanOrEqual(4.5);
501
+ expect(
502
+ contrastRatio(hexIn(css, "btn-primary-text"), hexIn(css, "btn-primary-bg")),
503
+ "button label on the button fill",
504
+ ).toBeGreaterThanOrEqual(4.5);
505
+ const ring = hslToRgb(hslIn(css, "hsl-ring"));
506
+ expect(contrastRatio(ring, canvas), "ring on canvas").toBeGreaterThanOrEqual(3);
507
+ expect(contrastRatio(ring, card), "ring on card").toBeGreaterThanOrEqual(3);
508
+ });
509
+ });
510
+
511
+ describe('named theme: [data-theme="super"] / [data-theme="super-light"]', () => {
512
+ const dark = block('[data-theme="super"]');
513
+ const light = blocksIn(themes, '[data-theme="super-light"]').find((b) =>
514
+ b.includes("--hsl-background"),
515
+ );
516
+ if (!light) throw new Error('missing theme block: [data-theme="super-light"]');
517
+
518
+ it.each([
519
+ ["super", dark],
520
+ ["super-light", light],
521
+ ])("%s clears AA for ink, muted ink, the action fill and the ring", (_name, css) => {
522
+ const canvas = hslToRgb(hslIn(css, "hsl-background"));
523
+ const card = hslToRgb(hslIn(css, "hsl-card"));
524
+ const muted = hslToRgb(hslIn(css, "hsl-muted"));
525
+ const fg = hslToRgb(hslIn(css, "hsl-foreground"));
526
+ const mutedFg = hslToRgb(hslIn(css, "hsl-muted-foreground"));
527
+ expect(contrastRatio(fg, canvas), "ink on canvas").toBeGreaterThanOrEqual(7);
528
+ expect(contrastRatio(fg, card), "ink on card").toBeGreaterThanOrEqual(7);
529
+ expect(contrastRatio(mutedFg, canvas), "muted ink on canvas").toBeGreaterThanOrEqual(4.5);
530
+ expect(contrastRatio(mutedFg, card), "muted ink on card").toBeGreaterThanOrEqual(4.5);
531
+ expect(contrastRatio(mutedFg, muted), "muted ink on muted").toBeGreaterThanOrEqual(4.5);
532
+
533
+ const primary = hslToRgb(hslIn(css, "hsl-primary"));
534
+ const onPrimary = hslToRgb(hslIn(css, "hsl-primary-foreground"));
535
+ expect(contrastRatio(onPrimary, primary), "text on the action fill").toBeGreaterThanOrEqual(4.5);
536
+
537
+ const ring = hslToRgb(hslIn(css, "hsl-ring"));
538
+ expect(contrastRatio(ring, canvas), "ring on canvas").toBeGreaterThanOrEqual(3);
539
+ expect(contrastRatio(ring, card), "ring on card").toBeGreaterThanOrEqual(3);
540
+
541
+ for (const tier of ["text-primary", "text-secondary", "text-muted", "text-dim", "accent-text"]) {
542
+ expect(contrastRatio(hexIn(css, tier), card), `${tier} on card`).toBeGreaterThanOrEqual(4.5);
543
+ expect(contrastRatio(hexIn(css, tier), canvas), `${tier} on canvas`).toBeGreaterThanOrEqual(4.5);
544
+ }
545
+ });
546
+
547
+ it.each([
548
+ ["super", dark],
549
+ ["super-light", light],
550
+ ])("%s button tokens follow the action fill, not the Tangle indigo", (_name, css) => {
551
+ expect(contrastRatio(hexIn(css, "btn-primary-text"), hexIn(css, "btn-primary-bg"))).toBeGreaterThanOrEqual(4.5);
552
+ expect(contrastRatio(hexIn(css, "btn-primary-text"), hexIn(css, "btn-primary-hover"))).toBeGreaterThanOrEqual(4.5);
553
+ const fill = hslToRgb(hslIn(css, "hsl-primary"));
554
+ hexIn(css, "btn-primary-bg").forEach((channel, i) => {
555
+ expect(Math.abs(channel - fill[i]), "btn-primary-bg matches --hsl-primary").toBeLessThanOrEqual(4);
556
+ });
557
+ });
558
+
559
+ it("keeps the forest action in one hue family across modes", () => {
560
+ for (const token of ["hsl-primary", "hsl-ring"]) {
561
+ expect(
562
+ Math.abs(hslIn(dark, token).h - hslIn(light, token).h),
563
+ `--${token} hue`,
564
+ ).toBeLessThanOrEqual(10);
565
+ }
566
+ });
567
+
568
+ it("elevates by lightening in dark", () => {
569
+ const planes = ["depth-1", "depth-2", "depth-3", "depth-4"].map((t) =>
570
+ hexRelativeLuminanceIn(dark, t),
571
+ );
572
+ for (let i = 1; i < planes.length; i++) {
573
+ expect(planes[i], `depth step ${i}`).toBeGreaterThan(planes[i - 1]);
574
+ }
575
+ });
576
+
577
+ it("inherits status tones instead of retinting them", () => {
578
+ for (const css of [dark, light]) {
579
+ expect(css).not.toMatch(/--surface-(success|warning|danger|info|neutral)-/);
580
+ expect(css).not.toMatch(/--tone-/);
581
+ }
582
+ });
583
+ });
584
+
585
+ describe('named theme: [data-theme="website"]', () => {
586
+ const rules = themes.replace(/\/\*[\s\S]*?\*\//g, "");
587
+ const light = block('[data-theme="website"]:where(:not(.dark))');
588
+ const dark = block('.dark[data-theme="website"]');
589
+ const props = (css: string) =>
590
+ [...css.matchAll(/(--[\w-]+)\s*:/g)].map((match) => match[1]).sort();
591
+
592
+ it("takes its dark mode from the .dark class, so a light island is the same attribute", () => {
593
+ expect(rules).toMatch(/^\[data-theme="website"\]:where\(:not\(\.dark\)\) \{/m);
594
+ expect(rules).toMatch(/^\.dark\[data-theme="website"\] \{/m);
595
+ expect(rules).not.toContain('[data-theme="website-light"]');
596
+ });
597
+
598
+ it("starts from a complete canonical baseline in either mode", () => {
599
+ const header = (anchor: string) => {
600
+ const end = tokens.indexOf(anchor);
601
+ return tokens.slice(tokens.lastIndexOf("}", end) + 1, tokens.indexOf("{", end));
602
+ };
603
+ expect(header("color-scheme: dark")).toContain('[data-theme="website"],');
604
+ expect(header("color-scheme: light")).toContain('[data-theme="website"]:where(:not(.dark)),');
605
+ });
606
+
607
+ it("declares the same properties in both modes", () => {
608
+ expect(props(dark)).toEqual(props(light));
609
+ });
610
+
611
+ it("changes planes and ink only: accent, status, category and syntax stay canonical", () => {
612
+ for (const css of [light, dark]) {
613
+ expect(css).not.toMatch(
614
+ /--hsl-(primary|ring)|--accent-text|--brand-|--btn-|--(hsl-)?(success|warning|destructive|info|error)\b|--surface-(success|warning|danger|info|neutral)-|--status-|--tone-|--syntax-/,
615
+ );
616
+ }
617
+ });
618
+
619
+ it("keeps the canonical ladder roles: paper cards in light, rising planes in dark", () => {
620
+ expect(hslIn(light, "hsl-card")).toEqual({ h: 0, s: 0, l: 100 });
621
+ const steps = [
622
+ "md3-surface-container-lowest",
623
+ "md3-surface-container-low",
624
+ "md3-surface-container",
625
+ "md3-surface-container-high",
626
+ "md3-surface-container-highest",
627
+ ].map((token) => hexRelativeLuminanceIn(dark, token));
628
+ for (let i = 1; i < steps.length; i++) {
629
+ expect(steps[i], `dark step ${i} must rise`).toBeGreaterThan(steps[i - 1]);
630
+ }
631
+ });
632
+
633
+ it.each([
634
+ ["light", light],
635
+ ["dark", dark],
636
+ ])("holds AA ink on every plane in %s", (_mode, css) => {
637
+ const fg = hslToRgb(hslIn(css, "hsl-foreground"));
638
+ const mutedInk = hslToRgb(hslIn(css, "hsl-muted-foreground"));
639
+ const planes = [
640
+ ["canvas", hslToRgb(hslIn(css, "hsl-background"))],
641
+ ["card", hslToRgb(hslIn(css, "hsl-card"))],
642
+ ["muted", hslToRgb(hslIn(css, "hsl-muted"))],
643
+ ["popover", hslToRgb(hslIn(css, "hsl-popover"))],
644
+ ["elevated", hexIn(css, "depth-4")],
645
+ ["highest", hexIn(css, "md3-surface-container-highest")],
646
+ ] as const;
647
+ for (const [name, plane] of planes) {
648
+ expect(contrastRatio(fg, plane), `ink on ${name}`).toBeGreaterThanOrEqual(7);
649
+ expect(contrastRatio(mutedInk, plane), `muted ink on ${name}`).toBeGreaterThanOrEqual(4.5);
650
+ for (const token of ["text-secondary", "text-muted", "text-dim"]) {
651
+ expect(contrastRatio(hexIn(css, token), plane), `${token} on ${name}`).toBeGreaterThanOrEqual(4.5);
652
+ }
653
+ }
654
+ });
655
+ });
@@ -45,8 +45,14 @@
45
45
  [data-theme="aubergine-light"],
46
46
  [data-theme="arena"],
47
47
  [data-theme="arena-light"],
48
+ [data-theme="super"],
49
+ [data-theme="super-light"],
48
50
  [data-theme="tangle-dark"],
49
51
  [data-theme="tangle-light"],
52
+ [data-theme="hospitality"],
53
+ [data-theme="agents"],
54
+ [data-theme="agents-light"],
55
+ [data-theme="website"],
50
56
  .light,
51
57
  .dark {
52
58
  color-scheme: dark;
@@ -516,10 +522,14 @@
516
522
  * carries both `data-sandbox-ui` (dark) and `data-theme="light"`, light wins. */
517
523
  [data-sandbox-theme="vault"]:where(:not(.dark)),
518
524
  [data-sandbox-theme="dawn"]:where(:not(.dark)),
525
+ [data-theme="hospitality"]:where(:not(.dark)),
526
+ [data-theme="website"]:where(:not(.dark)),
519
527
  [data-theme="light"],
520
528
  [data-theme="aubergine-light"],
521
529
  [data-theme="arena-light"],
530
+ [data-theme="super-light"],
522
531
  [data-theme="tangle-light"],
532
+ [data-theme="agents-light"],
523
533
  .light {
524
534
  color-scheme: light;
525
535
  /* Light theme — neutral surfaces with purple accents */
@@ -925,6 +935,8 @@
925
935
  * themes, which would otherwise inherit the dark ramp from :root. */
926
936
  [data-sandbox-theme="vault"]:where(:not(.dark)),
927
937
  [data-sandbox-theme="dawn"]:where(:not(.dark)),
938
+ [data-theme="hospitality"]:where(:not(.dark)),
939
+ [data-theme="website"]:where(:not(.dark)),
928
940
  [data-theme="light"],
929
941
  .light,
930
942
  [data-theme$="-light"] {
@@ -959,3 +971,86 @@
959
971
  --motion-arrive: var(--duration-arrive) var(--ease-expo);
960
972
  }
961
973
  }
974
+
975
+ /* tone-scopes:begin — generated by scripts/gen-ladders.mjs; edit its CATEGORY map, not these lines. */
976
+ [data-tone="violet"],
977
+ [data-tone="violet"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
978
+ --tone-bg: var(--tone-violet-bg);
979
+ --tone-bg-hover: var(--tone-violet-bg-hover);
980
+ --tone-bg-selected: var(--tone-violet-bg-selected);
981
+ --tone-border: var(--tone-violet-border);
982
+ --tone-border-selected: var(--tone-violet-border-selected);
983
+ --tone-text: var(--tone-violet-text);
984
+ --tone-icon: var(--tone-violet-icon);
985
+ }
986
+ [data-tone="orange"],
987
+ [data-tone="orange"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
988
+ --tone-bg: var(--tone-orange-bg);
989
+ --tone-bg-hover: var(--tone-orange-bg-hover);
990
+ --tone-bg-selected: var(--tone-orange-bg-selected);
991
+ --tone-border: var(--tone-orange-border);
992
+ --tone-border-selected: var(--tone-orange-border-selected);
993
+ --tone-text: var(--tone-orange-text);
994
+ --tone-icon: var(--tone-orange-icon);
995
+ }
996
+ [data-tone="teal"],
997
+ [data-tone="teal"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
998
+ --tone-bg: var(--tone-teal-bg);
999
+ --tone-bg-hover: var(--tone-teal-bg-hover);
1000
+ --tone-bg-selected: var(--tone-teal-bg-selected);
1001
+ --tone-border: var(--tone-teal-border);
1002
+ --tone-border-selected: var(--tone-teal-border-selected);
1003
+ --tone-text: var(--tone-teal-text);
1004
+ --tone-icon: var(--tone-teal-icon);
1005
+ }
1006
+ [data-tone="blue"],
1007
+ [data-tone="blue"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
1008
+ --tone-bg: var(--tone-blue-bg);
1009
+ --tone-bg-hover: var(--tone-blue-bg-hover);
1010
+ --tone-bg-selected: var(--tone-blue-bg-selected);
1011
+ --tone-border: var(--tone-blue-border);
1012
+ --tone-border-selected: var(--tone-blue-border-selected);
1013
+ --tone-text: var(--tone-blue-text);
1014
+ --tone-icon: var(--tone-blue-icon);
1015
+ }
1016
+ [data-tone="pink"],
1017
+ [data-tone="pink"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
1018
+ --tone-bg: var(--tone-pink-bg);
1019
+ --tone-bg-hover: var(--tone-pink-bg-hover);
1020
+ --tone-bg-selected: var(--tone-pink-bg-selected);
1021
+ --tone-border: var(--tone-pink-border);
1022
+ --tone-border-selected: var(--tone-pink-border-selected);
1023
+ --tone-text: var(--tone-pink-text);
1024
+ --tone-icon: var(--tone-pink-icon);
1025
+ }
1026
+ [data-tone="brown"],
1027
+ [data-tone="brown"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
1028
+ --tone-bg: var(--tone-brown-bg);
1029
+ --tone-bg-hover: var(--tone-brown-bg-hover);
1030
+ --tone-bg-selected: var(--tone-brown-bg-selected);
1031
+ --tone-border: var(--tone-brown-border);
1032
+ --tone-border-selected: var(--tone-brown-border-selected);
1033
+ --tone-text: var(--tone-brown-text);
1034
+ --tone-icon: var(--tone-brown-icon);
1035
+ }
1036
+ [data-tone="cyan"],
1037
+ [data-tone="cyan"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
1038
+ --tone-bg: var(--tone-cyan-bg);
1039
+ --tone-bg-hover: var(--tone-cyan-bg-hover);
1040
+ --tone-bg-selected: var(--tone-cyan-bg-selected);
1041
+ --tone-border: var(--tone-cyan-border);
1042
+ --tone-border-selected: var(--tone-cyan-border-selected);
1043
+ --tone-text: var(--tone-cyan-text);
1044
+ --tone-icon: var(--tone-cyan-icon);
1045
+ }
1046
+ [data-tone="lime"],
1047
+ [data-tone="lime"] :is(.light, .dark, [data-theme], [data-sandbox-ui], [data-sandbox-theme]) {
1048
+ --tone-bg: var(--tone-lime-bg);
1049
+ --tone-bg-hover: var(--tone-lime-bg-hover);
1050
+ --tone-bg-selected: var(--tone-lime-bg-selected);
1051
+ --tone-border: var(--tone-lime-border);
1052
+ --tone-border-selected: var(--tone-lime-border-selected);
1053
+ --tone-text: var(--tone-lime-text);
1054
+ --tone-icon: var(--tone-lime-icon);
1055
+ }
1056
+ /* tone-scopes:end */