@cdevhub/ngx-tw 0.5.0 → 0.6.1

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 (209) hide show
  1. package/README.md +78 -15
  2. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
  4. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
  5. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
  6. package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
  7. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
  8. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
  9. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
  10. package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
  11. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
  12. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
  13. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
  14. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
  15. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
  16. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
  17. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
  18. package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
  19. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
  20. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
  21. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
  22. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
  23. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
  24. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
  25. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
  26. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
  27. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
  28. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
  29. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
  30. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
  32. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
  33. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
  34. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
  35. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
  36. package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
  37. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
  38. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
  39. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
  40. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
  41. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
  42. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
  43. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
  44. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
  45. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
  46. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
  47. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
  48. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +11 -2
  49. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
  50. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
  51. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
  52. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
  53. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
  54. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
  55. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
  56. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
  57. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
  58. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
  59. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
  60. package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
  61. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
  62. package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
  63. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
  64. package/fesm2022/cdevhub-ngx-tw-item.mjs +28 -4
  65. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
  66. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
  67. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
  68. package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
  69. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
  70. package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
  71. package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
  72. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
  73. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
  74. package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
  75. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
  76. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
  77. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
  78. package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
  79. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
  80. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
  81. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
  82. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
  83. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
  84. package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
  85. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
  86. package/fesm2022/{cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs → cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs} +3 -3
  87. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
  88. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
  89. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
  90. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +23 -7
  91. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
  92. package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
  93. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
  94. package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
  95. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
  96. package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
  97. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
  98. package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
  99. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
  100. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
  101. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
  102. package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
  103. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
  104. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
  105. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
  106. package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
  107. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
  108. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
  109. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
  110. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
  111. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
  112. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
  113. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
  114. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
  115. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
  116. package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
  117. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
  118. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
  119. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
  120. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
  121. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
  122. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
  123. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
  124. package/fesm2022/{cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs → cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs} +107 -19
  125. package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
  126. package/fesm2022/cdevhub-ngx-tw-toast.mjs +21 -13
  127. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
  128. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
  129. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
  130. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
  131. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
  132. package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
  133. package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
  134. package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
  135. package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
  136. package/index.json +1 -1
  137. package/package.json +63 -2
  138. package/theme/_base.css +13 -0
  139. package/theme/_dark.css +111 -36
  140. package/theme/_high-contrast-dark.css +367 -0
  141. package/theme/_high-contrast.css +13 -2
  142. package/theme/_light.css +332 -0
  143. package/theme/_semantic.css +60 -26
  144. package/theme/_typography.css +17 -0
  145. package/theme/index.css +86 -7
  146. package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
  147. package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
  148. package/types/cdevhub-ngx-tw-button.d.ts +1 -0
  149. package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
  150. package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
  151. package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
  152. package/types/cdevhub-ngx-tw-card.d.ts +11 -3
  153. package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
  154. package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
  155. package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
  156. package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
  157. package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
  158. package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
  159. package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
  160. package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
  161. package/types/cdevhub-ngx-tw-core.d.ts +152 -21
  162. package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
  163. package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
  164. package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
  165. package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
  166. package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
  167. package/types/cdevhub-ngx-tw-dialog.d.ts +12 -3
  168. package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
  169. package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
  170. package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
  171. package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
  172. package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
  173. package/types/cdevhub-ngx-tw-input.d.ts +5 -8
  174. package/types/cdevhub-ngx-tw-item.d.ts +2 -0
  175. package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
  176. package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
  177. package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
  178. package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
  179. package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
  180. package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
  181. package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
  182. package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
  183. package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
  184. package/types/cdevhub-ngx-tw-select.d.ts +104 -33
  185. package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
  186. package/types/cdevhub-ngx-tw-sheet.d.ts +19 -3
  187. package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
  188. package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
  189. package/types/cdevhub-ngx-tw-split.d.ts +32 -2
  190. package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
  191. package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
  192. package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
  193. package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
  194. package/types/cdevhub-ngx-tw-table.d.ts +53 -10
  195. package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
  196. package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
  197. package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
  198. package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
  199. package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
  200. package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
  201. package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
  202. package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
  203. package/types/cdevhub-ngx-tw-toast.d.ts +20 -6
  204. package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
  205. package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
  206. package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
  207. package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
  208. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs.map +0 -1
  209. package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs.map +0 -1
