@sableui/react 0.14.0 → 0.16.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 (163) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/DESIGN.md +3 -1
  3. package/bin/sable-lint.mjs +5 -1
  4. package/dist/{_contract-CkqXDVww.d.ts → _contract-CDa9-NdB.d.ts} +47 -1
  5. package/dist/blocks/index.d.ts +12 -1
  6. package/dist/blocks/index.js +4 -0
  7. package/dist/blocks/message-reactions-block.js +87 -0
  8. package/dist/blocks/message-reactions-block.meta.js +23 -0
  9. package/dist/blocks/wallet-block.js +2 -2
  10. package/dist/components/app-shell/app-shell-frame.js +16 -0
  11. package/dist/components/app-shell/app-shell-main.js +12 -0
  12. package/dist/components/app-shell/app-shell.js +28 -4
  13. package/dist/components/app-shell/app-shell.meta.js +88 -4
  14. package/dist/components/area-chart/area-chart.meta.js +6 -1
  15. package/dist/components/attachment/attachment.meta.js +2 -1
  16. package/dist/components/attachment/attachment.variants.js +1 -1
  17. package/dist/components/badge/badge.meta.js +8 -1
  18. package/dist/components/badge/badge.variants.js +7 -7
  19. package/dist/components/banner/banner.meta.js +6 -1
  20. package/dist/components/banner/banner.variants.js +5 -5
  21. package/dist/components/bar-chart/bar-chart.meta.js +6 -1
  22. package/dist/components/bubble/bubble.js +105 -5
  23. package/dist/components/bubble/bubble.meta.js +42 -6
  24. package/dist/components/bubble/bubble.variants.js +1 -1
  25. package/dist/components/bubble/index.js +2 -0
  26. package/dist/components/caret-menu/caret-menu.js +5 -6
  27. package/dist/components/chat-composer/chat-composer.meta.js +2 -2
  28. package/dist/components/chat-composer/chat-composer.variants.js +1 -1
  29. package/dist/components/color-field/color-field.js +6 -8
  30. package/dist/components/combobox/combobox.js +27 -5
  31. package/dist/components/combobox/combobox.meta.js +10 -2
  32. package/dist/components/command-menu/command-menu.js +14 -3
  33. package/dist/components/command-menu/command-menu.meta.js +9 -1
  34. package/dist/components/date-picker/date-picker.meta.js +2 -2
  35. package/dist/components/feedback/feedback.js +9 -2
  36. package/dist/components/feedback/feedback.meta.js +8 -1
  37. package/dist/components/gradient-art/gradient-art.js +8 -5
  38. package/dist/components/gradient-art/gradient-art.meta.js +35 -2
  39. package/dist/components/input/input.meta.js +11 -3
  40. package/dist/components/input-group/input-group.js +1 -1
  41. package/dist/components/input-group/input-group.meta.js +1 -1
  42. package/dist/components/like-button/index.js +7 -0
  43. package/dist/components/like-button/like-button.js +89 -0
  44. package/dist/components/like-button/like-button.meta.js +132 -0
  45. package/dist/components/line-chart/line-chart.meta.js +6 -1
  46. package/dist/components/menu/menu.js +1 -1
  47. package/dist/components/meter/meter.js +53 -7
  48. package/dist/components/meter/meter.meta.js +51 -4
  49. package/dist/components/meter/meter.variants.js +43 -7
  50. package/dist/components/note/note.meta.js +5 -1
  51. package/dist/components/note/note.variants.js +4 -4
  52. package/dist/components/number-field/number-field.meta.js +2 -2
  53. package/dist/components/otp-field/otp-field.meta.js +2 -2
  54. package/dist/components/panel-group/panel-group.js +5 -8
  55. package/dist/components/pie-chart/pie-chart.meta.js +6 -1
  56. package/dist/components/radar-chart/radar-chart.meta.js +6 -1
  57. package/dist/components/radial-chart/radial-chart.meta.js +6 -1
  58. package/dist/components/reaction-picker/index.js +13 -0
  59. package/dist/components/reaction-picker/reaction-picker.js +104 -0
  60. package/dist/components/reaction-picker/reaction-picker.meta.js +156 -0
  61. package/dist/components/search-input/search-input.meta.js +11 -3
  62. package/dist/components/segmented-bar/segmented-bar.meta.js +8 -1
  63. package/dist/components/segmented-bar/segmented-bar.variants.js +7 -7
  64. package/dist/components/select/select.js +1 -1
  65. package/dist/components/select/select.meta.js +2 -2
  66. package/dist/components/sheet/sheet.js +5 -4
  67. package/dist/components/sidebar/sidebar.js +16 -1
  68. package/dist/components/sidebar/sidebar.meta.js +7 -2
  69. package/dist/components/sparkline/sparkline.meta.js +8 -1
  70. package/dist/components/status-dot/status-dot.meta.js +8 -1
  71. package/dist/components/status-dot/status-dot.variants.js +7 -7
  72. package/dist/components/stepper/stepper.meta.js +2 -1
  73. package/dist/components/stepper/stepper.variants.js +1 -1
  74. package/dist/components/table/table.meta.js +4 -4
  75. package/dist/components/textarea/textarea.js +5 -0
  76. package/dist/components/textarea/textarea.meta.js +3 -3
  77. package/dist/components/toast/toast.js +25 -13
  78. package/dist/components/toast/toast.meta.js +7 -1
  79. package/dist/file-hashes.json +112 -100
  80. package/dist/foundations/accessibility.js +5 -0
  81. package/dist/foundations/motion.js +21 -1
  82. package/dist/icon-sets/reicon.js +11 -1
  83. package/dist/index.d.ts +425 -84
  84. package/dist/index.js +11 -1
  85. package/dist/lib/chart/types.js +8 -8
  86. package/dist/lib/chart/use-arrival.js +5 -4
  87. package/dist/lib/field-shell.js +1 -1
  88. package/dist/lib/highlight-glide.js +6 -6
  89. package/dist/lib/scrub-gesture.js +6 -6
  90. package/dist/lib/taxonomy.js +2 -0
  91. package/dist/lib/use-caret-trigger.js +11 -18
  92. package/dist/lib/use-match-highlight.js +69 -0
  93. package/dist/lib/use-smooth-wheel.js +10 -8
  94. package/dist/motion/Burst.js +79 -0
  95. package/dist/motion/index.js +2 -0
  96. package/dist/presets/index.d.ts +13 -2
  97. package/dist/presets/index.js +17 -1
  98. package/dist/styles.css +241 -0
  99. package/dist/{theme-provider-CdSicAad.d.ts → theme-provider-BydfM5Z0.d.ts} +1 -1
  100. package/dist/themes/_contract.js +14 -0
  101. package/dist/themes/atelier/atelier.css +18 -0
  102. package/dist/themes/atelier/index.d.ts +1 -1
  103. package/dist/themes/contrast.js +48 -1
  104. package/dist/themes/ember/ember.css +18 -0
  105. package/dist/themes/ember/index.d.ts +1 -1
  106. package/dist/themes/index.d.ts +2 -2
  107. package/dist/themes/meridian/index.d.ts +1 -1
  108. package/dist/themes/meridian/meridian.css +18 -0
  109. package/dist/themes/poppy/index.d.ts +1 -1
  110. package/dist/themes/poppy/poppy.css +18 -0
  111. package/dist/themes/prism/index.d.ts +1 -1
  112. package/dist/themes/prism/prism.css +18 -0
  113. package/dist/themes/sable/index.d.ts +1 -1
  114. package/dist/themes/sable/sable.css +18 -0
  115. package/dist/themes/verdant/index.d.ts +1 -1
  116. package/dist/themes/verdant/verdant.css +18 -0
  117. package/llms/blocks/message-reactions-block.md +116 -0
  118. package/llms/blocks/wallet-block.md +5 -4
  119. package/llms/components/app-shell.md +72 -3
  120. package/llms/components/area-chart.md +1 -1
  121. package/llms/components/attachment.md +1 -1
  122. package/llms/components/badge.md +1 -1
  123. package/llms/components/banner.md +1 -1
  124. package/llms/components/bar-chart.md +1 -1
  125. package/llms/components/bubble.md +17 -7
  126. package/llms/components/chat-composer.md +1 -1
  127. package/llms/components/combobox.md +2 -1
  128. package/llms/components/command-menu.md +3 -2
  129. package/llms/components/date-picker.md +1 -1
  130. package/llms/components/feedback.md +2 -1
  131. package/llms/components/gradient-art.md +28 -1
  132. package/llms/components/input-group.md +1 -1
  133. package/llms/components/input.md +4 -2
  134. package/llms/components/like-button.md +91 -0
  135. package/llms/components/line-chart.md +1 -1
  136. package/llms/components/meter.md +33 -4
  137. package/llms/components/note.md +1 -1
  138. package/llms/components/number-field.md +1 -1
  139. package/llms/components/otp-field.md +1 -1
  140. package/llms/components/pie-chart.md +1 -1
  141. package/llms/components/radar-chart.md +1 -1
  142. package/llms/components/radial-chart.md +1 -1
  143. package/llms/components/reaction-picker.md +115 -0
  144. package/llms/components/search-input.md +20 -2
  145. package/llms/components/segmented-bar.md +1 -1
  146. package/llms/components/select.md +1 -1
  147. package/llms/components/sidebar.md +3 -2
  148. package/llms/components/sparkline.md +1 -1
  149. package/llms/components/status-dot.md +1 -1
  150. package/llms/components/stepper.md +1 -1
  151. package/llms/components/table.md +2 -2
  152. package/llms/components/textarea.md +2 -2
  153. package/llms/components/toast.md +2 -1
  154. package/llms/foundations/accessibility.md +1 -0
  155. package/llms/foundations/motion.md +18 -2
  156. package/llms/reference/token-intent.md +22 -2
  157. package/llms/reference/utilities.md +9 -3
  158. package/llms-full.txt +596 -61
  159. package/llms.txt +10 -7
  160. package/package.json +1 -1
  161. package/registry.json +968 -68
  162. package/scripts/lint-rules.mjs +6 -3
  163. package/targets/ios.json +18 -0
