@rt-tools/ui-kit 0.0.19 → 0.0.20

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 (69) hide show
  1. package/fesm2022/rt-tools-ui-kit.mjs +205 -80
  2. package/fesm2022/rt-tools-ui-kit.mjs.map +1 -1
  3. package/package.json +1 -1
  4. package/rt-tools-ui-kit-0.0.20.tgz +0 -0
  5. package/src/lib/ui-kit/action-bar/components/bar/rtui-action-bar.component.scss +18 -18
  6. package/src/lib/ui-kit/action-bar/components/container/rtui-action-bar-container.component.scss +5 -7
  7. package/src/lib/ui-kit/aside/components/container/aside-container.component.scss +1 -0
  8. package/src/lib/ui-kit/aside/components/error-notification/aside-error-box.component.scss +6 -6
  9. package/src/lib/ui-kit/aside/components/panel/aside-panel.component.scss +25 -32
  10. package/src/lib/ui-kit/aside/stories/aside-component/test-aside.component.scss +1 -1
  11. package/src/lib/ui-kit/buttons/icon-round/rtui-round-icon-button.component.scss +4 -4
  12. package/src/lib/ui-kit/buttons/multi-button/rtui-multi-button.component.scss +7 -7
  13. package/src/lib/ui-kit/checkbox/rtui-checkbox.component.scss +10 -10
  14. package/src/lib/ui-kit/checkbox/stories/component/test-checkbox.component.scss +2 -2
  15. package/src/lib/ui-kit/dynamic-selectors/components/actions/rtui-dynamic-selector-list-actions.component.scss +2 -2
  16. package/src/lib/ui-kit/dynamic-selectors/components/dynamic-selector/rtui-dynamic-selector.component.scss +3 -3
  17. package/src/lib/ui-kit/dynamic-selectors/components/multi-selector-popup/rtui-multi-selector-popup.component.scss +17 -17
  18. package/src/lib/ui-kit/dynamic-selectors/components/placeholder/rtui-dynamic-selector-placeholder.component.scss +3 -4
  19. package/src/lib/ui-kit/dynamic-selectors/components/selected-list/rtui-dynamic-selector-selected-list.component.scss +2 -2
  20. package/src/lib/ui-kit/dynamic-selectors/strories/component/input/test-dynamic-input.component.scss +2 -3
  21. package/src/lib/ui-kit/dynamic-selectors/strories/component/selector/test-selector.component.scss +4 -5
  22. package/src/lib/ui-kit/file-uploader/rtui-file-upload.component.scss +5 -5
  23. package/src/lib/ui-kit/file-uploader/stories/component/test-file-upload.component.scss +1 -1
  24. package/src/lib/ui-kit/header/header.component.scss +1 -0
  25. package/src/lib/ui-kit/header/stories/component/test-header.component.scss +3 -3
  26. package/src/lib/ui-kit/image-uploader/image-uploader/rtui-image-upload.component.scss +5 -5
  27. package/src/lib/ui-kit/image-uploader/stories/component/test-image-upload.component.scss +2 -2
  28. package/src/lib/ui-kit/info-badge/info-badge.component.scss +20 -19
  29. package/src/lib/ui-kit/info-badge/stories/component/test-info-badge/test-info-badge.component.scss +1 -1
  30. package/src/lib/ui-kit/modal/modal.component.scss +5 -5
  31. package/src/lib/ui-kit/popover/rtui-popover-container.component.scss +2 -3
  32. package/src/lib/ui-kit/scrollable/scrollable-container.component.scss +3 -5
  33. package/src/lib/ui-kit/side-menu/menu/rtui-side-menu.component.scss +25 -25
  34. package/src/lib/ui-kit/side-menu/menu-sub-item/rtui-side-menu-sub-item.component.scss +14 -14
  35. package/src/lib/ui-kit/side-menu/stories/component/test-side-menu-wrapper.component.scss +10 -10
  36. package/src/lib/ui-kit/snack-bar/snack-bar.component.scss +9 -9
  37. package/src/lib/ui-kit/snack-bar/stories/component/test-snack-bar.component.scss +3 -3
  38. package/src/lib/ui-kit/spinner/spinner.component.scss +10 -13
  39. package/src/lib/ui-kit/table/components/clear-search-button/rtui-clear-button.component.scss +5 -5
  40. package/src/lib/ui-kit/table/components/pagination-view/rtui-pagination.component.scss +14 -22
  41. package/src/lib/ui-kit/table/components/table-base-cell/table-base-cell.component.scss +8 -9
  42. package/src/lib/ui-kit/table/components/table-config-aside/rt-table-config-aside.component.scss +1 -1
  43. package/src/lib/ui-kit/table/components/table-container/table-container.component.scss +16 -14
  44. package/src/lib/ui-kit/table/components/table-header-cell/table-header-cell.component.scss +6 -7
  45. package/src/lib/ui-kit/table/components/table-header-filter-cell/table-header-filter-cell.component.scss +3 -3
  46. package/src/lib/ui-kit/table/dynamic-list.component.scss +2 -2
  47. package/src/lib/ui-kit/table/stories/dynamic-list/test-dynamic-list.component.scss +1 -1
  48. package/src/lib/ui-kit/table/stories/pagination/test-pagination-component.scss +4 -4
  49. package/src/lib/ui-kit/table/stories/table/test-table-component.scss +1 -1
  50. package/src/lib/ui-kit/toggle/rtui-toggle.component.scss +15 -21
  51. package/src/lib/ui-kit/toggle/stories/component/test-toggle.component.scss +2 -2
  52. package/src/lib/ui-kit/toolbar/toolbar.component.scss +5 -10
  53. package/src/styles/TOKENS.md +95 -2
  54. package/src/styles/base/_base.scss +4 -5
  55. package/src/styles/base/_color-scheme.scss +86 -0
  56. package/src/styles/base/_mixin.scss +12 -15
  57. package/src/styles/base/_tokens.scss +139 -99
  58. package/src/styles/base/_variables.scss +5 -11
  59. package/src/styles/color-scheme.spec.ts +236 -0
  60. package/src/styles/components/_button.scss +32 -24
  61. package/src/styles/components/_dynamic-selectors.scss +9 -10
  62. package/src/styles/components/_form.scss +8 -13
  63. package/src/styles/components/_material-bridge.scss +30 -0
  64. package/src/styles/components/_rtui_button.scss +5 -5
  65. package/src/styles/components/_table.scss +23 -39
  66. package/src/styles/main.scss +4 -0
  67. package/styles/tokens.css +79 -101
  68. package/types/rt-tools-ui-kit.d.ts +55 -7
  69. package/rt-tools-ui-kit-0.0.19.tgz +0 -0