@@ -0,0 +1,332 @@
1
+ /* ===== Light theme (explicit opt-in) =====
2
+ A mechanical mirror of the light values that `_semantic.css`'s `@theme`
3
+ block already resolves on the root. It exists for one reason: Tailwind v4
4
+ emits `@theme` as `@layer theme { :root, :host { … } }`, and a
5
+ `<div data-theme="light">` matches neither `:root` nor `:host` — so before
6
+ this file a light subtree nested inside a dark or high-contrast ancestor
7
+ simply inherited the ancestor's tokens, and `[twTheme]="'light'"` was a
8
+ silent no-op. `dark` and `high-contrast` have always had element-agnostic
9
+ `[data-theme=…]` blocks; this is the missing third one.
10
+
11
+ Two invariants keep it safe:
12
+
13
+ 1. Every declaration restates the value `_semantic.css` already sets.
14
+ Nothing here is new or hand-tuned, so a light-on-light page — the common
15
+ case, where `<html data-theme="light">` matches both this block and the
16
+ `@theme` `:root` rule — computes byte-identical values and no pixel
17
+ moves. The rationale for each value (the WCAG contrast measurements, the
18
+ slot semantics, why `info-solid` is -700 and not -600) lives in
19
+ `_semantic.css` and is deliberately NOT duplicated here. Edit
20
+ `_semantic.css`, then regenerate this block from it.
21
+
22
+ 2. The 195 declarations below are exactly the key set that `_dark.css`,
23
+ `_high-contrast.css` and `_high-contrast-dark.css` define. The seven
24
+ `@theme` tokens omitted
25
+ (`--color-overlay-control{,-hover}`,
26
+ `--shadow-table-sticky{,-cell-start,-cell-end}`,
27
+ `--text-2xs{,--line-height}`) are scheme-invariant by design and are
28
+ omitted by the dark and high-contrast blocks too. The shadow tokens are
29
+ safe to omit even for subtree scoping: Tailwind inlines a named
30
+ `--shadow-*` value into the utility, so `shadow-table-sticky` compiles
31
+ to `--tw-shadow: 0 1px 0 0 var(--tw-shadow-color, var(--color-border))`
32
+ and re-resolves `--color-border` at the use site, inside the subtree.
33
+
34
+ Import order matters: this file must come BEFORE `_high-contrast.css`,
35
+ whose `@media (forced-colors: active)` block names `[data-theme="light"]`
36
+ at the same specificity and has to win — the same constraint that puts
37
+ `_high-contrast-dark.css` above `_high-contrast.css` too. `_dark.css`'s
38
+ `prefers-color-scheme` branch already excludes `[data-theme="light"]`
39
+ roots, so those two never fight. */
40
+
41
+ [data-theme="light"] {
42
+ /* ===== Surface (backgrounds) ===== */
43
+ --color-surface: var(--color-white);
44
+ --color-surface-raised: var(--color-white);
45
+ --color-surface-overlay: var(--color-white);
46
+ --color-surface-sunken: var(--color-gray-50);
47
+ --color-surface-muted: var(--color-gray-100);
48
+
49
+ /* ===== Foreground (text/icons) ===== */
50
+ --color-fg: var(--color-gray-900);
51
+ --color-fg-muted: var(--color-gray-600);
52
+ --color-fg-subtle: var(--color-gray-500);
53
+
54
+ /* ===== Border ===== */
55
+ --color-border: var(--color-gray-500);
56
+ --color-border-muted: var(--color-gray-200);
57
+ --color-border-strong: var(--color-gray-600);
58
+
59
+ /* ===== Primary ===== */
60
+ --color-primary-50: var(--color-blue-50);
61
+ --color-primary-100: var(--color-blue-100);
62
+ --color-primary-200: var(--color-blue-200);
63
+ --color-primary-300: var(--color-blue-300);
64
+ --color-primary-400: var(--color-blue-400);
65
+ --color-primary-500: var(--color-blue-500);
66
+ --color-primary-600: var(--color-blue-600);
67
+ --color-primary-700: var(--color-blue-700);
68
+ --color-primary-800: var(--color-blue-800);
69
+ --color-primary-900: var(--color-blue-900);
70
+ --color-primary-950: var(--color-blue-950);
71
+
72
+ /* ===== Secondary ===== */
73
+ --color-secondary-50: var(--color-slate-50);
74
+ --color-secondary-100: var(--color-slate-100);
75
+ --color-secondary-200: var(--color-slate-200);
76
+ --color-secondary-300: var(--color-slate-300);
77
+ --color-secondary-400: var(--color-slate-400);
78
+ --color-secondary-500: var(--color-slate-500);
79
+ --color-secondary-600: var(--color-slate-600);
80
+ --color-secondary-700: var(--color-slate-700);
81
+ --color-secondary-800: var(--color-slate-800);
82
+ --color-secondary-900: var(--color-slate-900);
83
+ --color-secondary-950: var(--color-slate-950);
84
+
85
+ /* ===== Accent ===== */
86
+ --color-accent-50: var(--color-violet-50);
87
+ --color-accent-100: var(--color-violet-100);
88
+ --color-accent-200: var(--color-violet-200);
89
+ --color-accent-300: var(--color-violet-300);
90
+ --color-accent-400: var(--color-violet-400);
91
+ --color-accent-500: var(--color-violet-500);
92
+ --color-accent-600: var(--color-violet-600);
93
+ --color-accent-700: var(--color-violet-700);
94
+ --color-accent-800: var(--color-violet-800);
95
+ --color-accent-900: var(--color-violet-900);
96
+ --color-accent-950: var(--color-violet-950);
97
+
98
+ /* ===== Neutral ===== */
99
+ --color-neutral-50: var(--color-gray-50);
100
+ --color-neutral-100: var(--color-gray-100);
101
+ --color-neutral-200: var(--color-gray-200);
102
+ --color-neutral-300: var(--color-gray-300);
103
+ --color-neutral-400: var(--color-gray-400);
104
+ --color-neutral-500: var(--color-gray-500);
105
+ --color-neutral-600: var(--color-gray-600);
106
+ --color-neutral-700: var(--color-gray-700);
107
+ --color-neutral-800: var(--color-gray-800);
108
+ --color-neutral-900: var(--color-gray-900);
109
+ --color-neutral-950: var(--color-gray-950);
110
+
111
+ /* ===== Info ===== */
112
+ --color-info-50: var(--color-sky-50);
113
+ --color-info-100: var(--color-sky-100);
114
+ --color-info-200: var(--color-sky-200);
115
+ --color-info-300: var(--color-sky-300);
116
+ --color-info-400: var(--color-sky-400);
117
+ --color-info-500: var(--color-sky-500);
118
+ --color-info-600: var(--color-sky-600);
119
+ --color-info-700: var(--color-sky-700);
120
+ --color-info-800: var(--color-sky-800);
121
+ --color-info-900: var(--color-sky-900);
122
+ --color-info-950: var(--color-sky-950);
123
+
124
+ /* ===== Success ===== */
125
+ --color-success-50: var(--color-green-50);
126
+ --color-success-100: var(--color-green-100);
127
+ --color-success-200: var(--color-green-200);
128
+ --color-success-300: var(--color-green-300);
129
+ --color-success-400: var(--color-green-400);
130
+ --color-success-500: var(--color-green-500);
131
+ --color-success-600: var(--color-green-600);
132
+ --color-success-700: var(--color-green-700);
133
+ --color-success-800: var(--color-green-800);
134
+ --color-success-900: var(--color-green-900);
135
+ --color-success-950: var(--color-green-950);
136
+
137
+ /* ===== Warning ===== */
138
+ --color-warning-50: var(--color-amber-50);
139
+ --color-warning-100: var(--color-amber-100);
140
+ --color-warning-200: var(--color-amber-200);
141
+ --color-warning-300: var(--color-amber-300);
142
+ --color-warning-400: var(--color-amber-400);
143
+ --color-warning-500: var(--color-amber-500);
144
+ --color-warning-600: var(--color-amber-600);
145
+ --color-warning-700: var(--color-amber-700);
146
+ --color-warning-800: var(--color-amber-800);
147
+ --color-warning-900: var(--color-amber-900);
148
+ --color-warning-950: var(--color-amber-950);
149
+
150
+ /* ===== Error ===== */
151
+ --color-error-50: var(--color-red-50);
152
+ --color-error-100: var(--color-red-100);
153
+ --color-error-200: var(--color-red-200);
154
+ --color-error-300: var(--color-red-300);
155
+ --color-error-400: var(--color-red-400);
156
+ --color-error-500: var(--color-red-500);
157
+ --color-error-600: var(--color-red-600);
158
+ --color-error-700: var(--color-red-700);
159
+ --color-error-800: var(--color-red-800);
160
+ --color-error-900: var(--color-red-900);
161
+ --color-error-950: var(--color-red-950);
162
+
163
+ /* ===== Role slot tokens (light) =====
164
+
165
+ ===== `-border` / `-border-strong`: raised for SC 1.4.11 on 2026-09-04 =====
166
+
167
+ The seven coloured `-border` tokens were `{role}-300`, measuring
168
+ 1.40–1.92:1 against `--color-surface` (white) — the worst of the four
169
+ schemes against the 3:1 non-text-contrast floor, and in the DEFAULT one.
170
+ They are the only boundary of the alert `outline` variant (`alert.ts:50` —
171
+ transparent background, so nothing else marks the container), which makes
172
+ them identifying, not decorative. `info`, `success` and `warning` failed
173
+ the same floor on `-border-strong` too (2.15–2.71 on surface, 2.07–2.54 on
174
+ their own `-soft` fill), so three of the four tiers below move on their own
175
+ evidence rather than as a knock-on.
176
+
177
+ Rule for `-border` — the LIGHTEST palette step measuring ≥ 3.4:1 against
178
+ `--color-surface`. This is `_dark.css`'s rule read in light's direction: on
179
+ white, contrast rises with the step number, so "dimmest passing step" and
180
+ "lightest passing step" are the same instruction about keeping the tier as
181
+ subtle as the floor allows. The 0.4 margin over 3:1 is what stops a palette
182
+ retune dropping the token below it silently. Applied to grey it re-derives
183
+ `gray-500` — the value `--color-border` already ships — which is what makes
184
+ it the right rule rather than one fitted to this table.
185
+
186
+ role was now on surface on soft step below (fails)
187
+ primary blue-300 blue-500 3.76 3.45 blue-400 2.64
188
+ secondary slate-300 slate-500 4.77 4.55 slate-400 2.63
189
+ accent violet-300 violet-500 4.40 4.01 violet-400 2.85
190
+ info sky-300 sky-600 4.02 3.77 sky-500 2.71
191
+ success green-300 green-700 4.94 4.72 green-600 3.22
192
+ warning amber-300 amber-700 5.05 4.87 amber-600 3.19
193
+ error red-300 red-500 3.82 3.50 red-400 2.89
194
+ neutral (--color-border, gray-500) 4.84 4.39 gray-400 2.60
195
+
196
+ `success` and `warning` land two steps further than the rest because
197
+ green-600 (3.22 / 3.07) and amber-600 (3.19 / 3.08) clear the 3:1 floor by
198
+ 0.07 on the soft fill — inside the margin the rule exists to keep. The
199
+ spread of steps is the hues differing in luminance, not an inconsistency;
200
+ `_dark.css` produced the same spread from the same rule.
201
+
202
+ Rule for `-border-strong` — the next palette step darker than that role's
203
+ `-border`. Every role clears both floors with room (4.36–7.23 on `-soft`,
204
+ 4.76–7.56 on surface) and stays strictly darker than `-border`, so the two
205
+ tiers remain distinguishable; `theme-contrast.spec.ts` asserts both halves.
206
+
207
+ Known consequence, considered and accepted: for `primary`, `accent`, `info`
208
+ and `error` the new `-border-strong` now equals that role's `-solid`, so the
209
+ 1px rim on a solid-filled indicator (`stepper.ts`, `timeline.ts`:
210
+ `bg-{role}-solid border border-{role}-border-strong`) no longer reads as a
211
+ separate edge. Those indicators carry their emphasis through the fill and
212
+ the `ring-4 ring-{role}-soft` halo; buying the rim back costs two more steps
213
+ of darkening on every ring in the scheme, which is the worse trade.
214
+
215
+ Re-measure with `docs/research/2026-09-audit/p8-border-steps.mjs light`;
216
+ do not estimate.
217
+ */
218
+
219
+ /* ----- Primary (blue) ----- */
220
+ --color-primary-soft: var(--color-primary-50);
221
+ --color-primary-soft-hover: var(--color-primary-100);
222
+ --color-primary-soft-fg: var(--color-primary-900);
223
+ --color-primary-soft-fg-muted: var(--color-primary-800);
224
+ --color-primary-solid: var(--color-primary-600);
225
+ --color-primary-solid-hover: var(--color-primary-700);
226
+ --color-primary-solid-fg: var(--color-white);
227
+ --color-primary-border: var(--color-primary-500);
228
+ --color-primary-border-strong: var(--color-primary-600);
229
+ --color-primary-fg: var(--color-primary-700);
230
+ --color-primary-icon: var(--color-primary-600);
231
+
232
+ /* ----- Secondary (slate) ----- */
233
+ --color-secondary-soft: var(--color-secondary-50);
234
+ --color-secondary-soft-hover: var(--color-secondary-100);
235
+ --color-secondary-soft-fg: var(--color-secondary-900);
236
+ --color-secondary-soft-fg-muted: var(--color-secondary-800);
237
+ --color-secondary-solid: var(--color-secondary-700);
238
+ --color-secondary-solid-hover: var(--color-secondary-800);
239
+ --color-secondary-solid-fg: var(--color-white);
240
+ --color-secondary-border: var(--color-secondary-500);
241
+ --color-secondary-border-strong: var(--color-secondary-600);
242
+ --color-secondary-fg: var(--color-secondary-700);
243
+ --color-secondary-icon: var(--color-secondary-600);
244
+
245
+ /* ----- Accent (violet) ----- */
246
+ --color-accent-soft: var(--color-accent-50);
247
+ --color-accent-soft-hover: var(--color-accent-100);
248
+ --color-accent-soft-fg: var(--color-accent-900);
249
+ --color-accent-soft-fg-muted: var(--color-accent-800);
250
+ --color-accent-solid: var(--color-accent-600);
251
+ --color-accent-solid-hover: var(--color-accent-700);
252
+ --color-accent-solid-fg: var(--color-white);
253
+ --color-accent-border: var(--color-accent-500);
254
+ --color-accent-border-strong: var(--color-accent-600);
255
+ --color-accent-fg: var(--color-accent-700);
256
+ --color-accent-icon: var(--color-accent-600);
257
+
258
+ /* ----- Neutral ----- (uses surface/fg tokens so dark mode is automatic) */
259
+ --color-neutral-soft: var(--color-surface-muted);
260
+ --color-neutral-soft-hover: var(--color-surface-sunken);
261
+ --color-neutral-soft-fg: var(--color-fg);
262
+ --color-neutral-soft-fg-muted: var(--color-fg-muted);
263
+ --color-neutral-solid: var(--color-fg);
264
+ --color-neutral-solid-hover: var(--color-gray-700);
265
+ --color-neutral-solid-fg: var(--color-surface);
266
+ --color-neutral-border: var(--color-border);
267
+ --color-neutral-border-strong: var(--color-border-strong);
268
+ --color-neutral-fg: var(--color-fg);
269
+ --color-neutral-icon: var(--color-fg-muted);
270
+
271
+ /* ----- Info (sky) ----- */
272
+ --color-info-soft: var(--color-info-50);
273
+ --color-info-soft-hover: var(--color-info-100);
274
+ --color-info-soft-fg: var(--color-info-900);
275
+ --color-info-soft-fg-muted: var(--color-info-800);
276
+ --color-info-solid: var(--color-info-700);
277
+ --color-info-solid-hover: var(--color-info-800);
278
+ --color-info-solid-fg: var(--color-white);
279
+ --color-info-border: var(--color-info-600);
280
+ --color-info-border-strong: var(--color-info-700);
281
+ --color-info-fg: var(--color-info-700);
282
+ --color-info-icon: var(--color-info-600);
283
+
284
+ /* ----- Success (green) ----- */
285
+ --color-success-soft: var(--color-success-50);
286
+ --color-success-soft-hover: var(--color-success-100);
287
+ --color-success-soft-fg: var(--color-success-900);
288
+ --color-success-soft-fg-muted: var(--color-success-800);
289
+ --color-success-solid: var(--color-success-700);
290
+ --color-success-solid-hover: var(--color-success-800);
291
+ --color-success-solid-fg: var(--color-white);
292
+ --color-success-border: var(--color-success-700);
293
+ --color-success-border-strong: var(--color-success-800);
294
+ --color-success-fg: var(--color-success-700);
295
+ --color-success-icon: var(--color-success-600);
296
+
297
+ /* ----- Warning (amber) ----- */
298
+ --color-warning-soft: var(--color-warning-50);
299
+ --color-warning-soft-hover: var(--color-warning-100);
300
+ --color-warning-soft-fg: var(--color-warning-900);
301
+ --color-warning-soft-fg-muted: var(--color-warning-800);
302
+ --color-warning-solid: var(--color-warning-500);
303
+ --color-warning-solid-hover: var(--color-warning-600);
304
+ --color-warning-solid-fg: var(--color-warning-950);
305
+ --color-warning-border: var(--color-warning-700);
306
+ --color-warning-border-strong: var(--color-warning-800);
307
+ --color-warning-fg: var(--color-warning-800);
308
+ --color-warning-icon: var(--color-warning-600);
309
+
310
+ /* ----- Error (red) ----- */
311
+ --color-error-soft: var(--color-error-50);
312
+ --color-error-soft-hover: var(--color-error-100);
313
+ --color-error-soft-fg: var(--color-error-900);
314
+ --color-error-soft-fg-muted: var(--color-error-800);
315
+ --color-error-solid: var(--color-error-600);
316
+ --color-error-solid-hover: var(--color-error-700);
317
+ --color-error-solid-fg: var(--color-white);
318
+ --color-error-border: var(--color-error-500);
319
+ --color-error-border-strong: var(--color-error-600);
320
+ --color-error-fg: var(--color-error-700);
321
+ --color-error-icon: var(--color-error-600);
322
+
323
+ /* ===== Legacy on-role aliases — see note in `_semantic.css` ===== */
324
+ --color-on-info: var(--color-info-solid-fg);
325
+ --color-on-success: var(--color-success-solid-fg);
326
+ --color-on-warning: var(--color-warning-solid-fg);
327
+ --color-on-error: var(--color-error-solid-fg);
328
+ --color-on-primary: var(--color-primary-solid-fg);
329
+ --color-on-secondary: var(--color-secondary-solid-fg);
330
+ --color-on-accent: var(--color-accent-solid-fg);
331
+ --color-on-neutral: var(--color-neutral-solid-fg);
332
+ }
@@ -22,10 +22,31 @@
22
22
  --color-fg-muted: var(--color-gray-600);