package/dist/styles.css CHANGED
@@ -86,6 +86,16 @@
86
86
  --color-border-strong: var(--border-strong);
87
87
  --color-border-floating: var(--border-floating);
88
88
  --color-input: var(--input);
89
+ --color-field: var(--field);
90
+ --color-field-border: var(--field-border);
91
+ --color-shell-ground: var(--shell-ground);
92
+ --color-destructive-mark: var(--destructive-mark);
93
+ --color-success-mark: var(--success-mark);
94
+ --color-tone-warning-mark: var(--tone-warning-mark);
95
+ --color-tone-info-mark: var(--tone-info-mark);
96
+ --color-tone-1-mark: var(--tone-1-mark);
97
+ --color-tone-2-mark: var(--tone-2-mark);
98
+ --color-tone-3-mark: var(--tone-3-mark);
89
99
  --color-control-border: var(--control-border);
90
100
  --color-ring: var(--ring);
91
101
 
@@ -378,6 +388,33 @@
378
388
  and reads as a faint lit edge in dark mode, where shadows barely show. */
379
389
  --border-floating: var(--theme-border-floating, color-mix(in oklch, transparent 92%, var(--foreground)));
380
390
 
391
+ /* The text field: its fill and its outline. Outlined on the card by default;
392
+ a theme fills its fields instead with `--theme-field: var(--muted)` and
393
+ `--theme-field-border: transparent`. Every field reads the pair through
394
+ lib/field-shell, so one choice restyles them all. */
395
+ --field: var(--theme-field, var(--card));
396
+ --field-border: var(--theme-field-border, var(--input));
397
+
398
+ /* The ground of an inset app frame (`AppShell frame="inset"`): the rail and
399
+ the gap around the raised main panel. One step off the rail toward its ink,
400
+ because most themes paint the rail the page's colour and the panel would
401
+ otherwise sit on its own colour. */
402
+ --shell-ground: var(--theme-shell-ground, color-mix(in oklch, var(--sidebar) 97%, var(--sidebar-foreground)));
403
+
404
+ /* Status and tone colours at graphic strength: a meter's fill, a segmented
405
+ bar, a status dot, a chart series, a soft tint. The label fill is dark
406
+ enough for white ink; a mark carries no ink, so it is the same hue lifted
407
+ and saturated (MARK_TOKENS in themes/_contract.ts). Every bundled theme
408
+ tunes its own through the hooks; this derivation is the fallback for a
409
+ preset that does not. */
410
+ --destructive-mark: var(--theme-destructive-mark, oklch(from var(--destructive) max(l, 0.62) calc(c * 1.25) h));
411
+ --success-mark: var(--theme-success-mark, oklch(from var(--success) max(l, 0.68) calc(c * 1.25) h));
412
+ --tone-warning-mark: var(--theme-tone-warning-mark, oklch(from var(--tone-warning) max(l, 0.71) calc(c * 1.25) h));
413
+ --tone-info-mark: var(--theme-tone-info-mark, oklch(from var(--tone-info) max(l, 0.63) calc(c * 1.25) h));
414
+ --tone-1-mark: var(--theme-tone-1-mark, oklch(from var(--tone-1) max(l, 0.62) calc(c * 1.25) h));
415
+ --tone-2-mark: var(--theme-tone-2-mark, oklch(from var(--tone-2) max(l, 0.6) calc(c * 1.25) h));
416
+ --tone-3-mark: var(--theme-tone-3-mark, oklch(from var(--tone-3) max(l, 0.66) calc(c * 1.25) h));
417
+
381
418
  /* The Switch knob when OFF: light in BOTH modes, like every physical toggle.
382
419
  It used to be `--background`, which in a dark theme is a near-black knob on
383
420
  a dark track (well under 3:1). */
