tiny-essentials 1.29.0 → 1.29.2

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 (131) hide show
  1. package/changelog/1/29/1.md +11 -0
  2. package/changelog/1/29/2.md +82 -0
  3. package/dist/v1/TinyBasicsEs.min.js +1 -1
  4. package/dist/v1/TinyEssentials.min.js +1 -1
  5. package/dist/v1/TinyFetchLoader.min.js +1 -0
  6. package/dist/v1/TinyImageLoader.min.js +1 -0
  7. package/dist/v1/TinyMediaCache.min.js +1 -0
  8. package/dist/v1/TinyMediaLoader.min.js +1 -0
  9. package/dist/v1/basics/index.cjs +5 -0
  10. package/dist/v1/basics/index.d.mts +2 -1
  11. package/dist/v1/basics/index.d.mts.map +1 -1
  12. package/dist/v1/basics/index.mjs +2 -1
  13. package/dist/v1/basics/media/youtube.cjs +275 -0
  14. package/dist/v1/basics/media/youtube.d.mts +107 -0
  15. package/dist/v1/basics/media/youtube.d.mts.map +1 -0
  16. package/dist/v1/basics/media/youtube.mjs +214 -0
  17. package/dist/v1/index.cjs +13 -0
  18. package/dist/v1/index.d.mts +6 -1
  19. package/dist/v1/index.d.mts.map +1 -1
  20. package/dist/v1/index.mjs +7 -2
  21. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.cjs +0 -1
  22. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts +0 -1
  23. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts.map +1 -1
  24. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.mjs +0 -1
  25. package/dist/v1/libs/fs/plugins/OPFS/index.cjs +0 -8
  26. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts +0 -8
  27. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts.map +1 -1
  28. package/dist/v1/libs/fs/plugins/OPFS/index.mjs +0 -8
  29. package/dist/v1/libs/html/TinyHtml.cjs +1 -1
  30. package/dist/v1/libs/html/TinyHtml.d.mts +2 -2
  31. package/dist/v1/libs/html/TinyHtml.d.mts.map +1 -1
  32. package/dist/v1/libs/html/TinyHtml.mjs +1 -1
  33. package/dist/v1/libs/html/loader/TinyMediaLoader.cjs +1999 -0
  34. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts +999 -0
  35. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts.map +1 -0
  36. package/dist/v1/libs/html/loader/TinyMediaLoader.mjs +1852 -0
  37. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.cjs +77 -0
  38. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts +103 -0
  39. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts.map +1 -0
  40. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.mjs +67 -0
  41. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.cjs +630 -0
  42. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts +138 -0
  43. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts.map +1 -0
  44. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.mjs +576 -0
  45. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.cjs +70 -0
  46. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts +100 -0
  47. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts.map +1 -0
  48. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.mjs +60 -0
  49. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.cjs +946 -0
  50. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts +67 -0
  51. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts.map +1 -0
  52. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.mjs +896 -0
  53. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.cjs +225 -0
  54. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts +149 -0
  55. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts.map +1 -0
  56. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.mjs +197 -0
  57. package/dist/v1/libs/html/loader/formats/TinyImageLoader.cjs +1454 -0
  58. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts +200 -0
  59. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts.map +1 -0
  60. package/dist/v1/libs/html/loader/formats/TinyImageLoader.mjs +1317 -0
  61. package/dist/v1/libs/html/loader/probe/TinyImageProbe.cjs +668 -0
  62. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts +83 -0
  63. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts.map +1 -0
  64. package/dist/v1/libs/html/loader/probe/TinyImageProbe.mjs +626 -0
  65. package/dist/v1/libs/html/loader/utils/TinyBufferReader.cjs +277 -0
  66. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts +118 -0
  67. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts.map +1 -0
  68. package/dist/v1/libs/html/loader/utils/TinyBufferReader.mjs +247 -0
  69. package/dist/v1/libs/html/loader/utils/TinyIsoBox.cjs +128 -0
  70. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts +49 -0
  71. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts.map +1 -0
  72. package/dist/v1/libs/html/loader/utils/TinyIsoBox.mjs +116 -0
  73. package/dist/v1/libs/html/loader/utils/TinyMediaCache.cjs +796 -0
  74. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts +354 -0
  75. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts.map +1 -0
  76. package/dist/v1/libs/html/loader/utils/TinyMediaCache.mjs +734 -0
  77. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.cjs +302 -0
  78. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts +256 -0
  79. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts.map +1 -0
  80. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.mjs +280 -0
  81. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.cjs +194 -0
  82. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts +138 -0
  83. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts.map +1 -0
  84. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.mjs +175 -0
  85. package/dist/v1/libs/tools/TinyPkgExportValidator.cjs +359 -55
  86. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts +64 -6
  87. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts.map +1 -1
  88. package/dist/v1/libs/tools/TinyPkgExportValidator.mjs +320 -57
  89. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.cjs +0 -1
  90. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts +0 -1
  91. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts.map +1 -1
  92. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.mjs +0 -1
  93. package/dist/v1/webTemplates/bootstrap/5.3/scss/background/_background-grid.scss +15 -0
  94. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-contrast.scss +208 -0
  95. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-ghost.scss +89 -0
  96. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_cube-icon.scss +65 -0
  97. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_sphere-pulse.scss +39 -0
  98. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_badges.scss +90 -0
  99. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_bootstrap-overrides.scss +495 -0
  100. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_buttons.scss +390 -0
  101. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_colors.scss +213 -0
  102. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_effects.scss +153 -0
  103. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms-tones.scss +69 -0
  104. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms.scss +323 -0
  105. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_global.scss +31 -0
  106. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_links.scss +47 -0
  107. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tables.scss +25 -0
  108. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_theme.scss +21 -0
  109. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tokens.scss +161 -0
  110. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_utilities.scss +81 -0
  111. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_variables.scss +63 -0
  112. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_form-tone-mixins.scss +236 -0
  113. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_sizing.scss +68 -0
  114. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_tone-mixins.scss +392 -0
  115. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_typography.scss +112 -0
  116. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/background/_tiny_gradient_1.scss +131 -0
  117. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/colors/_pink.scss +47 -0
  118. package/dist/v1/webTemplates/multiformats/14.0/IPFSHasher/index.cjs +2 -2
  119. package/docs/v1/Exports.md +33 -2
  120. package/docs/v1/README.md +9 -0
  121. package/docs/v1/basics/youtube.md +204 -0
  122. package/docs/v1/libs/html/loader/TinyFetchLoader.md +114 -0
  123. package/docs/v1/libs/html/loader/TinyImageLoader.md +141 -0
  124. package/docs/v1/libs/html/loader/TinyMediaCache.md +166 -0
  125. package/docs/v1/libs/html/loader/TinyMediaLoader.md +300 -0
  126. package/docs/v1/libs/tools/TinyPkgExportValidator.md +55 -0
  127. package/docs/v1/webTemplates/ag-psd/31.0/ProcessSolidFilters.md +0 -4
  128. package/docs/v1/webTemplates/bootstrap/5.3/DeepStrap.md +177 -0
  129. package/package.json +281 -17
  130. /package/dist/v1/webTemplates/bootstrap/5.3/scss/input/{Placeholder-Colors-Fix.scss → _placeholder-colors-fix.scss} +0 -0
  131. /package/dist/v1/webTemplates/bootstrap/5.3/scss/spacing/{Spacing-Plus.scss → _spacing-plus.scss} +0 -0