23
23
  --color-fg-subtle: var(--color-gray-500);
24
24
 
25
- /* ===== Border ===== */
26
- --color-border: var(--color-gray-300);
25
+ /* ===== Border =====
26
+ `--color-border` and `--color-border-strong` carry the boundary that
27
+ IDENTIFIES a control — the outline of an input, a checkbox, a select
28
+ trigger. WCAG 2.2 SC 1.4.11 (Non-text Contrast) requires 3:1 for exactly
29
+ that, and for an unchecked checkbox the border IS the component. Measured
30
+ against `--color-surface`, gray-300 gave 1.47:1 and gray-400 gave 2.60:1,
31
+ so both failed; the values below are the first palette steps that clear
32
+ 3:1 (4.84:1 and 7.56:1 in light, 4.16:1 and 7.73:1 in dark).
33
+ (The dark `-strong` figure read 8.59 until 2026-09-03; measured it is
34
+ 7.73, and no plausible pairing reproduces 8.59 — gray-400 on gray-900 is
35
+ 6.82. The verdict is unchanged: it was and is the first step clearing 3:1.
36
+ Re-measure with `scratchpad/p6-pairs.mjs` rather than estimating.)
37
+
38
+ `--color-border-muted` is deliberately NOT raised. It is the decorative
39
+ divider — ghost-variant footers, subtle rules between rows — and SC 1.4.11
40
+ exempts boundaries that are purely decorative and not needed to identify a
41
+ component or its state. Raising it would darken every hairline in the
42
+ library for no accessibility gain.
43
+
44
+ axe does not catch any of this: its `color-contrast` rule tests TEXT only,
45
+ so these three tokens were invisible to the a11y sweep and were measured
46
+ by hand. See docs/audit-2026-09-register.md. */
47
+ --color-border: var(--color-gray-500);
27
48
  --color-border-muted: var(--color-gray-200);