@@ -848,6 +885,24 @@
848
885
  }
849
886
  }
850
887
 
888
+ /* ==========================================================================
889
+ Search matches — the paint behind `useMatchHighlight` (lib/use-match-highlight),
890
+ which Combobox and CommandMenu run on their rows and a consumer can run on any
891
+ results list. The CSS Custom Highlight API marks text Ranges, so nothing is
892
+ wrapped in a <mark> and React's text nodes stay as rendered.
893
+
894
+ On `highlight` because that token exists for exactly this ("search hits" in
895
+ its intent). A tint of it, not the solid pair: a solid fill behind a few
896
+ letters is what a text selection looks like, and a list where every row
897
+ seems half-selected reads as a bug. The tint leaves the row's own ink, so
898
+ contrast stays the row's. Where the API is missing no ranges are registered
899
+ and this rule matches nothing.
900
+ ========================================================================== */
901
+
902
+ ::highlight(sable-match) {
903
+ background-color: color-mix(in oklab, var(--highlight) 36%, transparent);
904
+ }
905
+
851
906
  /* ==========================================================================
852
907
  UI tier — the WORKSPACE register's chrome typography. A separate ramp from the
853
908
  six page tiers above, on purpose.
@@ -1995,6 +2050,51 @@
1995
2050
  background-position: 0 0;
1996
2051
  }
1997
2052
 
2053
+ /* texture-dither — a faint field of tiny squares that dissolves, the pixel /
2054
+ halftone texture products lay over the top of a content area or behind an
2055
+ empty-state heading. Pure CSS and static: the dots are the element's own
2056
+ background, cut out by a mask of a small pixel tile intersected with a fade.
2057
+
2058
+ The tile is 12×12 cells of one square each on a 2-unit pitch, about 40%
2059
+ filled at random (no runs of three, no 2×2 clumps) and a third of the dots at
2060
+ half strength, so it reads as dither rather than as a grid of dots. It is a
2061
+ MASK, so the SVG carries no colour of its own: the dots paint in
2062
+ `--border-strong`, the structural-divider ink, which every theme tunes for
2063
+ both modes — faint on a light page, a soft grey on a dark one.
2064
+
2065
+ Decoration only: put it on its own absolutely-positioned, aria-hidden element
2066
+ (it sets pointer-events: none but no position, so it never takes layout),
2067
+ first in a `relative isolate` parent and at -z-10, so the content after it
2068
+ paints on top without a z-index of its own:
2069
+
2070
+ <div class="relative isolate">
2071
+ <div aria-hidden class="texture-dither absolute inset-x-0 top-0 -z-10 h-40" />
2072
+ …content…
2073
+ </div>
2074
+
2075
+ Three hooks, all optional, read with fallbacks (the checkerboard pattern):
2076
+ --dither-fade the fade's direction, any linear-gradient side or angle
2077
+ (default `to bottom`: dense at the top, gone at the bottom)
2078
+ --dither-size the tile (default 48px → 2px squares on a 4px pitch)
2079
+ --dither-color the dot ink (default var(--border-strong))
2080
+
2081
+ Not `bg-dither`, for the reason `checkerboard` is not `bg-checkerboard`: a
2082
+ `bg-` name joins tailwind-merge's background group and would evict, or be
2083
+ evicted by, a real colour class. */
2084
+ @utility texture-dither {
2085
+ pointer-events: none;
2086
+ background-color: var(--dither-color, var(--border-strong));
2087
+ --dither-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M4 0h1v1H4zM8 0h1v1H8zM16 0h1v1H16zM2 2h1v1H2zM6 2h1v1H6zM14 2h1v1H14zM6 4h1v1H6zM10 4h1v1H10zM22 4h1v1H22zM2 6h1v1H2zM8 6h1v1H8zM14 6h1v1H14zM20 6h1v1H20zM2 8h1v1H2zM12 8h1v1H12zM18 8h1v1H18zM20 8h1v1H20zM12 10h1v1H12zM8 12h1v1H8zM2 14h1v1H2zM6 14h1v1H6zM16 14h1v1H16zM18 14h1v1H18zM0 16h1v1H0zM4 16h1v1H4zM6 16h1v1H6zM22 16h1v1H22zM10 18h1v1H10zM12 18h1v1H12zM16 18h1v1H16zM4 20h1v1H4zM20 20h1v1H20zM22 20h1v1H22zM0 22h1v1H0zM8 22h1v1H8zM12 22h1v1H12zM14 22h1v1H14zM20 22h1v1H20z'/%3E%3Cpath fill-opacity='.5' d='M0 0h1v1H0zM22 0h1v1H22zM20 2h1v1H20zM8 8h1v1H8zM14 8h1v1H14zM0 10h1v1H0zM4 10h1v1H4zM16 10h1v1H16zM22 10h1v1H22zM2 12h1v1H2zM4 12h1v1H4zM10 12h1v1H10zM18 12h1v1H18zM10 14h1v1H10zM0 18h1v1H0zM18 18h1v1H18zM10 20h1v1H10zM16 20h1v1H16zM18 22h1v1H18z'/%3E%3C/svg%3E");
2088
+ -webkit-mask-image: var(--dither-tile), linear-gradient(var(--dither-fade, to bottom), rgb(0 0 0), rgb(0 0 0 / 0.45) 35%, rgb(0 0 0 / 0));
2089
+ mask-image: var(--dither-tile), linear-gradient(var(--dither-fade, to bottom), rgb(0 0 0), rgb(0 0 0 / 0.45) 35%, rgb(0 0 0 / 0));
2090
+ -webkit-mask-size: var(--dither-size, 48px) var(--dither-size, 48px), 100% 100%;
2091
+ mask-size: var(--dither-size, 48px) var(--dither-size, 48px), 100% 100%;
2092
+ -webkit-mask-repeat: repeat, no-repeat;
2093
+ mask-repeat: repeat, no-repeat;
2094
+ -webkit-mask-composite: source-in;
2095
+ mask-composite: intersect;
2096
+ }
2097
+
1998
2098
  /* The default transition for interactive chrome — hover/focus/selection colour
1999
2099
  shifts plus the press/slide transforms. The single transition declarer for
2000
2100
  interactive controls: it lists scale + translate too, so `motion-press` and
@@ -2475,6 +2575,147 @@
2475
2575
  var(--motion-ease-standard), var(--motion-ease-standard), var(--motion-ease-standard);
2476
2576
  }
2477
2577
 
2578
+ /* Bloom — a small glyph landing in its "on" state: a liked heart, a starred
2579
+ item, a toast's status icon. It grows from nothing past its size and settles
2580
+ back, the amplitude a 16px glyph needs to read as an event. Surfaces never
2581
+ bloom: a dialog that overshot 20% would be a lurch, which is why the overlay
2582
+ recipes travel from 0.96. Size is what sets the amplitude.
2583
+
2584
+ A keyframe animation, so it plays whenever the element MOUNTS: remount the
2585
+ glyph (a changing `key`) to replay it on each "on", and leave it off the
2586
+ resting state so a page that loads with a liked post does not bloom every
2587
+ heart. --motion-bloom-delay holds the glyph at nothing first (a raw delay;
2588
+ the recipe scales it), so a ring or burst can lead. Expressive: "subtle"
2589
+ and reduced motion land the glyph at once. Put it on a wrapper around a
2590
+ glyph that carries motion-press or motion-interactive: an animation holds
2591
+ `scale` while it runs. */
2592
+ @keyframes sable-bloom {
2593
+ 0% {
2594
+ scale: 0;
2595
+ }
2596
+ 55% {
2597
+ scale: 1.2;
2598
+ }
2599
+ 80% {
2600
+ scale: 0.95;
2601
+ }
2602
+ 100% {
2603
+ scale: 1;
2604
+ }
2605
+ }
2606
+ @utility motion-bloom {
2607
+ animation: sable-bloom calc(var(--motion-duration-slower) * var(--motion-expressive, 1))
2608
+ var(--motion-ease-decelerate)
2609
+ calc(var(--motion-bloom-delay, 0ms) * var(--motion-scale, 1) * var(--motion-expressive, 1))
2610
+ backwards;
2611
+ }
2612
+
2613
+ /* Burst — the follow-through behind a bloom, drawn by <Burst> (src/motion): a
2614
+ disc that hollows into a ring and shifts colour, then dots thrown outward
2615
+ that shrink as they go. Plain classes, not utilities: the component owns the
2616
+ markup and the per-dot angles. Sized by --burst-size (the ring's diameter,
2617
+ about twice the glyph's). Coloured from the themed palette through
2618
+ `data-palette` scopes, never a step: the ring blooms in currentColor and
2619
+ fades into its scope's dot colour, and each dot carries a family of its
2620
+ own. Every duration is expressive, so under
2621
+ "subtle" or reduced motion it ends on its invisible last frame at once; the
2622
+ component also renders nothing then. */
2623
+ .sable-burst {
2624
+ position: absolute;
2625
+ inset: 0;
2626
+ pointer-events: none;
2627
+ }
2628
+ /* Centred on the glyph by `translate`, which applies before the animated
2629
+ `scale` and `transform`, so each piece grows and travels from the centre.
2630
+ (A grid cell sized itself to the 2x ring and pinned it off-centre.) */
2631
+ .sable-burst > * {
2632
+ position: absolute;
2633
+ left: 50%;
2634
+ top: 50%;
2635
+ translate: -50% -50%;
2636
+ }
2637
+ @keyframes sable-burst-ring {
2638
+ 0% {
2639
+ scale: 0.2;
2640
+ border-width: calc(var(--burst-size) / 2);
2641
+ border-color: currentColor;
2642
+ opacity: 1;
2643
+ }
2644
+ 45% {
2645
+ scale: 1;
2646
+ border-width: calc(var(--burst-size) / 2);
2647
+ }
2648
+ 100% {
2649
+ scale: 1.1;
2650
+ border-width: 0;
2651
+ border-color: var(--palette-dot, currentColor);
2652
+ opacity: 0;
2653
+ }
2654
+ }
2655
+ .sable-burst-ring {
2656
+ width: var(--burst-size);
2657
+ height: var(--burst-size);
2658
+ border-radius: 9999px;
2659
+ border-style: solid;
2660
+ border-width: 0;
2661
+ opacity: 0;
2662
+ animation: sable-burst-ring calc(var(--motion-duration-slower) * var(--motion-expressive, 1))
2663
+ var(--motion-ease-decelerate) forwards;
2664
+ }
2665
+ @keyframes sable-burst-dot {
2666
+ 0% {
2667
+ opacity: 1;
2668
+ transform: rotate(var(--burst-dot-angle)) translateX(calc(var(--burst-size) * 0.4)) scale(1);
2669
+ }
2670
+ 100% {
2671
+ opacity: 1;
2672
+ transform: rotate(var(--burst-dot-angle)) translateX(calc(var(--burst-size) * var(--burst-dot-reach)))
2673
+ scale(0);
2674
+ }
2675
+ }
2676
+ .sable-burst-dot {
2677
+ width: var(--burst-dot-size);
2678
+ height: var(--burst-dot-size);
2679
+ border-radius: 9999px;
2680
+ background-color: var(--palette-dot, currentColor);
2681
+ opacity: 0;
2682
+ /* Thrown as the ring opens, not with it. */
2683
+ animation: sable-burst-dot calc(var(--motion-duration-slower) * 1.3 * var(--motion-expressive, 1))
2684
+ var(--motion-ease-decelerate) calc(var(--motion-duration-fast) * var(--motion-expressive, 1)) forwards;
2685
+ }
2686
+ /* A thrown glyph (Burst's `particle`) instead of a disc: the emoji itself,
2687
+ sized by the same --burst-dot-size, so a reaction sprays copies of what was
2688
+ chosen. Counter-rotated on its way out so it travels upright, and it fades
2689
+ at the end of its flight rather than shrinking to a point. */
2690
+ @keyframes sable-burst-particle {
2691
+ 0% {
2692
+ opacity: 1;
2693
+ transform: rotate(var(--burst-dot-angle)) translateX(calc(var(--burst-size) * 0.3))
2694
+ rotate(calc(var(--burst-dot-angle) * -1)) scale(0.4);
2695
+ }
2696
+ 60% {
2697
+ opacity: 1;
2698
+ transform: rotate(var(--burst-dot-angle)) translateX(calc(var(--burst-size) * var(--burst-dot-reach) * 0.9))
2699
+ rotate(calc(var(--burst-dot-angle) * -1)) scale(1);
2700
+ }
2701
+ 100% {
2702
+ opacity: 0;
2703
+ transform: rotate(var(--burst-dot-angle)) translateX(calc(var(--burst-size) * var(--burst-dot-reach)))
2704
+ rotate(calc(var(--burst-dot-angle) * -1)) scale(0.7);
2705
+ }
2706
+ }
2707
+ .sable-burst-dot[data-particle] {
2708
+ display: grid;
2709
+ place-items: center;
2710
+ width: auto;
2711
+ height: auto;
2712
+ border-radius: 0;
2713
+ background-color: transparent;
2714
+ font-size: var(--burst-dot-size);
2715
+ line-height: 1;
2716
+ animation-name: sable-burst-particle;
2717
+ }
2718
+
2478
2719
  /* --------------------------------------------------------------------------
2479
2720
  Loader recipes — looping indicators. Durations scale with --motion-scale, so
2480
2721
  the policy switch freezes them to a static first frame.
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { T as ThemeManifest } from './_contract-CkqXDVww.js';
3
+ import { T as ThemeManifest } from './_contract-CDa9-NdB.js';
4
4
 
5
5
  declare const SABLE_THEME_ATTRIBUTE: "data-sable-theme";
6
6
  declare const DEFAULT_THEME_ID: string;
@@ -312,6 +312,17 @@ var PALETTE_SLOT_TOKENS = [
312
312
  "palette-solid-ink"
313
313
  ];
314
314
  var DERIVED_EDGE_TOKENS = ["border-floating"];
315
+ var FIELD_TOKENS = ["field", "field-border"];
316
+ var APP_SHELL_TOKENS = ["shell-ground"];
317
+ var MARK_TOKENS = [
318
+ "destructive-mark",
319
+ "success-mark",
320
+ "tone-warning-mark",
321
+ "tone-info-mark",
322
+ "tone-1-mark",
323
+ "tone-2-mark",
324
+ "tone-3-mark"
325
+ ];
315
326
  var TYPE_UI_TOKENS = [
316
327
  "type-ui-md-size",
317
328
  "type-ui-md-weight",
@@ -323,10 +334,13 @@ var TYPE_UI_TOKENS = [
323
334
  "type-ui-micro-weight"
324
335
  ];
325
336
  export {
337
+ APP_SHELL_TOKENS,
326
338
  ART_TOKENS,
327
339
  DENSITY_TOKENS,
328
340
  DERIVED_EDGE_TOKENS,
341
+ FIELD_TOKENS,
329
342
  LAYERING_TOKENS,
343
+ MARK_TOKENS,
330
344
  MOTION_TOKENS,
331
345
  PALETTE_SLOT_TOKENS,
332
346
  PALETTE_TOKENS,
@@ -128,6 +128,15 @@
128
128
  --tone-1-foreground: #ffffff;
129
129
  --tone-info-foreground: #ffffff;
130
130
  --tone-warning-foreground: #ffffff;
131
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
132
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
133
+ --theme-destructive-mark: oklch(62.0% 0.234 22.0);
134
+ --theme-success-mark: oklch(70.0% 0.130 173.0);
135
+ --theme-tone-warning-mark: oklch(71.0% 0.156 52.0);
136
+ --theme-tone-info-mark: oklch(63.0% 0.130 250.0);
137
+ --theme-tone-1-mark: oklch(70.0% 0.117 173.0);
138
+ --theme-tone-2-mark: oklch(62.0% 0.143 300.0);
139
+ --theme-tone-3-mark: oklch(60.0% 0.000 0.0);
131
140
  --highlight-foreground: #000000;
132
141
  --overlay: oklch(7% 0 0 / 0.55);
133
142
  --overlay-foreground: #ffffff;
@@ -211,6 +220,15 @@
211
220
  --tone-1-foreground: oklch(13% 0 0);
212
221
  --tone-info-foreground: oklch(13% 0 0);
213
222
  --tone-warning-foreground: oklch(13% 0 0);
223
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
224
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
225
+ --theme-destructive-mark: oklch(65.0% 0.218 22.0);
226
+ --theme-success-mark: oklch(74.0% 0.137 173.0);
227
+ --theme-tone-warning-mark: oklch(80.0% 0.129 52.0);
228
+ --theme-tone-info-mark: oklch(76.0% 0.114 250.0);
229
+ --theme-tone-1-mark: oklch(76.0% 0.114 173.0);
230
+ --theme-tone-2-mark: oklch(76.0% 0.137 300.0);
231
+ --theme-tone-3-mark: oklch(80.0% 0.000 0.0);
214
232
  --highlight-foreground: #ffffff;
215
233
  --overlay: oklch(0% 0 0 / 0.7);
216
234
  --overlay-foreground: #ffffff;
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /**
4
4
  * Mono Editorial — a Sable theme. Concrete token values live in
@@ -127,7 +127,16 @@ var NON_TEXT_PAIRS = {
127
127
  // The sidebar family repeats the set against its own surface, which is exactly
128
128
  // why it exists as a family (see token-docs: "tuned against `sidebar`").
129
129
  "sidebar-border": { surfaces: ["sidebar"], tier: "hairline" },
130
- "sidebar-ring": { surfaces: ["sidebar"], tier: "focus" }
130
+ "sidebar-ring": { surfaces: ["sidebar"], tier: "focus" },
131
+ // Status and tone colours at graphic strength, on the surfaces a meter, dot
132
+ // or chart sits on. Bundled themes declare these as `--theme-*-mark` hooks.
133
+ "destructive-mark": { surfaces: ["background", "card"], tier: "graphic" },
134
+ "success-mark": { surfaces: ["background", "card"], tier: "graphic" },
135
+ "tone-warning-mark": { surfaces: ["background", "card"], tier: "graphic" },
136
+ "tone-info-mark": { surfaces: ["background", "card"], tier: "graphic" },
137
+ "tone-1-mark": { surfaces: ["background", "card"], tier: "graphic" },
138
+ "tone-2-mark": { surfaces: ["background", "card"], tier: "graphic" },
139
+ "tone-3-mark": { surfaces: ["background", "card"], tier: "graphic" }
131
140
  };
132
141
  function evaluateNonTextContrast(mark, surface, tier = "focus") {
133
142
  const ratio = contrastRatio(mark, surface);
@@ -140,6 +149,10 @@ function evaluateNonTextContrast(mark, surface, tier = "focus") {
140
149
  if (tier === "control") {
141
150
  return { ratio, lc, wcagRatioPasses, passes: wcagRatioPasses, basis: wcagRatioPasses ? "wcag" : "none" };
142
151
  }
152
+ if (tier === "graphic") {
153
+ const passes = ratio >= NON_TEXT_HARD_FLOOR;
154
+ return { ratio, lc, wcagRatioPasses, passes, basis: wcagRatioPasses ? "wcag" : passes ? "visibility" : "none" };
155
+ }
143
156
  if (wcagRatioPasses) return { ratio, lc, wcagRatioPasses, passes: true, basis: "wcag" };
144
157
  if (Math.abs(lc) >= NON_TEXT_PERCEPTUAL_FLOOR && ratio >= NON_TEXT_HARD_FLOOR) {
145
158
  return { ratio, lc, wcagRatioPasses, passes: true, basis: "perceptual" };
@@ -198,6 +211,38 @@ function inkPolarity(color, inks) {
198
211
  };
199
212
  return inks.reduce((best, ink) => cost(ink) < cost(best) ? ink : best);
200
213
  }
214
+ var MARK_FLOOR = NON_TEXT_HARD_FLOOR;
215
+ var MARK_NEUTRAL_CHROMA = 0.03;
216
+ function markLightness(h) {
217
+ const hue = (h % 360 + 360) % 360;
218
+ if (hue < 38 || hue >= 350) return 0.62;
219
+ if (hue < 70) return 0.71;
220
+ if (hue < 110) return 0.78;
221
+ if (hue < 190) return 0.7;
222
+ if (hue < 268) return 0.63;
223
+ if (hue < 300) return 0.6;
224
+ return 0.62;
225
+ }
226
+ function markFor(fill, mode, surfaces = []) {
227
+ const neutral = fill.c < MARK_NEUTRAL_CHROMA;
228
+ const hue = (fill.h % 360 + 360) % 360;
229
+ let l = fill.l;
230
+ if (mode === "light") l = neutral ? Math.max(l, 0.6) : Math.max(l, markLightness(hue));
231
+ else if (!neutral && (hue < 38 || hue >= 350)) l = Math.max(l, 0.65);
232
+ const lift = mode === "light" ? 1.3 : 1.15;
233
+ const chromaAt = (lightness) => {
234
+ if (neutral) return fill.c;
235
+ const max = maxChromaAt(lightness, fill.h);
236
+ return Math.max(Math.min(fill.c, max), Math.min(max * FILL_GAMUT_SAFETY, fill.c * lift));
237
+ };
238
+ let mark = { ...fill, l, c: chromaAt(l) };
239
+ const reads = (m) => surfaces.every((s) => contrastRatio(linearOf(m), linearOf(s)) >= MARK_FLOOR);
240
+ for (let i = 0; i < 60 && !reads(mark); i++) {
241
+ l = Math.min(0.98, Math.max(0.05, l + (mode === "light" ? -0.01 : 0.01)));
242
+ mark = { ...mark, l, c: neutral ? fill.c : Math.min(mark.c, maxChromaAt(l, fill.h)) };
243
+ }
244
+ return mark;
245
+ }
201
246
  function linearRgbToOklch([r, g, b]) {
202
247
  const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
203
248
  const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
@@ -257,6 +302,7 @@ export {
257
302
  HAIRLINE_VISIBILITY_FLOOR,
258
303
  LABELLED_FILLS,
259
304
  LABEL_CONTRAST_RULE,
305
+ MARK_FLOOR,
260
306
  NON_TEXT_FLOOR,
261
307
  NON_TEXT_HARD_FLOOR,
262
308
  NON_TEXT_PAIRS,
@@ -280,6 +326,7 @@ export {
280
326
  linearRgbToOklch,
281
327
  linearToSrgb,
282
328
  luminance,
329
+ markFor,
283
330
  maxChromaAt,
284
331
  oklchToLinearRgb,
285
332
  parseColor,
@@ -184,6 +184,15 @@
184
184
  --tone-1-foreground: oklch(100% 0 0);
185
185
  --tone-info-foreground: oklch(100% 0 0);
186
186
  --tone-warning-foreground: oklch(100% 0 0);
187
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
188
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
189
+ --theme-destructive-mark: oklch(62.0% 0.221 25.0);
190
+ --theme-success-mark: oklch(70.0% 0.130 165.0);
191
+ --theme-tone-warning-mark: oklch(71.0% 0.156 52.0);
192
+ --theme-tone-info-mark: oklch(63.0% 0.169 250.0);
193
+ --theme-tone-1-mark: oklch(62.0% 0.195 309.0);
194
+ --theme-tone-2-mark: oklch(60.0% 0.182 285.0);
195
+ --theme-tone-3-mark: oklch(70.0% 0.091 130.0);
187
196
  --highlight-foreground: oklch(100% 0 0);
188
197
  --overlay: oklch(14.1% 0.018 70.5);
189
198
  --overlay-foreground: oklch(100% 0 0);
@@ -272,6 +281,15 @@
272
281
  --tone-1-foreground: oklch(14.1% 0.018 70.5);
273
282
  --tone-info-foreground: oklch(14.1% 0.018 70.5);
274
283
  --tone-warning-foreground: oklch(14.1% 0.018 70.5);
284
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
285
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
286
+ --theme-destructive-mark: oklch(65.0% 0.184 25.0);
287
+ --theme-success-mark: oklch(74.0% 0.137 165.0);
288
+ --theme-tone-warning-mark: oklch(78.0% 0.149 60.0);
289
+ --theme-tone-info-mark: oklch(75.5% 0.126 250.0);
290
+ --theme-tone-1-mark: oklch(68.0% 0.161 309.0);
291
+ --theme-tone-2-mark: oklch(70.0% 0.137 285.0);
292
+ --theme-tone-3-mark: oklch(70.0% 0.103 130.0);
275
293
  --highlight-foreground: oklch(100% 0 0);
276
294
  --overlay: oklch(14.1% 0.018 70.5);
277
295
  --overlay-foreground: oklch(100% 0 0);
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /**
4
4
  * Ember — a Sable theme. Concrete token values live in
@@ -1,4 +1,4 @@
1
- export { A as AnyThemeId, D as DEFAULT_THEME_ID, S as SABLE_COLOR_STORAGE_KEY, a as SABLE_THEME_ATTRIBUTE, b as SABLE_THEME_STORAGE_KEY, c as SableColorMode, d as SableThemeContextValue, e as SableThemePreference, f as SableThemeProvider, g as SableThemeProviderProps, T as ThemeId, h as applySableColorMode, i as applySableTheme, j as buildThemeManifestById, k as defaultThemeId, l as featuredThemeManifests, m as getThemeManifest, n as isKnownThemeId, o as isThemeId, t as themeIds, p as themeManifestById, q as themeManifests, u as useSableTheme } from '../theme-provider-CdSicAad.js';
1
+ export { A as AnyThemeId, D as DEFAULT_THEME_ID, S as SABLE_COLOR_STORAGE_KEY, a as SABLE_THEME_ATTRIBUTE, b as SABLE_THEME_STORAGE_KEY, c as SableColorMode, d as SableThemeContextValue, e as SableThemePreference, f as SableThemeProvider, g as SableThemeProviderProps, T as ThemeId, h as applySableColorMode, i as applySableTheme, j as buildThemeManifestById, k as defaultThemeId, l as featuredThemeManifests, m as getThemeManifest, n as isKnownThemeId, o as isThemeId, t as themeIds, p as themeManifestById, q as themeManifests, u as useSableTheme } from '../theme-provider-BydfM5Z0.js';
2
2
  export { atelierTheme } from './atelier/index.js';
3
3
  export { default as emberTheme } from './ember/index.js';
4
4
  export { default as meridianTheme } from './meridian/index.js';
@@ -7,4 +7,4 @@ export { default as prismTheme } from './prism/index.js';
7
7
  export { default as sableTheme } from './sable/index.js';
8
8
  export { default as verdantTheme } from './verdant/index.js';
9
9
  import 'react';
10
- import '../_contract-CkqXDVww.js';
10
+ import '../_contract-CDa9-NdB.js';
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /**
4
4
  * Meridian — a Sable theme. Concrete token values live in
@@ -166,6 +166,15 @@
166
166
  --tone-1-foreground: oklch(94.6% 0.0083 91.48);
167
167
  --tone-info-foreground: oklch(94.6% 0.0083 91.48);
168
168
  --tone-warning-foreground: oklch(94.6% 0.0083 91.48);
169
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
170
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
171
+ --theme-destructive-mark: oklch(62.0% 0.246 25.0);
172
+ --theme-success-mark: oklch(70.0% 0.130 165.0);
173
+ --theme-tone-warning-mark: oklch(71.0% 0.156 52.0);
174
+ --theme-tone-info-mark: oklch(63.0% 0.169 250.0);
175
+ --theme-tone-1-mark: oklch(62.0% 0.195 309.0);
176
+ --theme-tone-2-mark: oklch(60.0% 0.182 285.0);
177
+ --theme-tone-3-mark: oklch(70.0% 0.091 130.0);
169
178
  --highlight-foreground: oklch(99% 0.004 91.5);
170
179
  --overlay: oklch(22.46% 0.0094 107.13);
171
180
  --overlay-foreground: oklch(94.3% 0.0042 91.45);
@@ -255,6 +264,15 @@
255
264
  --tone-1-foreground: oklch(22.46% 0.0094 107.13);
256
265
  --tone-info-foreground: oklch(22.46% 0.0094 107.13);
257
266
  --tone-warning-foreground: oklch(22.46% 0.0094 107.13);
267
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
268
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
269
+ --theme-destructive-mark: oklch(65.0% 0.231 25.0);
270
+ --theme-success-mark: oklch(75.5% 0.137 165.0);
271
+ --theme-tone-warning-mark: oklch(78.0% 0.149 60.0);
272
+ --theme-tone-info-mark: oklch(76.5% 0.122 250.0);
273
+ --theme-tone-1-mark: oklch(68.0% 0.161 309.0);
274
+ --theme-tone-2-mark: oklch(70.0% 0.137 285.0);
275
+ --theme-tone-3-mark: oklch(70.0% 0.103 130.0);
258
276
  --highlight-foreground: oklch(99% 0.004 91.5);
259
277
  --overlay: oklch(22.46% 0.0094 107.13);
260
278
  --overlay-foreground: oklch(94.3% 0.0042 91.45);
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /** Original Sable preset; no third-party artwork or reference-site code. */
4
4
  declare const poppyTheme: ThemeManifest;