@@ -18,11 +18,104 @@ Quick facts:
18
18
  fallback chains. Opt out: `@use '...main' with ($tokens-use-material: false)`.
19
19
  - Accent roles `{primary,success,warning,danger,info,neutral}`,
20
20
  steps `{subtle,solid,hover,disabled}` (simplified vs GMT).
21
+ - Accent indirection: the accent semantic tier derives from `--rt-color-{role}-{0..100}`
22
+ ramps (`{primary,info,success,warning,danger,brand}`). Custom brand palettes
23
+ override only those rows — see **Custom color schemes** below.
21
24
  - Foundations: `--rt-spacing-{0..64}` (px-named, rem values), `--rt-radius-*`,
22
25
  `--rt-font-*`, `--rt-shadow-*`, `--rt-transition-*`, `--rt-z-index-*`.
23
- - Legacy `--clr-*` variables are emitted as **deprecated aliases**.
24
26
  - Prebuilt CSS for non-sass consumers: `dist/ui-kit/styles/tokens.css`
25
27
  (`pnpm run build:tokens`).
26
28
  - Figma parity: collections `core` (`rt/color/*`) and `theme` (`rt/{bg,text,icon,border}/*`,
27
29
  Light/Dark modes) in the “RT-Tools UI Kit” file mirror these names 1:1.