28
- --color-border-strong: var(--color-gray-400);
49
+ --color-border-strong: var(--color-gray-600);
29
50
 
30
51
  /* ===== Table sticky shadows =====
31
52
  Hairline 1px shadows used to separate sticky table chrome from scrolled
@@ -36,15 +57,6 @@
36
57
  --shadow-table-sticky-cell-start: 1px 0 0 0 var(--color-border);
37
58
  --shadow-table-sticky-cell-end: -1px 0 0 0 var(--color-border);
38
59
 
39
- /* ===== Calendar widths =====
40
- Pinned per size so month / year / multi-year views share the same footprint
41
- across view transitions. Each value is roughly `cell-size × 7 + gutters`. */
42
- --width-calendar-xs: 210px;
43
- --width-calendar-sm: 240px;
44
- --width-calendar-md: 292px;
45
- --width-calendar-lg: 320px;
46
- --width-calendar-xl: 376px;
47
-
48
60
  /* ===== Extra-small typography =====
49
61
  Used for xs-density secondary text (xs descriptions, calendar cell labels,
50
62
  keyboard hints). Sits one step below Tailwind's `text-xs` (0.75rem).
@@ -176,6 +188,28 @@
176
188
  -solid-fg text on -solid (AA body)
177
189
  -border subtle border (outline variant, dividers)
178
190
  -border-strong accent border (indicators, rings)
191
+
192
+ `-border` reads as "subtle", but it is NOT decorative the way
193
+ `--color-border-muted` is: it is the alert `outline` variant's only
194
+ boundary (`alert.ts:50`, transparent background), so SC 1.4.11's 3:1
195
+ applies to it. All four schemes now clear that floor, on both tiers:
196
+
197
+ scheme {role}-border on surface 3:1?
198
+ light see `_light.css` 3.76 – 5.05 ✓ (raised 2026-09-04)
199
+ dark see `_dark.css` 3.42 – 4.22 ✓ (raised 2026-09-03)
200
+ high-contrast {hue}-700 4.94 – 10.34 ✓
201
+ high-contrast-dark {hue}-300 10.93 – 15.02 ✓
202
+
203
+ The ✓/✗ column is ENFORCED — `theme-contrast.spec.ts` recomputes it for
204
+ every scheme on every run, over `-border` AND `-border-strong`, against
205
+ both `--color-surface` and the role's own `-soft` fill. Its `KNOWN_FAILING`
206
+ allowance list is now EMPTY, and the assertion is two-sided: an entry that
207
+ stops failing turns the list red, so no scheme can carry a permanent
208
+ exemption. The ranges and step names above are indicative and were measured
209
+ on 2026-09-04; if you need a current number, re-run the harness rather than
210
+ quoting this — `docs/research/2026-09-audit/p6-contrast.mjs <scheme>
211
+ <baseline>` for a whole scheme, `p8-border-steps.mjs <scheme>` for the
212
+ per-step border table. Do not estimate.
179
213
  -fg colored text on neutral surface (tab labels, links)
180
214
  -icon icon tint on -soft / surface contexts
181
215
 
@@ -201,8 +235,8 @@
201
235
  --color-primary-solid: var(--color-primary-600);
202
236
  --color-primary-solid-hover: var(--color-primary-700);
203
237
  --color-primary-solid-fg: var(--color-white);
204
- --color-primary-border: var(--color-primary-300);
205
- --color-primary-border-strong: var(--color-primary-500);
238
+ --color-primary-border: var(--color-primary-500);
239
+ --color-primary-border-strong: var(--color-primary-600);
206
240
  --color-primary-fg: var(--color-primary-700);
207
241
  --color-primary-icon: var(--color-primary-600);
208
242
 
@@ -214,8 +248,8 @@
214
248
  --color-secondary-solid: var(--color-secondary-700);
215
249
  --color-secondary-solid-hover: var(--color-secondary-800);
216
250
  --color-secondary-solid-fg: var(--color-white);
217
- --color-secondary-border: var(--color-secondary-300);
218
- --color-secondary-border-strong: var(--color-secondary-500);
251
+ --color-secondary-border: var(--color-secondary-500);
252
+ --color-secondary-border-strong: var(--color-secondary-600);
219
253
  --color-secondary-fg: var(--color-secondary-700);
220
254
  --color-secondary-icon: var(--color-secondary-600);
221
255
 
@@ -227,8 +261,8 @@
227
261
  --color-accent-solid: var(--color-accent-600);
228
262
  --color-accent-solid-hover: var(--color-accent-700);
229
263
  --color-accent-solid-fg: var(--color-white);
230
- --color-accent-border: var(--color-accent-300);
231
- --color-accent-border-strong: var(--color-accent-500);
264
+ --color-accent-border: var(--color-accent-500);
265
+ --color-accent-border-strong: var(--color-accent-600);
232
266
  --color-accent-fg: var(--color-accent-700);
233
267
  --color-accent-icon: var(--color-accent-600);
234
268
 
@@ -254,8 +288,8 @@
254
288
  --color-info-solid: var(--color-info-700);
255
289
  --color-info-solid-hover: var(--color-info-800);
256
290
  --color-info-solid-fg: var(--color-white);
257
- --color-info-border: var(--color-info-300);
258
- --color-info-border-strong: var(--color-info-500);
291
+ --color-info-border: var(--color-info-600);
292
+ --color-info-border-strong: var(--color-info-700);
259
293
  --color-info-fg: var(--color-info-700);
260
294
  --color-info-icon: var(--color-info-600);
261
295
 
@@ -268,8 +302,8 @@
268
302
  --color-success-solid: var(--color-success-700);
269
303
  --color-success-solid-hover: var(--color-success-800);
270
304
  --color-success-solid-fg: var(--color-white);
271
- --color-success-border: var(--color-success-300);
272
- --color-success-border-strong: var(--color-success-500);
305
+ --color-success-border: var(--color-success-700);
306
+ --color-success-border-strong: var(--color-success-800);
273
307
  --color-success-fg: var(--color-success-700);
274
308
  --color-success-icon: var(--color-success-600);
275
309
 
@@ -283,8 +317,8 @@
283
317
  --color-warning-solid: var(--color-warning-500);
284
318
  --color-warning-solid-hover: var(--color-warning-600);
285
319
  --color-warning-solid-fg: var(--color-warning-950);
286
- --color-warning-border: var(--color-warning-300);
287
- --color-warning-border-strong: var(--color-warning-500);
320
+ --color-warning-border: var(--color-warning-700);
321
+ --color-warning-border-strong: var(--color-warning-800);
288
322
  /* -fg uses -800: amber-700/white is 3.4:1 (AA fail). amber-800/white is 6.5:1. */