@@ -97,6 +97,15 @@
97
97
  --tone-1-foreground: oklch(100.00000% 0.000000 89.8756);
98
98
  --tone-info-foreground: oklch(100.00000% 0.000000 89.8756);
99
99
  --tone-warning-foreground: oklch(100.00000% 0.000000 89.8756);
100
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
101
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
102
+ --theme-destructive-mark: oklch(62.0% 0.238 13.5);
103
+ --theme-success-mark: oklch(70.0% 0.111 159.0);
104
+ --theme-tone-warning-mark: oklch(76.0% 0.132 75.1);
105
+ --theme-tone-info-mark: oklch(63.0% 0.152 253.8);
106
+ --theme-tone-1-mark: oklch(62.0% 0.196 344.9);
107
+ --theme-tone-2-mark: oklch(62.0% 0.208 301.6);
108
+ --theme-tone-3-mark: oklch(63.0% 0.065 265.7);
100
109
  --highlight-foreground: oklch(27.91553% 0.070219 323.8141);
101
110
  --overlay: oklch(23.10300% 0.056738 321.2844);
102
111
  --overlay-foreground: oklch(100.00000% 0.000000 89.8756);
@@ -198,6 +207,15 @@
198
207
  --tone-1-foreground: oklch(27.91553% 0.070219 323.8141);