28
- - App-defined (never set by the kit): `--clr-avalon`, `--font-default`, mat theme colors.
30
+ - App-defined (never set by the kit): `--font-default`, mat theme colors.
31
+
32
+ ## Component theming API (Tier 3 contract)
33
+
34
+ Tier-3 vars are split into a **public theming API** and **internal implementation details**.
35
+ Only the public set is a compatibility promise; internal vars may be renamed or stop being
36
+ emitted in the next major release.
37
+
38
+ **Public** (override these from your app):
39
+
40
+ 1. Every var matching `--rt-<component>-*-{color,background-color,bg,shadow,indicator}` —
41
+ the color surface of each component.
42
+ 2. Documented size hooks proven by consumers:
43
+ `--rt-table-row-height`, `--rt-toolbar-body-height`, `--rt-toolbar-body-mobile-height`,
44
+ `--rt-aside-error-box-height`, `--rt-aside-host-width`,
45
+ `--rt-image-upload-host-min-height`, `--rt-image-upload-image-container-image-max-height`.
46
+
47
+ **Internal** (everything else): layout paddings/margins/gaps/font-sizes generated from SCSS maps.
48
+ They currently _are_ emitted (≈380 vars total, ~14% actually themed by consumers) — in the next
49
+ major the internal set stops being emitted and gets inlined into rules.
50
+
51
+ ### `:root` vs `:host` emission — override semantics
52
+
53
+ - Vars emitted at **`:root`** (global stylesheets + `ViewEncapsulation.None` components like
54
+ aside-panel) are overridable from any ancestor scope: `.dark-mode { --rt-aside-host-background-color: …; }`.
55
+ - Vars emitted at **`:host`** are set on the element itself and **win over inherited values** —
56
+ consumers must target the element (`rtui-toolbar { --rt-toolbar-body-height: … !important; }`).
57
+ This asymmetry is why some consumers need `!important` for toolbar/toggle but not for aside/table.
58
+ - Planned unification (major): emit defaults via `var(--override, default)` indirection so all
59
+ components are ancestor-overridable without `!important`.
60
+
61
+ ## Buttons: legacy vs rtui
62
+
63
+ `.c-button` (\_button.scss) is **deprecated**; `.rtui-btn` (\_rtui_button.scss) is the system.
64
+ Both stay until the next major because consumers apply `.c-button` classes and override
65
+ `--rt-button-*` directly. Migration map:
66
+
67
+ | legacy `.c-button` | `.rtui-btn` |
68
+ | ------------------------- | --------------------------------------------------------------------- |
69
+ | `--fill-green` / `-light` | `rtui-btn-success` / `-light` |
70
+ | `--fill-red` / `-light` | `rtui-btn-error` / `-light` |
71
+ | `--fill-blue` | `rtui-btn-accent-light` |
72
+ | `--fill-base/black/gray` | `rtui-btn-secondary` (+`-light`) |
73
+ | `--outline-{blue,base}` | `rtui-btn-{accent,secondary}-outline` |
74
+ | `--txt-*`, `--fab` | no equivalent yet — needs a text/icon appearance in `.rtui-btn` first |
75
+ | `--size-{sm,md,l}` | `rtui-btn-{sm,md,lg}` (+`-full`) |
76
+
77
+ ## Material bridge
78
+
79
+ All **global** Material/CDK overrides live in `styles/components/_material-bridge.scss`
80
+ (single file to review on a Material upgrade). Component-scoped piercings stay with their
81
+ component; the bridge header keeps the inventory of those locations.
82
+
83
+ ## Custom color schemes (brand palettes)
84
+
85
+ The accent semantic tier never hardcodes color — it derives from an indirection layer,
86
+ the **accent-role ramps** `--rt-color-{role}-{0..100}` for
87
+ `{primary, info, success, warning, danger, brand}`. A custom brand palette overrides
88
+ **only** those rows; the kit derives `--rt-{bg,text,icon,border}-accent-*`,
89
+ hover/subtle/disabled and `--rt-border-focus` from them. The block is scoped to
90
+ `[data-rt-scheme="<name>"]` on `<html>`, set raw → it wins over `--mat-sys-*`.
91
+
92
+ ```scss
93
+ @use '@rt-tools/ui-kit/src/styles/main' as rt;
94
+ @include rt.color-scheme(
95
+ 'teal',
96
+ (
97
+ primary: (
98
+ 20: #b3e3e1,
99
+ 40: #5cb8b5,
100
+ 60: #1a9d99,
101
+ 100: #008582,
102
+ ),
103
+ brand: (
104
+ 20: #e8e8e8,
105
+ 100: #008582,
106
+ ),
107
+ )
108
+ );
109
+ ```
110
+
111
+ ```typescript
112
+ // runtime twin (browser-only); prefer the Sass path for SSR/brand-critical schemes
113
+ theme.registerColorScheme('teal', { primary: { 100: '#008582' /* … */ } });
114
+ theme.setColorScheme('teal'); // data-rt-scheme="teal"; persisted to rt-color-scheme
115
+ theme.setColorScheme(null); // back to the default palette
116
+ ```
117
+
118
+ - Orthogonal to light/dark (one ramp per role serves both modes).
119
+ - Δ0: with no scheme the accent layer is byte-for-byte the historical palette
120
+ (regression-tested in `styles/color-scheme.spec.ts`); Sass↔JS generator parity is tested too.
121
+ - Full guide: Storybook **Foundation/Theming/Custom color schemes** (`docs/ColorSchemes.mdx`).
@@ -1,6 +1,6 @@
1
1
  $palette: (
2
2
  white: (
3
- 100: #ffffff,
3
+ 100: #fff,
4
4
  ),
5
5
  gray: (
6
6
  5: #f5f6f8,
@@ -10,7 +10,7 @@ $palette: (
10
10
  ),
11
11
  black: (
12
12
  10: #f3f3f3,
13
- 15: #eeeeee,
13
+ 15: #eee,
14
14
  20: #e0e0e0,
15
15
  30: #b2cbca,
16
16
  40: #a3a3a3,
@@ -55,10 +55,9 @@ $palette: (
55
55
 
56
56
  // NOTE: the $palette map above is kept for backwards compatibility (consumers may @use it).
57
57
  // All CSS custom property emission lives in base/_tokens.scss:
58
- // --rt-color-* primitives, --rt-{bg,text,icon,border}-* semantic, foundations,
59
- // and deprecated --clr-* aliases.
58
+ // --rt-color-* primitives, --rt-{bg,text,icon,border}-* semantic, and foundations.
60
59
 
61
60
  :root {
62
61
  // Buttons
63
- --rt-button-box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.12), 0 1px 18px 0 rgba(0, 0, 0, 0.14);
62
+ --rt-button-box-shadow: 0 3px 5px -1px rgb(0 0 0 / 20%), 0 6px 10px 0 rgb(0 0 0 / 12%), 0 1px 18px 0 rgb(0 0 0 / 14%);
64
63
  }
@@ -0,0 +1,86 @@
1
+ @use 'sass:map';
2
+ @use 'sass:meta';
3
+ @use 'sass:list';
4
+ @use './tokens' as tokens;
5
+
6
+ /// ============================================================================
7
+ /// Custom color schemes (brand palettes)
8
+ /// ============================================================================
9
+ ///
10
+ /// A color scheme overrides ONLY the accent-role indirection rows
11
+ /// `--rt-color-{role}-{0..100}` (see `_tokens.scss`). The whole semantic accent
12
+ /// tier (`--rt-bg/text/icon/border-accent-*`, hover/subtle/disabled, `--rt-border-focus`)
13
+ /// re-derives from those rows — so a brand recolors with Δ0 effort and the
14
+ /// component contract (semantic token names) stays untouched.
15
+ ///
16
+ /// The emitted block is scoped to `[data-rt-scheme="<name>"]`, which the runtime
17
+ /// (`RtThemeService.setColorScheme`) toggles on `<html>`. Because the scheme sets
18
+ /// raw values, it overrides the default rows that carry the `--mat-sys-*` fallback
19
+ /// → the scheme wins over an active Material theme.
20
+ ///
21
+ /// Usage:
22
+ /// @use '@rt-tools/ui-kit/src/styles/main' as rt; // or the package's scss entry
23
+ /// @include rt.color-scheme('teal', (
24
+ /// primary: (20: #b3e3e1, 40: #5cb8b5, 60: #1a9d99, 100: #008582),
25
+ /// brand: (20: #e8e8e8, 100: #008582),
26
+ /// ));
27
+ ///
28
+ /// One tonal ramp per role serves both light and dark (M3-style): the mode picks
29
+ /// the tone via `light-dark()` inside the semantic tier — schemes never duplicate
30
+ /// that logic. `$modes` is accepted for forward-compatibility but a single ramp
31
+ /// already covers every mode.
32
+
33
+ /// Roles a scheme may override, with their valid tone steps (from the default ramps).
34
+ $known-roles: tokens.$accent-roles;
35
+
36
+ /// Validate a single role/ramp pair; @error with an actionable message on bad input.
37
+ @function _validate-role($name, $role, $ramp) {
38
+ @if not map.has-key($known-roles, $role) {
39
+ @error 'rt.color-scheme("#{$name}"): unknown role "#{$role}". Allowed roles: #{map.keys($known-roles)}.';
40
+ }
41
+
42
+ @if meta.type-of($ramp) != 'map' {
43
+ @error 'rt.color-scheme("#{$name}"): role "#{$role}" must be a map of (tone: color), got #{meta.type-of($ramp)}.';
44
+ }
45
+
46
+ @each $step, $value in $ramp {
47
+ @if meta.type-of($step) != 'number' or not _is-integer-step($step) {
48
+ @error 'rt.color-scheme("#{$name}"): role "#{$role}" tone "#{$step}" must be an integer 0–100.';
49
+ }
50
+ }
51
+
52
+ @return true;
53
+ }
54
+
55
+ /// Tone steps must be integers within 0–100.
56
+ @function _is-integer-step($step) {
57
+ @return $step >= 0 and $step <= 100 and ($step % 1 == 0);
58
+ }
59
+
60
+ /// Emit a named color scheme as a `[data-rt-scheme]` block (only raw `--rt-color-{role}-{N}` rows).
61
+ ///
62
+ /// @param {String} $name Scheme name, matched by `data-rt-scheme="<name>"`.
63
+ /// @param {Map} $roles Map of `role: (tone: color, …)`. Roles ⊆ #{map.keys($known-roles)}.
64
+ /// @param {List} $modes Reserved for forward-compat; one ramp already serves all modes.
65
+ @mixin color-scheme($name, $roles, $modes: (light, dark)) {
66
+ @if meta.type-of($name) != 'string' {
67
+ @error 'rt.color-scheme: $name must be a string, got #{meta.type-of($name)}.';
68
+ }
69
+
70
+ @if meta.type-of($roles) != 'map' or list.length(map.keys($roles)) == 0 {
71
+ @error 'rt.color-scheme("#{$name}"): $roles must be a non-empty map of (role: ramp).';
72
+ }
73
+
74
+ @each $role, $ramp in $roles {
75
+ $ok: _validate-role($name, $role, $ramp);
76
+ }
77
+
78
+ // `:root[...]` (0,2,0) outranks the default `:root` rows (0,1,0) regardless of source order.
79
+ :root[data-rt-scheme='#{$name}'] {
80
+ @each $role, $ramp in $roles {
81
+ @each $step, $value in $ramp {
82
+ --rt-color-#{$role}-#{$step}: #{$value};
83
+ }
84
+ }
85
+ }
86
+ }
@@ -1,12 +1,7 @@
1
+ @use 'sass:color';
1
2
  @use 'sass:math';
2
3
  @use './variables' as vars;
3
4
 
4
- // css clr var generator
5
- // #{generateCssVar(red, 100)}: #eb5055;
6
- @function generateCssClrVar($color, $saturate) {
7
- @return --#{vars.$styles-clr-prefix}-#{$color}-#{$saturate};
8
- }
9
-
10
5
  // css var generator
11
6
  // #{generateCssVar(table-base-cell, suffix-icon, size)}: 1rem;
12
7
  @function generateCssVar($component-name, $element, $style-token) {
@@ -16,9 +11,9 @@
16
11
  // convert hex to rgb values
17
12
  // #{convert-hex-to-rgb-values(#ab2727)}: 171, 39, 39;
18
13
  @function convert-hex-to-rgb-values($hex) {
19
- $r: red($hex);
20
- $g: green($hex);
21
- $b: blue($hex);
14
+ $r: color.channel($hex, 'red', $space: rgb);
15
+ $g: color.channel($hex, 'green', $space: rgb);
16
+ $b: color.channel($hex, 'blue', $space: rgb);
22
17
 
23
18
  @return $r + ', ' + $g + ', ' + $b;
24
19
  }
@@ -26,6 +21,7 @@
26
21
  // px to rem
27
22
  // font-size: rem(16);
28
23
  $browser-context: 16;
24
+
29
25
  @function rem($valueRem, $context: $browser-context) {
30
26
  @return #{math.div($valueRem, $context)}rem;
31
27
  }
@@ -47,20 +43,21 @@ $browser-context: 16;
47
43
  @mixin flex-column-center {
48
44
  display: flex;
49
45
  flex-direction: column;
50
- justify-content: center;
51
46
  align-items: center;
47
+ justify-content: center;
52
48
  }
53
49
 
54
50
  @mixin visually-hidden {
55
51
  position: absolute;
52
+ overflow: hidden;
56
53
  width: 1px;
57
54
  height: 1px;
58
- margin: -1px;
59
- border: 0;
60
55
  padding: 0;
61
- white-space: nowrap;
62
- clip-path: inset(100%);
56
+ border: 0;
57
+ margin: -1px;
58
+ /* stylelint-disable-next-line property-no-deprecated -- legacy-browser leg of the visually-hidden pattern */
63
59
  clip: rect(0 0 0 0);
64
- overflow: hidden;
60
+ clip-path: inset(100%);
65
61
  pointer-events: none;
62
+ white-space: nowrap;
66
63
  }
@@ -31,11 +31,11 @@ $use-material: true !default;
31
31
  @function t($light, $dark: null, $mat: null) {
32
32
  $v: $light;
33
33
 
34
- @if $dark != null {
34
+ @if $dark {
35
35
  $v: light-dark(#{$light}, #{$dark});
36
36
  }
37
37
 
38
- @if $mat != null and $use-material {
38
+ @if $mat and $use-material {
39
39
  @return var(--mat-sys-#{$mat}, #{$v});
40
40
  }
41
41
 
@@ -46,14 +46,14 @@ $use-material: true !default;
46
46
 
47
47
  // Unified neutral scale (sorted by lightness, sourced from the legacy white/gray/black families)
48
48
  $neutral: (
49
- 0: #ffffff,
49
+ 0: #fff,
50
50
  5: #f5f6f8,
51
51
  10: #f3f3f3,
52
- 15: #eeeeee,
52
+ 15: #eee,
53
53
  20: #e8e8e8,
54
54
  25: #e0e0e0,
55
55
  30: #d1d1d1,
56
- 35: #cccccc,
56
+ 35: #ccc,
57
57
  40: #a3a3a3,
58
58
  60: #747474,
59
59
  80: #323033,
@@ -105,103 +105,158 @@ $hue-base: (
105
105
  'green': #01af8d,
106
106
  'brand': #0d1c2b,
107
107
  );
108
-
109
108
  $opacity-steps: (5, 10, 20, 30, 40, 50, 60, 70, 80, 90);
110
109
  $overlay-steps: (5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90);
111
110
 
111
+ /* ------------------------------ Accent-role ramps (indirection layer) ------------------------------ */
112
+ // The semantic accent tier references ONLY these `--rt-color-{role}-{0..100}` rows — never raw hues.
113
+ // A custom color scheme overrides just these rows (see `_color-scheme.scss`) and the entire
114
+ // accent layer (bg/text/icon/border + hover/subtle/disabled/focus derivations) recolors with Δ0 effort.
115
+ // ---
116
+ // Defaults reproduce the historical own-palette byte-for-byte. Tones that previously mapped to a
117
+ // Material system color carry the `--mat-sys-*` fallback INSIDE the tone (`t(..., null, $mat)`), so:
118
+ // - default render honors Material (as before);
119
+ // - a scheme override replaces the tone with a raw value → the scheme wins over Material.
120
+ // `brand` is navy in light (100) / near-white in dark (20); both carry mat-sys-primary because the
121
+ // original text/icon-accent-brand mapped to --mat-sys-primary.
122
+ $accent-roles: (
123
+ 'primary': (
124
+ 20: t(#eaedfc, null, primary-container),
125
+ 40: #b3ceef,
126
+ 60: t(#6d96e8, null, primary),
127
+ 100: t(#4284d7, null, primary),
128
+ ),
129
+ 'info': (
130
+ 20: #eaedfc,
131
+ 80: #4285f4,
132
+ 100: #4284d7,
133
+ ),
134
+ 'success': (
135
+ 10: #e5f8f4,
136
+ 80: #21b18e,
137
+ 100: #01af8d,
138
+ ),
139
+ 'warning': (
140
+ 10: #e8cbbf,
141
+ 80: #ee7a34,
142
+ 100: #ef7128,
143
+ ),
144
+ 'danger': (
145
+ 10: t(#fdedee, null, error-container),
146
+ 60: #e88487,
147
+ 100: t(#eb5055, null, error),
148
+ ),
149
+ 'brand': (
150
+ 20: t(#e8e8e8, null, primary),
151
+ 100: t(#0d1c2b, null, primary),
152
+ ),
153
+ );
154
+
112
155
  /* ============================== Tier 2: semantic ============================== */
113
156
  // NOTE: function calls in this map are evaluated when the module loads,
114
157
  // honoring a `with ($use-material: ...)` configuration.
115
158
 
116
159
  $semantic: (
117
- /* ---- bg / base (adaptive) ---- */ bg-base-base: t(#ffffff, #1c1b1e, surface),
118
- bg-base-elevated: t(#ffffff, #2a292d, surface-container),
160
+ /* ---- bg / base (adaptive) ---- */ bg-base-base: t(#fff, #1c1b1e, surface),
161
+ bg-base-elevated: t(#fff, #2a292d, surface-container),
119
162
  bg-base-subtle: t(#f5f6f8, #232226),
120
- bg-base-hover: t(#f3f3f3, rgba(255, 255, 255, 0.06)),
121
- bg-base-active: t(#eeeeee, rgba(255, 255, 255, 0.1)),
163
+ bg-base-hover: t(#f3f3f3, rgb(255 255 255 / 6%)),
164
+ bg-base-active: t(#eee, rgb(255 255 255 / 10%)),
122
165
  bg-base-strong: t(#e0e0e0, #3f3e43),
123
166
  bg-base-emphasis: t(#747474, #a3a3a3),
124
167
  bg-base-emphasis-soft: t(#a3a3a3, #747474),
125
168
  bg-base-inverse: t(#181818, #f3f3f3, inverse-surface),
126
- bg-base-inverse-soft: t(#323033, #eeeeee),
127
- bg-base-overlay: t(rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0.6)),
128
- /* ---- bg / static ---- */ bg-static-light: #ffffff,
169
+ bg-base-inverse-soft: t(#323033, #eee),
170
+ bg-base-overlay: t(rgb(0 0 0 / 32%), rgb(0 0 0 / 60%)),
171
+ /* ---- bg / static ---- */ bg-static-light: #fff,
129
172
  bg-static-dark: #181818,
130
173
  bg-static-none: transparent,
131
- /* ---- bg / accent: {subtle, solid, hover, disabled} (simplified GMT scale) ---- */
132
- bg-accent-primary-subtle: t(#eaedfc, color-mix(in srgb, #4284d7 18%, #1c1b1e), primary-container),
133
- bg-accent-primary-solid: t(#4284d7, #4284d7, primary),
134
- bg-accent-primary-hover: t(color-mix(in srgb, #4284d7 90%, #000000), color-mix(in srgb, #4284d7 90%, #ffffff)),
135
- bg-accent-primary-disabled: color-mix(in srgb, #4284d7 38%, transparent),
136
- bg-accent-success-subtle: t(#e5f8f4, color-mix(in srgb, #01af8d 18%, #1c1b1e)),
137
- bg-accent-success-solid: #21b18e,
138
- bg-accent-success-hover: t(color-mix(in srgb, #21b18e 90%, #000000), color-mix(in srgb, #21b18e 90%, #ffffff)),
139
- bg-accent-success-disabled: color-mix(in srgb, #21b18e 38%, transparent),
140
- bg-accent-warning-subtle: t(#e8cbbf, color-mix(in srgb, #ef7128 18%, #1c1b1e)),
141
- bg-accent-warning-solid: #ee7a34,
142
- bg-accent-warning-hover: t(color-mix(in srgb, #ee7a34 90%, #000000), color-mix(in srgb, #ee7a34 90%, #ffffff)),
143
- bg-accent-warning-disabled: color-mix(in srgb, #ee7a34 38%, transparent),
144
- bg-accent-danger-subtle: t(#fdedee, color-mix(in srgb, #eb5055 18%, #1c1b1e), error-container),
145
- bg-accent-danger-solid: t(#eb5055, #eb5055, error),
146
- bg-accent-danger-hover: t(color-mix(in srgb, #eb5055 90%, #000000), color-mix(in srgb, #eb5055 90%, #ffffff)),
147
- bg-accent-danger-disabled: color-mix(in srgb, #eb5055 38%, transparent),
148
- bg-accent-info-subtle: t(#eaedfc, color-mix(in srgb, #4284d7 18%, #1c1b1e)),
149
- bg-accent-info-solid: #4284d7,
150
- bg-accent-info-hover: t(color-mix(in srgb, #4284d7 90%, #000000), color-mix(in srgb, #4284d7 90%, #ffffff)),
151
- bg-accent-info-disabled: color-mix(in srgb, #4284d7 38%, transparent),
152
- bg-accent-neutral-subtle: t(#f3f3f3, rgba(255, 255, 255, 0.06)),
174
+ /* ---- bg / accent: {subtle, solid, hover, disabled} driven by --rt-color-{role}-{N} ---- */
175
+ bg-accent-primary-subtle: t(var(--rt-color-primary-20), color-mix(in srgb, var(--rt-color-primary-100) 18%, #1c1b1e)),
176
+ bg-accent-primary-solid: var(--rt-color-primary-100),
177
+ bg-accent-primary-hover: t(
178
+ color-mix(in srgb, var(--rt-color-primary-100) 90%, #000),
179
+ color-mix(in srgb, var(--rt-color-primary-100) 90%, #fff)
180
+ ),
181
+ bg-accent-primary-disabled: color-mix(in srgb, var(--rt-color-primary-100) 38%, transparent),
182
+ bg-accent-success-subtle: t(var(--rt-color-success-10), color-mix(in srgb, var(--rt-color-success-100) 18%, #1c1b1e)),
183
+ bg-accent-success-solid: var(--rt-color-success-80),
184
+ bg-accent-success-hover: t(
185
+ color-mix(in srgb, var(--rt-color-success-80) 90%, #000),
186
+ color-mix(in srgb, var(--rt-color-success-80) 90%, #fff)
187
+ ),
188
+ bg-accent-success-disabled: color-mix(in srgb, var(--rt-color-success-80) 38%, transparent),
189
+ bg-accent-warning-subtle: t(var(--rt-color-warning-10), color-mix(in srgb, var(--rt-color-warning-100) 18%, #1c1b1e)),
190
+ bg-accent-warning-solid: var(--rt-color-warning-80),
191
+ bg-accent-warning-hover: t(
192
+ color-mix(in srgb, var(--rt-color-warning-80) 90%, #000),
193
+ color-mix(in srgb, var(--rt-color-warning-80) 90%, #fff)
194
+ ),
195
+ bg-accent-warning-disabled: color-mix(in srgb, var(--rt-color-warning-80) 38%, transparent),
196
+ bg-accent-danger-subtle: t(var(--rt-color-danger-10), color-mix(in srgb, var(--rt-color-danger-100) 18%, #1c1b1e)),
197
+ bg-accent-danger-solid: var(--rt-color-danger-100),
198
+ bg-accent-danger-hover: t(
199
+ color-mix(in srgb, var(--rt-color-danger-100) 90%, #000),
200
+ color-mix(in srgb, var(--rt-color-danger-100) 90%, #fff)
201
+ ),
202
+ bg-accent-danger-disabled: color-mix(in srgb, var(--rt-color-danger-100) 38%, transparent),
203
+ bg-accent-info-subtle: t(var(--rt-color-info-20), color-mix(in srgb, var(--rt-color-info-100) 18%, #1c1b1e)),
204
+ bg-accent-info-solid: var(--rt-color-info-100),
205
+ bg-accent-info-hover: t(color-mix(in srgb, var(--rt-color-info-100) 90%, #000), color-mix(in srgb, var(--rt-color-info-100) 90%, #fff)),
206
+ bg-accent-info-disabled: color-mix(in srgb, var(--rt-color-info-100) 38%, transparent),
207
+ bg-accent-neutral-subtle: t(#f3f3f3, rgb(255 255 255 / 6%)),
153
208
  bg-accent-neutral-solid: t(#747474, #a3a3a3),
154
209
  bg-accent-neutral-hover: t(#a3a3a3, #747474),
155
- bg-accent-neutral-disabled: t(rgba(116, 116, 116, 0.38), rgba(163, 163, 163, 0.38)),
156
- /* ---- text / base (adaptive) ---- */ text-base-primary: t(rgba(0, 0, 0, 0.87), rgba(255, 255, 255, 0.87), on-surface),
210
+ bg-accent-neutral-disabled: t(rgb(116 116 116 / 38%), rgb(163 163 163 / 38%)),
211
+ /* ---- text / base (adaptive) ---- */ text-base-primary: t(rgb(0 0 0 / 87%), rgb(255 255 255 / 87%), on-surface),
157
212
  text-base-strong: t(#181818, #f3f3f3),
158
213
  text-base-soft: t(#323033, #e0e0e0),
159
214
  text-base-secondary: t(#747474, #a3a3a3, on-surface-variant),
160
215
  text-base-disabled: t(#a3a3a3, #747474),
161
- text-base-inverse: t(#ffffff, #181818, inverse-on-surface),
162
- /* ---- text / static ---- */ text-static-light: #ffffff,
216
+ text-base-inverse: t(#fff, #181818, inverse-on-surface),
217
+ /* ---- text / static ---- */ text-static-light: #fff,
163
218
  text-static-dark: #181818,
164
- /* ---- text / accent ---- */ text-accent-brand: t(#0d1c2b, #e8e8e8, primary),
165
- text-accent-primary: t(#4284d7, #6d96e8, primary),
166
- text-accent-success: #01af8d,
167
- text-accent-success-soft: #21b18e,
168
- text-accent-warning: #ef7128,
169
- text-accent-warning-soft: #ee7a34,
170
- text-accent-danger: t(#eb5055, #eb5055, error),
171
- text-accent-danger-soft: #e88487,
172
- text-accent-info: #4284d7,
173
- text-accent-info-soft: #4285f4,
219
+ /* ---- text / accent ---- */ text-accent-brand: t(var(--rt-color-brand-100), var(--rt-color-brand-20)),
220
+ text-accent-primary: t(var(--rt-color-primary-100), var(--rt-color-primary-60)),
221
+ text-accent-success: var(--rt-color-success-100),
222
+ text-accent-success-soft: var(--rt-color-success-80),
223
+ text-accent-warning: var(--rt-color-warning-100),
224
+ text-accent-warning-soft: var(--rt-color-warning-80),
225
+ text-accent-danger: var(--rt-color-danger-100),
226
+ text-accent-danger-soft: var(--rt-color-danger-60),
227
+ text-accent-info: var(--rt-color-info-100),
228
+ text-accent-info-soft: var(--rt-color-info-80),
174
229
  /* ---- icon / neutral (adaptive) ---- */ icon-neutral-default: t(#323033, #e0e0e0),
175
230
  icon-neutral-soft: t(#747474, #a3a3a3),
176
231
  icon-neutral-disabled: t(#a3a3a3, #747474),
177
- icon-neutral-inverse: t(#ffffff, #181818),
178
- /* ---- icon / static ---- */ icon-static-light: #ffffff,
232
+ icon-neutral-inverse: t(#fff, #181818),
233
+ /* ---- icon / static ---- */ icon-static-light: #fff,
179
234
  icon-static-dark: #181818,
180
- /* ---- icon / accent ---- */ icon-accent-brand: t(#0d1c2b, #e8e8e8, primary),
181
- icon-accent-primary: t(#4284d7, #6d96e8, primary),
182
- icon-accent-success: #01af8d,
183
- icon-accent-warning: #ef7128,
184
- icon-accent-danger: t(#eb5055, #eb5055, error),
185
- icon-accent-info: #4284d7,
235
+ /* ---- icon / accent ---- */ icon-accent-brand: t(var(--rt-color-brand-100), var(--rt-color-brand-20)),
236
+ icon-accent-primary: t(var(--rt-color-primary-100), var(--rt-color-primary-60)),
237
+ icon-accent-success: var(--rt-color-success-100),
238
+ icon-accent-warning: var(--rt-color-warning-100),
239
+ icon-accent-danger: var(--rt-color-danger-100),
240
+ icon-accent-info: var(--rt-color-info-100),
186
241
  /* ---- border / neutral (adaptive) ---- */ border-neutral-subtle: t(#e8e8e8, #2e2d31),
187
242
  border-neutral-default: t(#e0e0e0, #3f3e43, outline-variant),
188
243
  border-neutral-medium: t(#d1d1d1, #4a494e),
189
- border-neutral-divider: t(#cccccc, #4a494e),
244
+ border-neutral-divider: t(#ccc, #4a494e),
190
245
  border-neutral-strong: t(#a3a3a3, #5c5b60, outline),
191
246
  border-neutral-emphasis: t(#747474, #a3a3a3),
192
- /* ---- border / accent ---- */ border-accent-primary: t(#4284d7, #6d96e8, primary),
193
- border-accent-success: #01af8d,
194
- border-accent-warning: #ef7128,
195
- border-accent-danger: t(#eb5055, #eb5055, error),
196
- border-accent-danger-soft: #e88487,
197
- border-accent-info: #4284d7,
198
- border-focus: t(#b3ceef, #6d96e8),
247
+ /* ---- border / accent ---- */ border-accent-primary: t(var(--rt-color-primary-100), var(--rt-color-primary-60)),
248
+ border-accent-success: var(--rt-color-success-100),
249
+ border-accent-warning: var(--rt-color-warning-100),
250
+ border-accent-danger: var(--rt-color-danger-100),
251
+ border-accent-danger-soft: var(--rt-color-danger-60),
252
+ border-accent-info: var(--rt-color-info-100),
253
+ border-focus: t(var(--rt-color-primary-40), var(--rt-color-primary-60)),
199
254
  /* ---- form controls (rt extension) ---- */ control-track: t(#e8e8e8, #4a494e),
200
- control-thumb: t(#ffffff, #eeeeee),
255
+ control-thumb: t(#fff, #eee),
201
256
  control-checked: t(#323033, #e0e0e0),
202
- /* ---- misc ---- */ scrollbar-thumb: t(#cccccc, #4a494e),
257
+ /* ---- misc ---- */ scrollbar-thumb: t(#ccc, #4a494e),
203
258
  scrollbar-thumb-hover: t(#a3a3a3, #5c5b60),
204
- shadow-color: t(#747474, rgba(0, 0, 0, 0.6))
259
+ shadow-color: t(#747474, rgb(0 0 0 / 60%))
205
260
  );
206
261
 
207
262
  /* ============================== Foundations (mode-independent) ============================== */
@@ -222,7 +277,6 @@ $spacing: (
222
277
  56: 3.5rem,
223
278
  64: 4rem,
224
279
  );
225
-
226
280
  $radius: (
227
281
  xs: 0.25rem,
228
282
  sm: 0.5rem,
@@ -232,7 +286,6 @@ $radius: (
232
286
  2xl: 2rem,
233
287
  full: 624.9375rem,
234
288
  );
235
-
236
289
  $font-size: (
237
290
  xs: 0.75rem,
238
291
  sm: 0.875rem,
@@ -240,32 +293,28 @@ $font-size: (
240
293
  lg: 1.25rem,
241
294
  xl: 1.5rem,
242
295
  );
243
-
244
296
  $font-weight: (
245
297
  regular: 400,
246
298
  medium: 500,
247
299
  semibold: 600,
248
300
  bold: 700,
249
301
  );
250
-
251
302
  $shadow: (
252
303
  sm: (
253
- 0 0.0625rem 0.25rem 0 rgba(0, 0, 0, 0.12),
304
+ 0 0.0625rem 0.25rem 0 rgb(0 0 0 / 12%),
254
305
  ),
255
306
  md: (
256
- 0 0.25rem 0.5rem 0 rgba(0, 0, 0, 0.14),
307
+ 0 0.25rem 0.5rem 0 rgb(0 0 0 / 14%),
257
308
  ),
258
309
  lg: (
259
310
  0 0.5rem 1rem 0 var(--rt-shadow-color),
260
311
  ),
261
312
  );
262
-
263
313
  $transition: (
264
314
  fast: 0.15s ease-in-out,
265
315
  base: 0.25s ease-in-out,
266
316
  slow: 0.4s ease-in-out,
267
317
  );
268
-
269
318
  $z-index: (
270
319
  dropdown: 1000,
271
320
  sticky: 1020,
@@ -315,6 +364,13 @@ $breakpoint: (
315
364
  --rt-color-light-a#{$a}: rgba(255, 255, 255, #{calc($a / 100)});
316
365
  }
317
366
 
367
+ // accent-role ramps (indirection layer) — overridable per color scheme
368
+ @each $role, $tones in $accent-roles {
369
+ @each $step, $value in $tones {
370
+ --rt-color-#{$role}-#{$step}: #{$value};
371
+ }
372
+ }
373
+
318
374
  /* --- Tier 2: semantic --- */
319
375
  @each $token, $value in $semantic {
320
376
  --rt-#{$token}: #{$value};
@@ -324,50 +380,34 @@ $breakpoint: (
324
380
  @each $token, $value in $spacing {
325
381
  --rt-spacing-#{$token}: #{$value};
326
382
  }
383
+
327
384
  @each $token, $value in $radius {
328
385
  --rt-radius-#{$token}: #{$value};
329
386
  }
387
+
330
388
  @each $token, $value in $font-size {
331
389
  --rt-font-size-#{$token}: #{$value};
332
390
  }
391
+
333
392
  @each $token, $value in $font-weight {
334
393
  --rt-font-weight-#{$token}: #{$value};
335
394
  }
395
+
336
396
  @each $token, $value in $shadow {
337
397
  --rt-shadow-#{$token}: #{$value};
338
398
  }
399
+
339
400
  @each $token, $value in $transition {
340
401
  --rt-transition-#{$token}: #{$value};
341
402
  }
403
+
342
404
  @each $token, $value in $z-index {
343
405
  --rt-z-index-#{$token}: #{$value};
344
406
  }
407
+
345
408
  @each $token, $value in $breakpoint {
346
409
  --rt-breakpoint-#{$token}: #{$value};
347
410
  }
348
-
349
- /* --- Deprecated aliases (legacy --clr-*; remove after consumers migrate) --- */
350
- --clr-white-100: var(--rt-color-neutral-0);
351
- --clr-gray-5: var(--rt-color-neutral-5);
352
- --clr-gray-10: var(--rt-color-neutral-20);
353
- --clr-gray-15: var(--rt-color-neutral-30);
354
- --clr-gray-20: var(--rt-color-neutral-35);
355
- --clr-black-10: var(--rt-color-neutral-10);
356
- --clr-black-15: var(--rt-color-neutral-15);
357
- --clr-black-20: var(--rt-color-neutral-25);
358
- --clr-black-30: #b2cbca; // palette outlier, kept verbatim
359
- --clr-black-40: var(--rt-color-neutral-40);
360
- --clr-black-60: var(--rt-color-neutral-60);
361
- --clr-black-80: var(--rt-color-neutral-80);
362
- --clr-black-100: var(--rt-color-neutral-100);
363
- @each $hue, $steps in $hues {
364
- @each $step, $value in $steps {
365
- --clr-#{$hue}-#{$step}: var(--rt-color-#{$hue}-#{$step});
366
- }
367
- }
368
- --clr-txt: var(--rt-text-base-primary);
369
- --clr-base-accent: var(--rt-color-brand);
370
- --clr-white-rgb: 255, 255, 255;
371
411
  }
372
412
 
373
413
  /* Theme switching: global class + nested local contexts (GMT data-theme analogue) */