289
323
  --color-warning-fg: var(--color-warning-800);
290
324
  --color-warning-icon: var(--color-warning-600);
@@ -297,8 +331,8 @@
297
331
  --color-error-solid: var(--color-error-600);
298
332
  --color-error-solid-hover: var(--color-error-700);
299
333
  --color-error-solid-fg: var(--color-white);
300
- --color-error-border: var(--color-error-300);
301
- --color-error-border-strong: var(--color-error-500);
334
+ --color-error-border: var(--color-error-500);
335
+ --color-error-border-strong: var(--color-error-600);
302
336
  --color-error-fg: var(--color-error-700);
303
337
  --color-error-icon: var(--color-error-600);
304
338
 
@@ -3,6 +3,23 @@
3
3
  --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
4
4
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace;
5
5
 
6
+ /* ===== Font sizes — line-heights pinned in `rem`, deliberately =====
7
+ Tailwind's defaults are UNITLESS ratios (e.g. `--text-sm--line-height:
8
+ calc(1.25 / 0.875)`). A consumer who re-units `--text-sm` therefore
9
+ rescales every line box, which silently overflows controls whose height is
10
+ pinned. Absolute values make the line box a fixed 4px multiple that cannot
11
+ be rescaled out from under a pinned height.
12
+
13
+ These reproduce Tailwind's own COMPUTED defaults exactly (16 / 20 / 24px),
14
+ so the visual diff of adopting them is zero. This is robustness, not a
15
+ redesign — do not "simplify" them back to ratios. */
16
+ --text-xs: 0.75rem;
17
+ --text-xs--line-height: 1rem; /* 12 / 16 */
18
+ --text-sm: 0.875rem;
19
+ --text-sm--line-height: 1.25rem; /* 14 / 20 */
20
+ --text-base: 1rem;
21
+ --text-base--line-height: 1.5rem; /* 16 / 24 */
22
+
6
23
  /* ===== Animation durations ===== */