199
208
  --tone-info-foreground: oklch(27.91553% 0.070219 323.8141);
200
209
  --tone-warning-foreground: oklch(27.91553% 0.070219 323.8141);
210
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
211
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
212
+ --theme-destructive-mark: oklch(80.1% 0.118 6.9);
213
+ --theme-success-mark: oklch(83.1% 0.092 158.2);
214
+ --theme-tone-warning-mark: oklch(86.6% 0.136 86.7);
215
+ --theme-tone-info-mark: oklch(85.2% 0.074 252.9);
216
+ --theme-tone-1-mark: oklch(82.6% 0.111 343.4);
217
+ --theme-tone-2-mark: oklch(81.8% 0.108 306.5);
218
+ --theme-tone-3-mark: oklch(82.6% 0.068 270.3);
201
219
  }
202
220
 
203
221
  /* Art direction for generated imagery (GradientArt; ART_TOKENS in
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /** Original Sable preset; no third-party artwork or reference-site code. */
4
4
  declare const prismTheme: ThemeManifest;
@@ -97,6 +97,15 @@
97
97
  --tone-1-foreground: oklch(100.00000% 0.000000 89.8756);
98
98
  --tone-info-foreground: oklch(100.00000% 0.000000 89.8756);
99
99
  --tone-warning-foreground: oklch(100.00000% 0.000000 89.8756);