@@ -0,0 +1,153 @@
1
+ // =============================================================================
2
+ // Effect primitives
3
+ // Glass is a spectrum: 3 named levels, each with a fallback.
4
+ // =============================================================================
5
+
6
+ @use 'sass:map';
7
+
8
+ // ---------------------------------------------------------------- elevation --
9
+ /// Two-layer shadow: contact + ambient. The colour comes from the theme so the
10
+ /// light variant can use a slate shadow instead of pure black.
11
+ $elevation: (
12
+ 1: (
13
+ 0 1px 2px rgb(var(--ui-shadow-rgb) / 0.24),
14
+ ),
15
+ 2: (
16
+ 0 1px 2px rgb(var(--ui-shadow-rgb) / 0.24),
17
+ 0 8px 24px -16px rgb(var(--ui-shadow-rgb) / 0.72),
18
+ ),
19
+ 3: (
20
+ 0 2px 4px rgb(var(--ui-shadow-rgb) / 0.28),
21
+ 0 16px 48px -20px rgb(var(--ui-shadow-rgb) / 0.8),
22
+ ),
23
+ ) !default;
24
+
25
+ /// Applies a step from the elevation scale.
26
+ ///
27
+ /// @param {Number} $level - 1, 2 or 3.
28
+ @mixin elevation($level: 2) {
29
+ @if not map.has-key($elevation, $level) {
30
+ @error 'Unknown elevation level: #{$level}';
31
+ }
32
+
33
+ box-shadow: map.get($elevation, $level);
34
+ }
35
+
36
+ // -------------------------------------------------------------------- glass --
37
+ /// Frosted surface.
38
+ ///
39
+ /// The blur is painted on a `::before` layer, never on the element itself.
40
+ /// `backdrop-filter` turns the element into a stacking context and a containing
41
+ /// block for `position: fixed` / `position: absolute` descendants. Bootstrap's
42
+ /// `.dropdown-menu` (`z-index: 1000`), `.offcanvas` and `.tooltip` all rely on
43
+ /// escaping that box, so blurring the element directly traps them and breaks
44
+ /// the paint order.
45
+ ///
46
+ /// The element must be a positioning context (`relative`, `sticky` or `fixed`).
47
+ /// `.navbar` already is; the `.glass*` utilities set it explicitly.
48
+ ///
49
+ /// @param {String} $level - `subtle`, `default` or `strong`.
50
+ /// @param {String} $token - Token name, without the `--ui-` prefix.
51
+ /// @param {Boolean} $layer - `true` paints the blur on `::before` (default).
52
+ /// Pass `false` for leaf elements such as `.modal-backdrop`, where the extra
53
+ /// layer is dead weight.
54
+ @mixin glass($level: 'default', $token: 'surface', $layer: true) {
55
+ $config: (
56
+ 'subtle': (
57
+ alpha: 0.42,
58
+ blur: 12px,
59
+ ),
60
+ 'default': (
61
+ alpha: 0.62,
62
+ blur: 20px,
63
+ ),
64
+ 'strong': (
65
+ alpha: 0.78,
66
+ blur: 28px,
67
+ ),
68
+ );
69
+
70
+ @if not map.has-key($config, $level) {
71
+ @error 'Unknown glass level: #{$level}';
72
+ }
73
+
74
+ $alpha: map.get(map.get($config, $level), alpha);
75
+ $blur: map.get(map.get($config, $level), blur);
76
+
77
+ // Leaf element: no descendants to trap, paint in place.
78
+ @if not $layer {
79
+ background: rgb(var(--ui-#{$token}-rgb) / #{$alpha});
80
+ backdrop-filter: blur($blur) saturate(var(--ui-glass-saturate));
81
+ -webkit-backdrop-filter: blur($blur) saturate(var(--ui-glass-saturate));
82
+
83
+ @supports not (backdrop-filter: blur(1px)) {
84
+ background: rgb(var(--ui-#{$token}-rgb) / 0.98);
85
+ }
86
+ }
87
+
88
+ // Container: paint the blur on a pseudo-element so the element itself stays
89
+ // out of the stacking context / containing block business.
90
+ background: transparent;
91
+
92
+ &::before {
93
+ position: absolute;
94
+ inset: 0;
95
+ z-index: -1;
96
+ pointer-events: none;
97
+ content: '';
98
+ background: rgb(var(--ui-#{$token}-rgb) / #{$alpha});
99
+ border-radius: inherit;
100
+ backdrop-filter: blur($blur) saturate(var(--ui-glass-saturate));
101
+ -webkit-backdrop-filter: blur($blur) saturate(var(--ui-glass-saturate));
102
+
103
+ @supports not (backdrop-filter: blur(1px)) {
104
+ background: rgb(var(--ui-#{$token}-rgb) / 0.98);
105
+ }
106
+ }
107
+ }
108
+
109
+ // ------------------------------------------------------------------ surface --
110
+ /// Opaque surface. Used by components that must not be transparent (modals,
111
+ /// dropdowns) but still need the border and radius.
112
+ ///
113
+ /// @param {Number} $alpha - Background opacity.
114
+ @mixin surface($alpha: 0.98) {
115
+ background: rgb(var(--ui-surface-rgb) / #{$alpha});
116
+ border: 1px solid var(--ui-border);
117
+ border-radius: var(--bs-border-radius);
118
+ }
119
+
120
+ // ----------------------------------------------------------------- hairline --
121
+ /// 1px light line on the top edge. Fakes a lit bevel.
122
+ @mixin hairline-top($opacity: 1) {
123
+ box-shadow: inset 0 1px 0 rgb(var(--ui-heading-rgb) / #{0.06 * $opacity});
124
+ }
125
+
126
+ /// Full inner border, brighter at the top. Requires `position: relative`.
127
+ @mixin bevel($radius: inherit) {
128
+ &::after {
129
+ position: absolute;
130
+ inset: 0;
131
+ pointer-events: none;
132
+ content: '';
133
+ border-radius: $radius;
134
+ box-shadow: inset 0 1px 0 var(--ui-hairline-strong);
135
+ }
136
+ }
137
+
138
+ // -------------------------------------------------------------------- focus --
139
+ @mixin focus-ring($color: 'accent', $width: 3px) {
140
+ outline: none;
141
+ box-shadow: 0 0 0 $width rgb(var(--ui-#{$color}-rgb) / 0.24);
142
+ }
143
+
144
+ // ------------------------------------------------------------------ motion --
145
+ @mixin transition($properties...) {
146
+ transition-duration: var(--ui-duration);
147
+ transition-timing-function: var(--ui-ease);
148
+ transition-property: $properties;
149
+
150
+ @media (prefers-reduced-motion: reduce) {
151
+ transition-duration: 1ms;
152
+ }
153
+ }
@@ -0,0 +1,69 @@
1
+ @use 'sass:map';
2
+ @use 'sass:meta';
3
+ @use 'colors' as *;
4
+
5
+ /// @type Map
6
+ $form-tone-map: (
7
+ 'primary': (
8
+ 'tone': 'accent',
9
+ 'on': 'accent',
10
+ 'base': palette('indigo-500'),
11
+ ),
12
+ 'secondary': (
13
+ 'tone': 'text-muted',
14
+ 'on': 'text-muted',
15
+ 'base': palette('slate-400'),
16
+ ),
17
+ 'success': (
18
+ 'tone': 'success',
19
+ 'on': 'success',
20
+ 'base': palette('green-500'),
21
+ ),
22
+ 'danger': (
23
+ 'tone': 'error',
24
+ 'on': 'error',
25
+ 'base': palette('red-500'),
26
+ ),
27
+ 'warning': (
28
+ 'tone': 'warn',
29
+ 'on': 'warn',
30
+ 'base': palette('amber-500'),
31
+ ),
32
+ 'info': (
33
+ 'tone': 'info',
34
+ 'on': 'info',
35
+ 'base': palette('cyan-500'),
36
+ ),
37
+ 'light': (
38
+ 'tone': 'neutral-light',
39
+ 'on': 'neutral-light',
40
+ 'base': palette('slate-050'),
41
+ ),
42
+ 'dark': (
43
+ 'tone': 'neutral-dark',
44
+ 'on': 'neutral-dark',
45
+ 'base': palette('slate-900'),
46
+ ),
47
+ );
48
+
49
+ @each $name, $config in $form-tone-map {
50
+ @if meta.type-of($config) != 'map' {
51
+ @error 'Form tone `#{$name}` must be a map, got `#{meta.type-of($config)}`.';
52
+ }
53
+
54
+ @each $key in ('tone', 'on') {
55
+ @if not map.has-key($config, $key) {
56
+ @error 'Form tone `#{$name}` is missing the `#{$key}` key.';
57
+ }
58
+ }
59
+
60
+ $mark: null;
61
+
62
+ @if map.has-key($config, 'mark') {
63
+ $mark: map.get($config, 'mark');
64
+ } @else if map.has-key($config, 'base') {
65
+ $mark: form-mark-contrast(map.get($config, 'base'));
66
+ }
67
+
68
+ @include form-tone-plugin($name, map.get($config, 'tone'), map.get($config, 'on'), $mark);
69
+ }
@@ -0,0 +1,323 @@
1
+ // =============================================================================
2
+ // Form controls
3
+ // =============================================================================
4
+
5
+ @use 'colors' as *;
6
+
7
+ // ------------------------------------------------------------- tone hooks --
8
+ :where(.form-select, .form-check, .form-range) {
9
+ --form-tone: var(--ui-accent);
10
+ --form-tone-rgb: var(--ui-accent-rgb);
11
+ --form-tone-on: var(--ui-on-accent);
12
+ }
13
+
14
+ // ------------------------------------------------------------------ shared --
15
+ %field {
16
+ color: var(--ui-text);
17
+ background-color: rgb(var(--ui-input-rgb) / 0.72);
18
+ border: 1px solid var(--ui-border);
19
+ border-radius: var(--bs-border-radius-sm);
20
+ box-shadow: none;
21
+ transition:
22
+ border-color var(--ui-duration) var(--ui-ease),
23
+ background-color var(--ui-duration) var(--ui-ease),
24
+ box-shadow var(--ui-duration) var(--ui-ease);
25
+
26
+ &:hover:not(:disabled):not(:focus):not([readonly]) {
27
+ border-color: var(--ui-border-strong);
28
+ }
29
+
30
+ &::placeholder {
31
+ color: var(--ui-text-muted);
32
+ opacity: 0.65;
33
+ }
34
+
35
+ &:focus {
36
+ color: var(--ui-text);
37
+ background-color: rgb(var(--ui-input-rgb) / 1);
38
+ border-color: var(--form-tone);
39
+ outline: none;
40
+ box-shadow: 0 0 0 3px rgb(var(--form-tone-rgb) / 0.2);
41
+ }
42
+
43
+ &:disabled,
44
+ &[readonly] {
45
+ color: var(--ui-text-muted);
46
+ background-color: var(--ui-overlay-1);
47
+ border-color: var(--ui-border);
48
+ opacity: 0.7;
49
+ }
50
+
51
+ &::file-selector-button {
52
+ color: var(--ui-text);
53
+ background-color: var(--ui-overlay-2);
54
+ }
55
+ }
56
+
57
+ // ---------------------------------------------------------------- controls --
58
+ .form-control,
59
+ .form-select {
60
+ @extend %field;
61
+ }
62
+
63
+ .form-select {
64
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='#{svg-color('control-icon')}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
65
+ }
66
+
67
+ // ------------------------------------------------------------ input-group --
68
+ .input-group-text {
69
+ color: var(--ui-text-muted);
70
+ background-color: var(--ui-overlay-1);
71
+ border-color: var(--ui-border);
72
+ border-radius: var(--bs-border-radius-sm);
73
+ }
74
+
75
+ .input-group {
76
+ > .form-control,
77
+ > .form-select,
78
+ > .input-group-text,
79
+ > .btn {
80
+ border-radius: var(--bs-border-radius-sm);
81
+ }
82
+
83
+ > :not(:last-child) {
84
+ border-top-right-radius: 0;
85
+ border-bottom-right-radius: 0;
86
+ }
87
+
88
+ > :not(:first-child) {
89
+ margin-left: -1px;
90
+ border-top-left-radius: 0;
91
+ border-bottom-left-radius: 0;
92
+ }
93
+ }
94
+
95
+ // ------------------------------------------------------------------ labels --
96
+ .form-label,
97
+ .col-form-label {
98
+ color: var(--ui-text-muted);
99
+ }
100
+
101
+ .form-text {
102
+ color: var(--ui-text-muted);
103
+ }
104
+
105
+ // ------------------------------------------------------------------ checks --
106
+ .form-check-input {
107
+ background-color: rgb(var(--ui-input-rgb) / 0.72);
108
+ border-color: color-mix(in srgb, var(--form-tone) 45%, transparent);
109
+ transition:
110
+ background-color var(--ui-duration) var(--ui-ease),
111
+ border-color var(--ui-duration) var(--ui-ease),
112
+ box-shadow var(--ui-duration) var(--ui-ease);
113
+
114
+ // Unchecked + hover: previews the tone before the click.
115
+ &:hover:not(:disabled):not(:checked):not(:indeterminate) {
116
+ background-color: rgb(var(--form-tone-rgb) / 0.1);
117
+ border-color: color-mix(in srgb, var(--form-tone) 75%, transparent);
118
+ }
119
+
120
+ &:checked,
121
+ &:indeterminate {
122
+ color: var(--form-tone-on);
123
+ background-color: var(--form-tone);
124
+ border-color: var(--form-tone);
125
+ }
126
+
127
+ &:focus {
128
+ border-color: var(--form-tone);
129
+ box-shadow: 0 0 0 3px rgb(var(--form-tone-rgb) / 0.2);
130
+ }
131
+
132
+ &:disabled {
133
+ background-color: var(--ui-overlay-1);
134
+ border-color: var(--ui-border);
135
+ opacity: 0.5;
136
+ }
137
+ }
138
+
139
+ .form-check-label {
140
+ color: var(--ui-text);
141
+ }
142
+
143
+ .form-switch .form-check-input {
144
+ --form-switch-size: 1em;
145
+ --form-switch-inset: 0.15em;
146
+
147
+ background-color: var(--ui-input);
148
+ background-image: radial-gradient(circle, var(--form-tone) 0 42%, transparent 43%);
149
+ background-repeat: no-repeat;
150
+ background-position: left var(--form-switch-inset) center;
151
+ background-size: var(--form-switch-size) var(--form-switch-size);
152
+ border-color: color-mix(in srgb, var(--form-tone) 45%, transparent);
153
+ transition:
154
+ background-color var(--ui-duration) var(--ui-ease),
155
+ border-color var(--ui-duration) var(--ui-ease);
156
+
157
+ &:checked {
158
+ background-color: var(--form-tone);
159
+ background-image: radial-gradient(circle, var(--form-tone-on) 0 42%, transparent 43%);
160
+ background-position: right var(--form-switch-inset) center;
161
+ border-color: var(--form-tone);
162
+ }
163
+
164
+ &:hover:not(:disabled) {
165
+ border-color: color-mix(in srgb, var(--form-tone) 75%, transparent);
166
+ }
167
+
168
+ &:active:not(:disabled) {
169
+ border-color: var(--form-tone);
170
+ }
171
+
172
+ &:focus {
173
+ border-color: var(--form-tone);
174
+ box-shadow: 0 0 0 3px rgb(var(--form-tone-rgb) / 0.2);
175
+ }
176
+ }
177
+
178
+ // ------------------------------------------------------------------ range --
179
+ .form-range {
180
+ width: 100%;
181
+ height: 1.25rem;
182
+ padding: 0;
183
+ accent-color: var(--form-tone);
184
+ background: transparent;
185
+ appearance: none;
186
+
187
+ &:focus {
188
+ outline: none;
189
+ }
190
+
191
+ &::-webkit-slider-runnable-track {
192
+ height: 4px;
193
+ background-color: var(--ui-input);
194
+ border-radius: 999px;
195
+ box-shadow: inset 0 0 0 1px var(--ui-border);
196
+ }
197
+
198
+ &::-webkit-slider-thumb {
199
+ width: 14px;
200
+ height: 14px;
201
+ margin-top: -5px;
202
+ background-color: var(--form-tone);
203
+ border: 2px solid var(--ui-surface);
204
+ border-radius: 50%;
205
+ transition: box-shadow var(--ui-duration) var(--ui-ease);
206
+ appearance: none;
207
+ }
208
+
209
+ &::-moz-range-track {
210
+ height: 4px;
211
+ background-color: var(--form-tone);
212
+ border-radius: 999px;
213
+ box-shadow: inset 0 0 0 1px var(--ui-border);
214
+ }
215
+
216
+ &::-moz-range-thumb {
217
+ width: 14px;
218
+ height: 14px;
219
+ background-color: var(--ui-accent);
220
+ border: 2px solid var(--ui-surface);
221
+ border-radius: 50%;
222
+ }
223
+
224
+ &:focus-visible {
225
+ &::-webkit-slider-thumb,
226
+ &::-moz-range-thumb {
227
+ box-shadow: 0 0 0 3px rgb(var(--form-tone-rgb) / 0.28);
228
+ }
229
+ }
230
+
231
+ &:disabled {
232
+ opacity: 0.45;
233
+ }
234
+ }
235
+
236
+ // -------------------------------------------------------------- validation --
237
+ :root,
238
+ [data-bs-theme='dark'],
239
+ [data-bs-theme='light'] {
240
+ --bs-form-valid-color: var(--ui-success);
241
+ --bs-form-valid-border-color: var(--ui-success);
242
+ --bs-form-invalid-color: var(--ui-error);
243
+ --bs-form-invalid-border-color: var(--ui-error);
244
+ }
245
+
246
+ @each $state, $token in ('valid': 'success', 'invalid': 'error') {
247
+ .#{$state}-feedback {
248
+ color: var(--ui-#{$token});
249
+ }
250
+
251
+ // Text inputs and selects.
252
+ .form-control,
253
+ .form-select {
254
+ &.is-#{$state},
255
+ .was-validated &:#{$state} {
256
+ background-image: none;
257
+ border-color: var(--ui-#{$token});
258
+
259
+ &:focus {
260
+ border-color: var(--ui-#{$token});
261
+ box-shadow: 0 0 0 3px rgb(var(--ui-#{$token}-rgb) / 0.2);
262
+ }
263
+ }
264
+ }
265
+
266
+ // Checkboxes, radios and switches.
267
+ .form-check-input {
268
+ &.is-#{$state},
269
+ .was-validated &:#{$state} {
270
+ --form-tone: var(--ui-#{$token});
271
+ --form-tone-rgb: var(--ui-#{$token}-rgb);
272
+ --form-tone-on: var(--ui-on-#{$token});
273
+
274
+ border-color: color-mix(in srgb, var(--form-tone) 45%, transparent);
275
+
276
+ &:hover:not(:disabled):not(:checked) {
277
+ background-color: rgb(var(--form-tone-rgb) / 0.1);
278
+ border-color: color-mix(in srgb, var(--form-tone) 75%, transparent);
279
+ }
280
+
281
+ &:checked,
282
+ &:indeterminate {
283
+ background-color: var(--form-tone);
284
+ border-color: var(--form-tone);
285
+ }
286
+
287
+ &:focus {
288
+ border-color: var(--form-tone);
289
+ box-shadow: 0 0 0 3px rgb(var(--form-tone-rgb) / 0.2);
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ // --------------------------------------------------------------- floating --
296
+ .form-floating > .form-control,
297
+ .form-floating > .form-select {
298
+ height: calc(3rem + 2px);
299
+ }
300
+
301
+ .form-floating > label {
302
+ color: var(--ui-text-muted);
303
+ }
304
+
305
+ // ------------------------------------------------------------------- file --
306
+ .form-control::-webkit-file-upload-button {
307
+ color: var(--ui-text);
308
+ background-color: var(--ui-overlay-2);
309
+ border-color: var(--ui-border);
310
+ }
311
+
312
+ // ------------------------------------------------------------------ close --
313
+ .btn-close {
314
+ filter: var(--ui-close-filter, none);
315
+
316
+ &:focus {
317
+ box-shadow: 0 0 0 3px rgb(var(--ui-accent-rgb) / 0.2);
318
+ }
319
+ }
320
+
321
+ [data-bs-theme='dark'] .btn-close {
322
+ --ui-close-filter: invert(1) grayscale(1) brightness(1.6);
323
+ }
@@ -0,0 +1,31 @@
1
+ ::selection {
2
+ color: var(--ui-heading);
3
+ background: rgb(var(--ui-accent-rgb) / 0.32);
4
+ }
5
+
6
+ // Global scrollbar.
7
+ * {
8
+ scrollbar-color: var(--ui-border-strong) transparent;
9
+ scrollbar-width: thin;
10
+ }
11
+
12
+ *::-webkit-scrollbar {
13
+ width: 10px;
14
+ height: 10px;
15
+ }
16
+
17
+ *::-webkit-scrollbar-track {
18
+ background: transparent;
19
+ }
20
+
21
+ *::-webkit-scrollbar-thumb {
22
+ background: var(--ui-border-strong);
23
+ background-clip: padding-box;
24
+ border: 2px solid transparent;
25
+ border-radius: 999px;
26
+ }
27
+
28
+ *::-webkit-scrollbar-thumb:hover {
29
+ background: var(--ui-text-muted);
30
+ background-clip: padding-box;
31
+ }
@@ -0,0 +1,47 @@
1
+ // =============================================================================
2
+ // Links
3
+ // =============================================================================
4
+
5
+ a:not(
6
+ :where(
7
+ .btn,
8
+ .nav-link,
9
+ .dropdown-item,
10
+ .page-link,
11
+ .navbar-brand,
12
+ .list-group-item,
13
+ .accordion-button,
14
+ .btn-close
15
+ )
16
+ ) {
17
+ color: var(--ui-accent);
18
+ text-decoration: none;
19
+ text-underline-offset: 0.2em;
20
+ transition: color var(--ui-duration) var(--ui-ease);
21
+
22
+ &:hover {
23
+ color: var(--ui-accent-soft);
24
+ text-decoration: underline;
25
+ }
26
+
27
+ &:focus-visible {
28
+ outline: 2px solid var(--ui-accent);
29
+ outline-offset: 2px;
30
+ border-radius: 2px;
31
+ }
32
+ }
33
+
34
+ .alert a:not(.btn),
35
+ .alert .alert-link {
36
+ color: inherit;
37
+ text-decoration: underline;
38
+ text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
39
+ text-underline-offset: 0.2em;
40
+ transition: text-decoration-color var(--ui-duration) var(--ui-ease);
41
+
42
+ &:hover,
43
+ &:focus-visible {
44
+ color: inherit;
45
+ text-decoration-color: currentColor;
46
+ }
47
+ }
@@ -0,0 +1,25 @@
1
+ // =============================================================================
2
+ // Table variants
3
+ //
4
+ // Three sources, one mixin each:
5
+ //
6
+ // 1. Semantic tones → `--ui-*` tokens, theme-aware.
7
+ // 2. Custom tones → `--ui-*` tokens, theme-aware.
8
+ // 3. BS 5.3 palette → raw colors, static (matches upstream).
9
+ // =============================================================================
10
+
11
+ @use 'sass:map';
12
+ @use 'colors' as *;
13
+
14
+ // 1. Semantic tones (primary, secondary, success, danger, warning, info).
15
+ @each $name, $token in $subtle-tokens {
16
+ @include tone-table-class($name, $token);
17
+ }
18
+
19
+ // 2. Custom tones.
20
+ @include tone-table-class('pink', 'pink');
21
+
22
+ // 3. Bootstrap 5.3 palette.
23
+ @each $name, $color in $colors {
24
+ @include tone-table-from-color($name, $color);
25
+ }
@@ -0,0 +1,21 @@
1
+ // =============================================================================
2
+ // Entry point — order matters, do not reorder.
3
+ // =============================================================================
4
+
5
+ @import './plugins/tone-mixins';
6
+ @import './plugins/form-tone-mixins';
7
+ @import 'bootstrap/scss/functions';
8
+ @import 'variables';
9
+ @import 'bootstrap/scss/bootstrap';
10
+
11
+ @import 'tokens';
12
+ @import 'effects';
13
+ @import 'global';
14
+ @import 'bootstrap-overrides';
15
+ @import 'buttons';
16
+ @import 'forms';
17
+ @import 'forms-tones';
18
+ @import 'links';
19
+ @import 'utilities';
20
+ @import 'badges';
21
+ @import 'tables';