7
24
  --duration-fast: 150ms;
8
25
  --duration-normal: 200ms;
package/theme/index.css CHANGED
@@ -3,23 +3,85 @@
3
3
  /* ===== Dark variant binding =====
4
4
  Re-binds Tailwind's `dark:` variant so it activates on the same condition
5
5
  that flips the semantic tokens in `_dark.css`:
6
- 1. an explicit `[data-theme="dark"]` ancestor, OR
7
- 2. `prefers-color-scheme: dark` AND no explicit `data-theme` opt-out.
6
+ 1. an explicit `[data-theme="dark"]` or `[data-theme="high-contrast-dark"]`
7
+ ancestor, OR
8
+ 2. `prefers-color-scheme: dark` AND no explicit `data-theme` opt-out,
9
+ and in BOTH cases only while no nearer `[data-theme="light"]` /
10
+ `[data-theme="high-contrast"]` ancestor has opted the subtree back out.
11
+
12
+ `high-contrast-dark` counts as dark here because it IS dark — a subtree
13
+ scoped to it must keep the same `dark:` utilities a `dark` subtree gets, or
14
+ consumer overrides silently stop applying inside it.
8
15
 
9
16
  Without this binding `dark:` defaults to `@media (prefers-color-scheme: dark)`,
10
17
  which drifts from the `[data-theme="dark"]` selector — producing inverted
11
18
  token state but un-inverted dark utilities (or vice versa) whenever OS
12
- preference disagrees with the consumer's chosen theme. Keep this rule in
13
- lock-step with the activation predicates in `_dark.css`. */
19
+ preference disagrees with the consumer's chosen theme.
20
+
21
+ Keep this rule in lock-step with the activation predicates in `_dark.css`
22
+ and `_light.css` — with ONE deliberate divergence, stated here so a later
23
+ pass does not "fix" it into a bug. `_dark.css`'s media branch excludes
24
+ `[data-theme="high-contrast-dark"]` roots, because a root asking for the
25
+ dark high-contrast TOKENS must not be handed the plain dark ones. The media
26
+ branch below does NOT exclude them, because a root asking for dark high
27
+ contrast is still asking for dark, and `dark:` utilities must keep applying
28
+ there. The two predicates answer different questions — "which token set" and
29
+ "is this dark" — and only agree on three of the four schemes.
30
+
31
+ The `:not(:where(…))` exclusions carry zero specificity, so they cannot
32
+ change how a consumer's own `dark:` utility resolves against their other
33
+ rules — they only narrow *when* it applies. Both branches need one, but the
34
+ two are deliberately NOT the same shape:
35
+
36
+ - The media branch excludes any `[data-theme="light"]` /
37
+ `[data-theme="high-contrast"]` ancestor outright. Re-entering dark below
38
+ such a subtree is still handled, because the explicit branch above matches
39
+ it independently.
40
+ - The explicit branch can only exclude a light/high-contrast boundary that
41
+ sits *below* a dark one (`[data-theme="dark"] [data-theme="light"] *`).
42
+ The plain form would also strip `dark:` from a dark subtree nested inside
43
+ a light one, where it is correct — CSS has no "nearest themed ancestor"
44
+ combinator, and inherited custom properties get that semantic for free
45
+ while selectors do not. The residual gap is depth-3 alternation
46
+ (dark → light → dark), which is no worse than before this rule existed.
47
+
48
+ With two dark schemes and two light ones that exclusion is a 2×2 product,
49
+ so it is written with nested `:where()` groups rather than four spelled-out
50
+ descendant pairs. `:where()` contributes zero specificity and the whole
51
+ thing already sits inside a zero-specificity `:not(:where(…))`, so the
52
+ grouped form is exactly equivalent to the enumeration — just not four times
53
+ as long.
54
+
55
+ The library ships no `dark:` variants of its own, so this is consumer-facing
56
+ only. */
14
57
  @custom-variant dark {
15
- &:where([data-theme="dark"], [data-theme="dark"] *) {
58
+ &:where(
59
+ [data-theme="dark"],
60
+ [data-theme="dark"] *,
61
+ [data-theme="high-contrast-dark"],
62
+ [data-theme="high-contrast-dark"] *
63
+ ):not(
64
+ :where(
65
+ :where([data-theme="dark"], [data-theme="high-contrast-dark"])
66
+ :where([data-theme="light"], [data-theme="high-contrast"]),
67
+ :where([data-theme="dark"], [data-theme="high-contrast-dark"])
68
+ :where([data-theme="light"], [data-theme="high-contrast"]) *
69
+ )
70
+ ) {
16
71
  @slot;
17
72
  }
18
73
  @media (prefers-color-scheme: dark) {
19
74
  &:where(
20
75
  :root:not([data-theme="light"]):not([data-theme="high-contrast"]),
21
76
  :root:not([data-theme="light"]):not([data-theme="high-contrast"]) *
22
- ) {
77
+ ):not(
78
+ :where(
79
+ [data-theme="light"],
80
+ [data-theme="light"] *,
81
+ [data-theme="high-contrast"],
82
+ [data-theme="high-contrast"] *
83
+ )
84
+ ) {
23
85
  @slot;
24
86
  }
25
87
  }
@@ -54,8 +116,25 @@
54
116
  /* Semantic token definitions */
55
117
  @import "./_semantic.css";
56
118
 
57
- /* Theme overrides */
119
+ /* Theme overrides.
120
+ `_high-contrast.css` must stay LAST of the four, and every other scheme file
121
+ before it. Each scheme's own block is a bare `[data-theme=…]` at specificity
122
+ 0,1,0, and `_high-contrast.css`'s `@media (forced-colors: active)` list
123
+ names all four of them at that same 0,1,0 — so source order is the only
124
+ tie-breaker and the forced-colors remap has to come last to win. That is why
125
+ `_light.css` leads and why `_high-contrast-dark.css` sits above
126
+ `_high-contrast.css` rather than below it.
127
+
128
+ Between the first three the order is grouping, not cascade: `[data-theme]`
129
+ values are matched exactly, so no two scheme blocks can ever apply to the
130
+ same element. `_high-contrast-dark.css` sits next to `_dark.css` because it
131
+ is the dark family's contrast variant, and because `_dark.css`'s
132
+ `prefers-color-scheme` branch has to exclude it by name — that branch is
133
+ 0,4,0 and would otherwise outrank it. See the header of
134
+ `_high-contrast-dark.css`. */
135
+ @import "./_light.css";
58
136
  @import "./_dark.css";
137
+ @import "./_high-contrast-dark.css";
59
138
  @import "./_high-contrast.css";
60
139
 
61
140
  /* Base/reset */
@@ -4,7 +4,13 @@ import { CollapsibleGroupComponent } from '@cdevhub/ngx-tw/collapsible';
4
4
  /** Open mode of the accordion. */
5
5
  type AccordionType = 'single' | 'multiple';
6
6
  /** Visual style of the accordion container. */
7
- type AccordionVariant = 'default' | 'bordered' | 'ghost';
7
+ type AccordionVariant = 'default' | 'outline' | 'ghost' | AccordionVariantLegacy;
8
+ /**
9
+ * Legacy `variant` spellings, kept so existing templates keep compiling.
10
+ * @deprecated `'bordered'` is an alias for `'outline'` and renders identically.
11
+ * It will be removed in the next major — prefer `'outline'`.
12
+ */
13
+ type AccordionVariantLegacy = 'bordered';
8
14
  /**
9
15
  * Accordion — single- or multiple-open-panel group built on top of
10
16
  * `<tw-collapsible>` children. Extends `CollapsibleGroupComponent` to inherit
@@ -24,16 +30,18 @@ type AccordionVariant = 'default' | 'bordered' | 'ghost';
24
30
  declare class AccordionComponent extends CollapsibleGroupComponent {
25
31
  /** Open mode. `'single'` allows one panel open at a time; `'multiple'` allows many. Defaults to `'single'`. */
26
32
  readonly type: _angular_core.InputSignal<AccordionType>;
27
- /** Visual style of the accordion container. Defaults to `'default'`. */
33
+ /** Visual style of the accordion container. Defaults to `'default'`. `'bordered'` is a deprecated alias for `'outline'` and renders identically. */
28
34
  readonly variant: _angular_core.InputSignal<AccordionVariant>;
29
35
  /** In `'single'` mode, whether re-clicking the open panel closes it. Defaults to `true` — accordions are collapsible by definition; opt-out only. */
30
36
  readonly collapsible: _angular_core.InputSignalWithTransform<boolean, unknown>;
31
- /** Accessible name for the accordion. Use when surrounding context doesn't make the purpose obvious. */
37
+ /** Accessible name for the accordion. Use when surrounding context doesn't make the purpose obvious. Defaults to `undefined`. Alias: `aria-label`. */
32
38
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
33
- /** ID(s) of element(s) that label the accordion. Use instead of `aria-label` when a visible heading is available. */
39
+ /** ID(s) of element(s) that label the accordion. Use instead of `aria-label` when a visible heading is available. Defaults to `undefined`. Alias: `aria-labelledby`. */
34
40
  readonly ariaLabelledby: _angular_core.InputSignal<string | undefined>;
35
41
  /** @internal APG: accordions don't carry `role="group"`. */
36
42
  readonly hostRole: _angular_core.Signal<string | null>;
43
+ /** @internal Canonical variant with legacy spellings folded in. */
44
+ private readonly resolvedVariant;
37
45
  /** @internal Variant-driven container classes; replaces the parent's default group string. */
38
46
  readonly hostClasses: _angular_core.Signal<string>;
39
47
  /** @internal Drive single-open-panel behaviour from `type`, ignoring the inherited `accordion` input. */