100
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
101
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
102
+ --theme-destructive-mark: oklch(62.0% 0.238 19.5);
103
+ --theme-success-mark: oklch(70.0% 0.105 166.9);
104
+ --theme-tone-warning-mark: oklch(75.0% 0.134 73.8);
105
+ --theme-tone-info-mark: oklch(63.0% 0.181 259.8);
106
+ --theme-tone-1-mark: oklch(62.0% 0.183 343.5);
107
+ --theme-tone-2-mark: oklch(60.0% 0.218 300.0);
108
+ --theme-tone-3-mark: oklch(63.0% 0.056 257.4);
100
109
  --highlight-foreground: oklch(26.55994% 0.047330 255.4106);
101
110
  --overlay: oklch(21.14912% 0.029163 257.5277);
102
111
  --overlay-foreground: oklch(100.00000% 0.000000 89.8756);
@@ -194,6 +203,15 @@
194
203
  --tone-1-foreground: oklch(25.20350% 0.047984 259.9119);
195
204
  --tone-info-foreground: oklch(25.20350% 0.047984 259.9119);
196
205
  --tone-warning-foreground: oklch(25.20350% 0.047984 259.9119);
206
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
207
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
208
+ --theme-destructive-mark: oklch(79.5% 0.121 8.7);
209
+ --theme-success-mark: oklch(82.2% 0.098 165.8);
210
+ --theme-tone-warning-mark: oklch(84.7% 0.124 84.2);
211
+ --theme-tone-info-mark: oklch(80.6% 0.097 259.5);
212
+ --theme-tone-1-mark: oklch(80.4% 0.117 341.7);
213
+ --theme-tone-2-mark: oklch(77.3% 0.135 301.0);
214
+ --theme-tone-3-mark: oklch(82.0% 0.053 256.5);
197
215
  }
198
216
 
199
217
  /* Art direction for generated imagery (GradientArt; ART_TOKENS in
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /**
4
4
  * Sable — the default theme. Concrete token values live in
@@ -280,6 +280,15 @@
280
280
  --tone-2-foreground: var(--zinc-50);
281
281
  --tone-1-foreground: var(--zinc-50);
282
282
  --tone-warning-foreground: var(--zinc-50);
283
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
284
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
285
+ --theme-destructive-mark: oklch(62.0% 0.244 22.0);
286
+ --theme-success-mark: oklch(70.0% 0.131 173.0);
287
+ --theme-tone-warning-mark: oklch(71.0% 0.169 52.0);
288
+ --theme-tone-info-mark: oklch(63.0% 0.178 250.0);
289
+ --theme-tone-1-mark: oklch(62.0% 0.269 309.0);
290
+ --theme-tone-2-mark: oklch(60.0% 0.227 285.0);
291
+ --theme-tone-3-mark: oklch(70.0% 0.131 173.0);
283
292
  --tone-info-foreground: var(--zinc-50);
284
293
  --highlight-foreground: var(--zinc-50);
285
294
 
@@ -463,6 +472,15 @@
463
472
  --tone-2-foreground: var(--zinc-950);
464
473
  --tone-1-foreground: var(--zinc-950);
465
474
  --tone-warning-foreground: var(--zinc-950);
475
+ /* Graphic strength (MARK_TOKENS): meters, bars, dots, chart series and soft tints.
476
+ The same hues lifted and saturated; held to 2:1 on the page, not a text ratio. */
477
+ --theme-destructive-mark: oklch(65.0% 0.231 25.0);
478
+ --theme-success-mark: oklch(78.0% 0.157 168.0);
479
+ --theme-tone-warning-mark: oklch(82.0% 0.132 65.0);
480
+ --theme-tone-info-mark: oklch(76.0% 0.144 235.0);
481
+ --theme-tone-1-mark: oklch(62.0% 0.295 318.0);
482
+ --theme-tone-2-mark: oklch(72.0% 0.151 285.0);
483
+ --theme-tone-3-mark: oklch(78.0% 0.157 168.0);
466
484
  --tone-info-foreground: var(--zinc-950);
467
485
  --highlight-foreground: var(--zinc-50);
468
486
  --overlay: var(--zinc-950);
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CkqXDVww.js';
1
+ import { T as ThemeManifest } from '../../_contract-CDa9-NdB.js';
2
2
 
3
3
  /**
4
4
  * Verdant — a Sable theme. Concrete token values live in