@livenetworks/ashlar 2.0.7 → 2.0.9

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 (213) hide show
  1. package/LICENSE +641 -641
  2. package/components/COMPONENTS.md +1116 -1116
  3. package/components/index.js +81 -81
  4. package/components/ln-accordion/ln-accordion-dev.scss +8 -8
  5. package/components/ln-accordion/ln-accordion.js +1 -1
  6. package/components/ln-accordion/ln-accordion.schema.json +30 -30
  7. package/components/ln-ajax/ln-ajax-dev.scss +8 -8
  8. package/components/ln-ajax/ln-ajax.js +1 -1
  9. package/components/ln-ajax/ln-ajax.schema.json +30 -30
  10. package/components/ln-api-connector/ln-api-connector.js +1 -1
  11. package/components/ln-api-connector/ln-api-connector.schema.json +9 -0
  12. package/components/ln-api-connector/src/ln-api-connector.js +2 -0
  13. package/components/ln-api-queue/ln-api-queue.js +1 -1
  14. package/components/ln-api-queue/ln-api-queue.schema.json +34 -34
  15. package/components/ln-api-queue/src/ln-api-queue.js +3 -13
  16. package/components/ln-autoresize/ln-autoresize-dev.scss +8 -8
  17. package/components/ln-autoresize/ln-autoresize.js +1 -1
  18. package/components/ln-autoresize/ln-autoresize.schema.json +22 -22
  19. package/components/ln-autosave/ln-autosave-dev.scss +13 -13
  20. package/components/ln-autosave/ln-autosave.js +1 -1
  21. package/components/ln-autosave/ln-autosave.schema.json +48 -48
  22. package/components/ln-autosave/src/autosave-model.js +34 -34
  23. package/components/ln-chart/ln-chart.js +1 -1
  24. package/components/ln-chart/ln-chart.schema.json +146 -146
  25. package/components/ln-chart/src/chart-model.js +154 -154
  26. package/components/ln-circular-progress/ln-circular-progress.js +1 -1
  27. package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -42
  28. package/components/ln-confirm/ln-confirm-dev.scss +24 -24
  29. package/components/ln-confirm/ln-confirm.js +1 -1
  30. package/components/ln-confirm/ln-confirm.schema.json +66 -66
  31. package/components/ln-confirm/src/ln-confirm.js +178 -178
  32. package/components/ln-core/attrs.js +13 -0
  33. package/components/ln-core/crypto.js +286 -265
  34. package/components/ln-core/dom.js +115 -115
  35. package/components/ln-core/form.js +146 -136
  36. package/components/ln-core/helpers.js +33 -33
  37. package/components/ln-core/http.js +48 -48
  38. package/components/ln-core/index.js +1 -1
  39. package/components/ln-core/lifecycle.js +5 -0
  40. package/components/ln-core/ln-core.schema.json +3 -2
  41. package/components/ln-core/locale.js +55 -55
  42. package/components/ln-core/matching.js +78 -78
  43. package/components/ln-core/number.js +125 -125
  44. package/components/ln-core/template.js +206 -206
  45. package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
  46. package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -50
  47. package/components/ln-couchdb-connector/src/ln-couchdb-connector.js +1 -0
  48. package/components/ln-data-coordinator/README.md +9 -38
  49. package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -8
  50. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -1
  51. package/components/ln-data-coordinator/ln-data-coordinator.schema.json +16 -16
  52. package/components/ln-data-coordinator/src/data-read-policy.js +0 -7
  53. package/components/ln-data-coordinator/src/ln-data-coordinator.js +432 -1308
  54. package/components/ln-data-store/ln-data-store-dev.scss +13 -13
  55. package/components/ln-data-store/ln-data-store.js +1 -1
  56. package/components/ln-data-store/ln-data-store.schema.json +84 -84
  57. package/components/ln-data-store/src/data-store-model.js +184 -184
  58. package/components/ln-data-store/src/ln-data-store.js +1 -1
  59. package/components/ln-date/ln-date.js +1 -1
  60. package/components/ln-date/ln-date.schema.json +92 -92
  61. package/components/ln-date/src/date-model.js +186 -186
  62. package/components/ln-debug/ln-debug.js +1 -1
  63. package/components/ln-debug/ln-debug.schema.json +28 -28
  64. package/components/ln-debug/src/console-sink.js +19 -19
  65. package/components/ln-debug/src/gate.js +95 -95
  66. package/components/ln-debug/src/generated-attributes.js +4 -2
  67. package/components/ln-dropdown/ln-dropdown-dev.scss +13 -13
  68. package/components/ln-dropdown/ln-dropdown.js +1 -1
  69. package/components/ln-dropdown/ln-dropdown.schema.json +90 -90
  70. package/components/ln-editor/ln-editor.js +1 -1
  71. package/components/ln-editor/ln-editor.schema.json +58 -58
  72. package/components/ln-external-links/ln-external-links.js +1 -1
  73. package/components/ln-external-links/ln-external-links.schema.json +18 -18
  74. package/components/ln-fill/ln-fill.js +1 -1
  75. package/components/ln-fill/ln-fill.schema.json +23 -23
  76. package/components/ln-filter/ln-filter.js +1 -1
  77. package/components/ln-filter/ln-filter.schema.json +153 -153
  78. package/components/ln-filter/src/filter-model.js +185 -185
  79. package/components/ln-form/ln-form-dev.scss +8 -8
  80. package/components/ln-form/ln-form.js +1 -1
  81. package/components/ln-form/ln-form.schema.json +6 -0
  82. package/components/ln-form/src/ln-form.js +21 -0
  83. package/components/ln-http/ln-http.js +1 -1
  84. package/components/ln-http/ln-http.schema.json +6 -6
  85. package/components/ln-icon/ln-icon.schema.json +6 -6
  86. package/components/ln-include/ln-include.js +1 -1
  87. package/components/ln-include/ln-include.schema.json +23 -23
  88. package/components/ln-key/ln-key-dev.scss +18 -18
  89. package/components/ln-key/ln-key.js +1 -1
  90. package/components/ln-key/ln-key.schema.json +56 -56
  91. package/components/ln-key/src/ln-key.js +10 -10
  92. package/components/ln-link/ln-link-dev.scss +8 -8
  93. package/components/ln-link/ln-link.js +1 -1
  94. package/components/ln-link/ln-link.schema.json +22 -22
  95. package/components/ln-list/README.md +152 -152
  96. package/components/ln-list/ln-list-dev.scss +8 -8
  97. package/components/ln-list/ln-list.js +1 -1
  98. package/components/ln-list/ln-list.schema.json +166 -166
  99. package/components/ln-modal/ln-modal.js +1 -1
  100. package/components/ln-modal/ln-modal.schema.json +65 -65
  101. package/components/ln-nav/ln-nav.js +1 -1
  102. package/components/ln-nav/ln-nav.schema.json +25 -25
  103. package/components/ln-number/ln-number.js +1 -1
  104. package/components/ln-number/ln-number.schema.json +63 -63
  105. package/components/ln-number/src/ln-number.js +26 -0
  106. package/components/ln-number/src/number-model.js +31 -31
  107. package/components/ln-obfuscator/README.md +60 -60
  108. package/components/ln-obfuscator/ln-obfuscator.js +1 -1
  109. package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -49
  110. package/components/ln-obfuscator/src/ln-obfuscator.js +159 -159
  111. package/components/ln-obfuscator/src/obfuscator-model.js +250 -250
  112. package/components/ln-options/ln-options.js +1 -1
  113. package/components/ln-options/ln-options.schema.json +6 -0
  114. package/components/ln-options/src/ln-options.js +4 -4
  115. package/components/ln-persist/README.md +151 -151
  116. package/components/ln-persist/ln-persist.js +1 -1
  117. package/components/ln-persist/ln-persist.schema.json +28 -28
  118. package/components/ln-persist/src/ln-persist.js +83 -83
  119. package/components/ln-picklist/README.md +230 -230
  120. package/components/ln-picklist/ln-picklist-dev.scss +22 -22
  121. package/components/ln-picklist/ln-picklist.js +1 -1
  122. package/components/ln-picklist/ln-picklist.schema.json +49 -49
  123. package/components/ln-picklist/src/ln-picklist.js +228 -228
  124. package/components/ln-popover/ln-popover-dev.scss +13 -13
  125. package/components/ln-popover/ln-popover.js +1 -1
  126. package/components/ln-popover/ln-popover.schema.json +82 -82
  127. package/components/ln-progress/ln-progress-dev.scss +8 -8
  128. package/components/ln-progress/ln-progress.js +1 -1
  129. package/components/ln-progress/ln-progress.schema.json +40 -40
  130. package/components/ln-router/ln-router.js +1 -1
  131. package/components/ln-router/ln-router.schema.json +76 -76
  132. package/components/ln-scroll/README.md +45 -45
  133. package/components/ln-scroll/ln-scroll.js +1 -1
  134. package/components/ln-scroll/ln-scroll.schema.json +85 -85
  135. package/components/ln-scroll/src/ln-scroll.js +150 -150
  136. package/components/ln-search/README.md +188 -188
  137. package/components/ln-search/ln-search.js +1 -1
  138. package/components/ln-search/ln-search.schema.json +103 -103
  139. package/components/ln-slug/ln-slug.js +1 -1
  140. package/components/ln-slug/ln-slug.schema.json +23 -23
  141. package/components/ln-slug/src/ln-slug.js +25 -1
  142. package/components/ln-sort/ln-sort.js +1 -1
  143. package/components/ln-sort/ln-sort.schema.json +104 -104
  144. package/components/ln-sort/src/ln-sort.js +321 -321
  145. package/components/ln-sort/src/sort-model.js +117 -117
  146. package/components/ln-sortable/ln-sortable-dev.scss +13 -13
  147. package/components/ln-sortable/ln-sortable.js +1 -1
  148. package/components/ln-sortable/ln-sortable.schema.json +36 -36
  149. package/components/ln-stat/ln-stat-dev.scss +8 -8
  150. package/components/ln-stat/ln-stat.js +1 -1
  151. package/components/ln-stat/ln-stat.schema.json +32 -32
  152. package/components/ln-stat/src/stat-model.js +28 -28
  153. package/components/ln-table/ln-table.js +1 -1
  154. package/components/ln-table/ln-table.schema.json +211 -211
  155. package/components/ln-table/src/table-model.js +98 -98
  156. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -1
  157. package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -93
  158. package/components/ln-tabs/ln-tabs.js +1 -1
  159. package/components/ln-tabs/ln-tabs.schema.json +75 -75
  160. package/components/ln-tabs/src/ln-tabs.js +208 -208
  161. package/components/ln-tabs/src/tabs-model.js +82 -82
  162. package/components/ln-time/ln-time-dev.scss +13 -13
  163. package/components/ln-time/ln-time.js +1 -1
  164. package/components/ln-time/ln-time.schema.json +38 -38
  165. package/components/ln-toast/ln-toast.js +1 -1
  166. package/components/ln-toast/ln-toast.schema.json +65 -65
  167. package/components/ln-toggle/ln-toggle.js +1 -1
  168. package/components/ln-toggle/ln-toggle.schema.json +52 -52
  169. package/components/ln-tooltip/ln-tooltip.js +1 -1
  170. package/components/ln-tooltip/ln-tooltip.schema.json +86 -86
  171. package/components/ln-translations/ln-translations.js +1 -1
  172. package/components/ln-translations/ln-translations.schema.json +120 -120
  173. package/components/ln-ui-coordinator/README.md +62 -62
  174. package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -1
  175. package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +28 -28
  176. package/components/ln-ui-coordinator/src/ln-ui-coordinator.js +140 -140
  177. package/components/ln-upload/ln-upload.js +1 -1
  178. package/components/ln-upload/ln-upload.schema.json +193 -193
  179. package/components/ln-upload/src/upload-model.js +78 -78
  180. package/components/ln-validate/ln-validate.js +1 -1
  181. package/components/ln-validate/ln-validate.schema.json +50 -50
  182. package/components/ln-validate/src/validate-model.js +64 -64
  183. package/components/ln-websocket-connector/README.md +166 -166
  184. package/components/ln-websocket-connector/ln-websocket-connector.js +1 -1
  185. package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -29
  186. package/components/ln-websocket-connector/src/ln-websocket-connector.js +283 -279
  187. package/ln-ashlar.html-data.json +15 -8
  188. package/package.json +85 -84
  189. package/theme/brand.css +73 -73
  190. package/theme/components/_confirm.scss +6 -6
  191. package/theme/components/_picklist.scss +3 -3
  192. package/theme/config/_palette.scss +274 -274
  193. package/theme/config/_theme.scss +292 -292
  194. package/theme/config/_tokens.scss +285 -285
  195. package/theme/config/mixins/_index.scss +62 -62
  196. package/theme/config/mixins/_picklist.scss +66 -66
  197. package/theme/ln-ashlar-dev.scss +66 -66
  198. package/theme/ln-ashlar-landing.scss +56 -56
  199. package/theme/ln-ashlar-theme.scss +63 -63
  200. package/theme/presentation/_bento.scss +151 -151
  201. package/theme/presentation/_cta.scss +111 -111
  202. package/theme/presentation/_effects.scss +216 -216
  203. package/theme/presentation/_features.scss +108 -108
  204. package/theme/presentation/_footer.scss +129 -129
  205. package/theme/presentation/_hero.scss +158 -158
  206. package/theme/presentation/_layout.scss +170 -170
  207. package/theme/presentation/_navbar.scss +140 -140
  208. package/theme/presentation/_pricing.scss +262 -262
  209. package/theme/presentation/_stats.scss +87 -87
  210. package/theme/presentation/_testimonials.scss +124 -124
  211. package/theme/presentation/_tokens.scss +39 -39
  212. package/theme/presentation/_typography.scss +163 -163
  213. package/web-types.json +26 -12
@@ -1,274 +1,274 @@
1
- // ==========================================================================
2
- // Palette & Color Derivation Mixins — ln-ashlar
3
- // ==========================================================================
4
- // Value mixins + the derivation chain, plus two zero-specificity CSS blocks
5
- // at the bottom (brand, base defaults).
6
- // Defines theme values (light and dark) and the unified color derivation chain.
7
- // ==========================================================================
8
-
9
- @mixin ln-values-light {
10
- // Secondary tint layers
11
- --color-secondary-light: 160 84% 94%;
12
- --color-secondary-lighter: 160 84% 97%;
13
-
14
- // Status colors
15
- --color-success: 142 76% 36%;
16
- --color-success-light: 142 71% 94%;
17
- --color-success-lighter: 142 71% 97%;
18
-
19
- --color-error: 0 84% 48%;
20
- --color-error-light: 0 84% 94%;
21
- --color-error-lighter: 0 84% 97%;
22
-
23
- --color-warning: 32 95% 38%;
24
- --color-warning-light: 38 92% 94%;
25
- --color-warning-lighter: 38 92% 97%;
26
-
27
- --color-info: 200 95% 38%;
28
- --color-info-light: 199 89% 94%;
29
- --color-info-lighter: 199 89% 97%;
30
-
31
- // Neutral scale (canonical greys)
32
- --color-neutral-50: 210 20% 98%;
33
- --color-neutral-100: 220 14% 96%;
34
- --color-neutral-150: 220 13% 93%;
35
- --color-neutral-175: 220 13% 91%;
36
- --color-neutral-200: 220 13% 90%;
37
- --color-neutral-300: 216 12% 84%;
38
- --color-neutral-400: 218 11% 58%;
39
- --color-neutral-500: 220 10% 40%;
40
- --color-neutral-600: 215 14% 34%;
41
- --color-neutral-700: 217 19% 27%;
42
- --color-neutral-800: 215 28% 17%;
43
- --color-neutral-900: 222 47% 11%;
44
-
45
- // Base canvas background
46
- --color-white: 0 0% 100%;
47
-
48
- // Shadows — cool-tinted, dual-layer (ambient + key light)
49
- --shadow-none: none;
50
-
51
- --shadow-xs:
52
- 0 1px 2px 0 hsl(220 40% 10% / 0.05);
53
-
54
- --shadow-sm:
55
- 0 1px 3px 0 hsl(220 40% 10% / 0.07),
56
- 0 1px 2px -1px hsl(220 40% 10% / 0.05);
57
-
58
- --shadow-md:
59
- 0 4px 6px -1px hsl(220 40% 10% / 0.08),
60
- 0 2px 4px -2px hsl(220 40% 10% / 0.05);
61
-
62
- --shadow-lg:
63
- 0 10px 15px -3px hsl(220 40% 10% / 0.08),
64
- 0 4px 6px -4px hsl(220 40% 10% / 0.04);
65
-
66
- --shadow-xl:
67
- 0 20px 25px -5px hsl(220 40% 10% / 0.09),
68
- 0 8px 10px -6px hsl(220 40% 10% / 0.04);
69
-
70
- --shadow-2xl:
71
- 0 25px 50px -12px hsl(220 40% 10% / 0.18);
72
-
73
- --shadow-inner:
74
- inset 0 2px 4px 0 hsl(220 40% 15% / 0.06);
75
-
76
- // Surface highlight — subtle top-edge bevel/illumination for elevated surfaces
77
- --surface-highlight: inset 0 1px 0 0 hsl(0 0% 100% / 0.6);
78
-
79
- // Value vocabulary — what bg/fg/border/shadow values exist
80
- --bg-base: hsl(var(--color-white));
81
- --bg-elevated: var(--bg-base);
82
- --bg-sunken: hsl(var(--color-neutral-100));
83
- --bg-recessed: hsl(var(--color-neutral-50));
84
-
85
- --bg-hover: hsl(var(--color-neutral-100));
86
- --bg-active: hsl(var(--color-neutral-150));
87
-
88
- // Bound low on the ramp so every tier clears 7:1 against --bg-active,
89
- // the lightest surface any of them lands on (8.02 / 11.52 / 14.11).
90
- --fg-default: hsl(var(--color-neutral-900));
91
- --fg-muted: hsl(var(--color-neutral-800));
92
- --fg-subtle: hsl(var(--color-neutral-700));
93
-
94
- --border-subtle: hsl(var(--color-neutral-200));
95
- --border-strong: hsl(var(--color-neutral-300));
96
-
97
- // Interactive boundaries only (input/select/checkbox). 1.4.11 wants 3:1
98
- // for these; --border-subtle/-strong stay decorative and exempt.
99
- --border-ui: hsl(var(--color-neutral-400));
100
-
101
- --color-scrim: hsl(var(--color-neutral-900) / 0.5);
102
-
103
- // Per-polarity, not derived in the chain: the chain re-evaluates at
104
- // [data-mode], where neutral-900 inverts to near-white and the scrim would
105
- // lighten the page instead of dimming it.
106
- --app-scrim-bg: hsl(var(--color-neutral-900) / 0.4);
107
- }
108
-
109
- @mixin ln-values-dark {
110
- // Neutral scale — inverted
111
- --color-neutral-50: 220 20% 5%;
112
- --color-neutral-100: 220 16% 7%;
113
- --color-neutral-150: 220 14% 10%;
114
- --color-neutral-175: 220 13% 12%;
115
- --color-neutral-200: 220 13% 14%;
116
- --color-neutral-300: 220 13% 36%;
117
- --color-neutral-400: 218 11% 52%;
118
- --color-neutral-500: 220 10% 68%;
119
- --color-neutral-600: 220 11% 76%;
120
- --color-neutral-700: 220 14% 84%;
121
- --color-neutral-800: 220 20% 92%;
122
- --color-neutral-900: 221 30% 97%;
123
-
124
- // --color-white is deliberately not restated: :where(:root) still matches
125
- // <html data-mode="dark"> and supplies it, and --color-accent-fg needs real
126
- // white for text on a solid accent fill.
127
-
128
- // Vocabulary — bg. Elevated is DARKER than sunken here; that inversion
129
- // against light is intentional.
130
- --bg-base: hsl(var(--color-neutral-100));
131
- --bg-elevated: hsl(var(--color-neutral-150));
132
- --bg-sunken: hsl(var(--color-neutral-175));
133
- --bg-recessed: hsl(var(--color-neutral-50));
134
- --bg-hover: hsl(var(--color-neutral-175));
135
- --bg-active: hsl(var(--color-neutral-200));
136
-
137
- // Vocabulary — fg
138
- // Bound high on the ramp for the same reason as light: every tier clears
139
- // 7:1 against --bg-active (8.68 / 10.74 / 14.78).
140
- --fg-default: hsl(var(--color-neutral-900));
141
- --fg-muted: hsl(var(--color-neutral-700));
142
- --fg-subtle: hsl(var(--color-neutral-600));
143
-
144
- --border-subtle: hsl(var(--color-neutral-175));
145
- --border-strong: hsl(var(--color-neutral-300));
146
-
147
- --border-ui: hsl(var(--color-neutral-400));
148
-
149
- // Scrims — anchored to black, not the ramp: dark --color-neutral-900 is
150
- // near-white, so binding either to it would need an index flip.
151
- --color-scrim: hsl(0 0% 0% / 0.6);
152
- --app-scrim-bg: hsl(0 0% 0% / 0.4);
153
-
154
- // Status tint layers — re-tuned for dark surfaces
155
- --color-success-light: 142 50% 18%;
156
- --color-success-lighter: 142 40% 13%;
157
- --color-warning-light: 32 55% 20%;
158
- --color-warning-lighter: 32 45% 14%;
159
- --color-info-light: 217 55% 22%;
160
- --color-info-lighter: 217 45% 15%;
161
-
162
- --color-error: 0 84% 65%; // Lighter red for text contrast in dark mode
163
- --color-error-light: 0 50% 20%;
164
- --color-error-lighter: 0 40% 14%;
165
-
166
- // Secondary tint layers — re-tuned for dark surfaces
167
- --color-secondary-light: 160 55% 20%;
168
- --color-secondary-lighter: 160 45% 14%;
169
-
170
- // Shadows — solid black, boosted alpha, dual-layer
171
- --shadow-xs:
172
- 0 1px 2px 0 hsl(0 0% 0% / 0.35);
173
- --shadow-sm:
174
- 0 1px 3px 0 hsl(0 0% 0% / 0.40),
175
- 0 1px 2px -1px hsl(0 0% 0% / 0.25);
176
- --shadow-md:
177
- 0 4px 6px -1px hsl(0 0% 0% / 0.45),
178
- 0 2px 4px -2px hsl(0 0% 0% / 0.30);
179
- --shadow-lg:
180
- 0 10px 15px -3px hsl(0 0% 0% / 0.50),
181
- 0 4px 6px -4px hsl(0 0% 0% / 0.35);
182
- --shadow-xl:
183
- 0 20px 25px -5px hsl(0 0% 0% / 0.60),
184
- 0 8px 10px -6px hsl(0 0% 0% / 0.40);
185
- --shadow-2xl:
186
- 0 25px 50px -12px hsl(0 0% 0% / 0.70);
187
- --shadow-inner:
188
- inset 0 2px 4px 0 hsl(0 0% 0% / 0.32);
189
-
190
- // Surface highlight — crisp top-edge bevel on dark elevated surfaces
191
- --surface-highlight: inset 0 1px 0 0 hsl(0 0% 100% / 0.08);
192
- }
193
-
194
- @mixin ln-color-chain {
195
- // brand → semantic
196
- --color-primary: var(--brand-primary);
197
- --color-secondary: var(--brand-secondary);
198
-
199
- // colour-aware shadows
200
- --shadow-primary: 0 8px 24px -6px hsl(var(--color-primary) / 0.28);
201
- --shadow-success: 0 8px 24px -6px hsl(var(--color-success) / 0.28);
202
- --shadow-error: 0 8px 24px -6px hsl(var(--color-error) / 0.28);
203
- }
204
-
205
- // ---------------------------------------------------------------------------
206
- // Brand — :where(:root) ONLY. Deliberately not in ln-values-light /
207
- // ln-values-dark and deliberately not joined to the four-axis block below.
208
- //
209
- // Brand is a literal with no polarity opinion. Declared inside the value
210
- // mixins it would be re-declared on every nested [data-mode] island, and a
211
- // declaration beats inheritance at any specificity — so a light card inside
212
- // <section data-theme="sunset" data-mode="dark"> would snap back to default
213
- // blue. :root-only means no island re-declares it; [data-theme] at (0,1,0)
214
- // rebinds it normally; a consumer's brand.css at (0,1,0) still wins at any
215
- // stylesheet load order, which is brand.css's whole guarantee.
216
- // ---------------------------------------------------------------------------
217
- :where(:root) {
218
- --brand-primary: 221 83% 43%;
219
- --brand-secondary: 160 84% 36%;
220
- }
221
-
222
- // ---------------------------------------------------------------------------
223
- // Base Defaults — Lazy-evaluated primitives and surfaces.
224
- // These live in :where(:root) (0,0,0) so they can be overridden by [data-skin]
225
- // or [data-theme] (0,1,0) without being clobbered by nested [data-mode] islands.
226
- // ---------------------------------------------------------------------------
227
- :where(:root),
228
- :where([data-mode]),
229
- :where([data-theme]),
230
- :where([data-skin]) {
231
- // shadow roles
232
- --shadow-resting: var(--shadow-sm);
233
- --shadow-floating: var(--shadow-md);
234
- --shadow-overlay: var(--shadow-xl);
235
-
236
- // primitives — what mixin bodies read
237
- --color-bg: var(--bg-base);
238
- --color-fg: var(--fg-default);
239
- --color-border: var(--border-subtle);
240
- --shadow: var(--shadow-resting);
241
- --radius: var(--radius-md);
242
-
243
- // accent — tints computed against the LOCAL --bg-base, so one
244
- // formula serves both themes. The two override slots are
245
- // undeclared by default; a client declares them to win.
246
- --color-accent: hsl(var(--color-primary));
247
- --color-accent-fg: hsl(var(--color-white));
248
-
249
- // Dark foreground pole for fills too light to carry white at AAA.
250
- // A literal, never var(--color-neutral-900) — that inverts to near-white
251
- // in dark mode, which is exactly where the ink islands live. Mirrors
252
- // $_ln-contrast-ink in _contrast.scss; keep the two in step.
253
- --color-ink: 222 47% 11%;
254
-
255
- // Checkmark stroke is baked into the data URI, so it ships in both poles
256
- // and --check-mark selects one. An ink island must repoint this or its
257
- // checkmark stays white on a light fill, well under the 3:1 that 1.4.11
258
- // asks of a meaningful graphic.
259
- --check-mark-on-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
260
- --check-mark-on-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f1729' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
261
- --check-mark: var(--check-mark-on-light);
262
- --color-accent-tint: var(--brand-primary-tint,
263
- color-mix(in srgb, hsl(var(--color-primary)) 8%, var(--bg-base)));
264
- --color-accent-tint-strong: var(--brand-primary-tint-strong,
265
- color-mix(in srgb, hsl(var(--color-primary)) 16%, var(--bg-base)));
266
-
267
- // button surface (neutral default)
268
- --btn-bg: var(--color-bg);
269
- --btn-fg: var(--color-fg);
270
- --btn-border: var(--border-strong);
271
- --btn-bg-hover: var(--bg-hover);
272
- --btn-fg-hover: var(--color-fg);
273
- --btn-border-hover: var(--border-strong);
274
- }
1
+ // ==========================================================================
2
+ // Palette & Color Derivation Mixins — ln-ashlar
3
+ // ==========================================================================
4
+ // Value mixins + the derivation chain, plus two zero-specificity CSS blocks
5
+ // at the bottom (brand, base defaults).
6
+ // Defines theme values (light and dark) and the unified color derivation chain.
7
+ // ==========================================================================
8
+
9
+ @mixin ln-values-light {
10
+ // Secondary tint layers
11
+ --color-secondary-light: 160 84% 94%;
12
+ --color-secondary-lighter: 160 84% 97%;
13
+
14
+ // Status colors
15
+ --color-success: 142 76% 36%;
16
+ --color-success-light: 142 71% 94%;
17
+ --color-success-lighter: 142 71% 97%;
18
+
19
+ --color-error: 0 84% 48%;
20
+ --color-error-light: 0 84% 94%;
21
+ --color-error-lighter: 0 84% 97%;
22
+
23
+ --color-warning: 32 95% 38%;
24
+ --color-warning-light: 38 92% 94%;
25
+ --color-warning-lighter: 38 92% 97%;
26
+
27
+ --color-info: 200 95% 38%;
28
+ --color-info-light: 199 89% 94%;
29
+ --color-info-lighter: 199 89% 97%;
30
+
31
+ // Neutral scale (canonical greys)
32
+ --color-neutral-50: 210 20% 98%;
33
+ --color-neutral-100: 220 14% 96%;
34
+ --color-neutral-150: 220 13% 93%;
35
+ --color-neutral-175: 220 13% 91%;
36
+ --color-neutral-200: 220 13% 90%;
37
+ --color-neutral-300: 216 12% 84%;
38
+ --color-neutral-400: 218 11% 58%;
39
+ --color-neutral-500: 220 10% 40%;
40
+ --color-neutral-600: 215 14% 34%;
41
+ --color-neutral-700: 217 19% 27%;
42
+ --color-neutral-800: 215 28% 17%;
43
+ --color-neutral-900: 222 47% 11%;
44
+
45
+ // Base canvas background
46
+ --color-white: 0 0% 100%;
47
+
48
+ // Shadows — cool-tinted, dual-layer (ambient + key light)
49
+ --shadow-none: none;
50
+
51
+ --shadow-xs:
52
+ 0 1px 2px 0 hsl(220 40% 10% / 0.05);
53
+
54
+ --shadow-sm:
55
+ 0 1px 3px 0 hsl(220 40% 10% / 0.07),
56
+ 0 1px 2px -1px hsl(220 40% 10% / 0.05);
57
+
58
+ --shadow-md:
59
+ 0 4px 6px -1px hsl(220 40% 10% / 0.08),
60
+ 0 2px 4px -2px hsl(220 40% 10% / 0.05);
61
+
62
+ --shadow-lg:
63
+ 0 10px 15px -3px hsl(220 40% 10% / 0.08),
64
+ 0 4px 6px -4px hsl(220 40% 10% / 0.04);
65
+
66
+ --shadow-xl:
67
+ 0 20px 25px -5px hsl(220 40% 10% / 0.09),
68
+ 0 8px 10px -6px hsl(220 40% 10% / 0.04);
69
+
70
+ --shadow-2xl:
71
+ 0 25px 50px -12px hsl(220 40% 10% / 0.18);
72
+
73
+ --shadow-inner:
74
+ inset 0 2px 4px 0 hsl(220 40% 15% / 0.06);
75
+
76
+ // Surface highlight — subtle top-edge bevel/illumination for elevated surfaces
77
+ --surface-highlight: inset 0 1px 0 0 hsl(0 0% 100% / 0.6);
78
+
79
+ // Value vocabulary — what bg/fg/border/shadow values exist
80
+ --bg-base: hsl(var(--color-white));
81
+ --bg-elevated: var(--bg-base);
82
+ --bg-sunken: hsl(var(--color-neutral-100));
83
+ --bg-recessed: hsl(var(--color-neutral-50));
84
+
85
+ --bg-hover: hsl(var(--color-neutral-100));
86
+ --bg-active: hsl(var(--color-neutral-150));
87
+
88
+ // Bound low on the ramp so every tier clears 7:1 against --bg-active,
89
+ // the lightest surface any of them lands on (8.02 / 11.52 / 14.11).
90
+ --fg-default: hsl(var(--color-neutral-900));
91
+ --fg-muted: hsl(var(--color-neutral-800));
92
+ --fg-subtle: hsl(var(--color-neutral-700));
93
+
94
+ --border-subtle: hsl(var(--color-neutral-200));
95
+ --border-strong: hsl(var(--color-neutral-300));
96
+
97
+ // Interactive boundaries only (input/select/checkbox). 1.4.11 wants 3:1
98
+ // for these; --border-subtle/-strong stay decorative and exempt.
99
+ --border-ui: hsl(var(--color-neutral-400));
100
+
101
+ --color-scrim: hsl(var(--color-neutral-900) / 0.5);
102
+
103
+ // Per-polarity, not derived in the chain: the chain re-evaluates at
104
+ // [data-mode], where neutral-900 inverts to near-white and the scrim would
105
+ // lighten the page instead of dimming it.
106
+ --app-scrim-bg: hsl(var(--color-neutral-900) / 0.4);
107
+ }
108
+
109
+ @mixin ln-values-dark {
110
+ // Neutral scale — inverted
111
+ --color-neutral-50: 220 20% 5%;
112
+ --color-neutral-100: 220 16% 7%;
113
+ --color-neutral-150: 220 14% 10%;
114
+ --color-neutral-175: 220 13% 12%;
115
+ --color-neutral-200: 220 13% 14%;
116
+ --color-neutral-300: 220 13% 36%;
117
+ --color-neutral-400: 218 11% 52%;
118
+ --color-neutral-500: 220 10% 68%;
119
+ --color-neutral-600: 220 11% 76%;
120
+ --color-neutral-700: 220 14% 84%;
121
+ --color-neutral-800: 220 20% 92%;
122
+ --color-neutral-900: 221 30% 97%;
123
+
124
+ // --color-white is deliberately not restated: :where(:root) still matches
125
+ // <html data-mode="dark"> and supplies it, and --color-accent-fg needs real
126
+ // white for text on a solid accent fill.
127
+
128
+ // Vocabulary — bg. Elevated is DARKER than sunken here; that inversion
129
+ // against light is intentional.
130
+ --bg-base: hsl(var(--color-neutral-100));
131
+ --bg-elevated: hsl(var(--color-neutral-150));
132
+ --bg-sunken: hsl(var(--color-neutral-175));
133
+ --bg-recessed: hsl(var(--color-neutral-50));
134
+ --bg-hover: hsl(var(--color-neutral-175));
135
+ --bg-active: hsl(var(--color-neutral-200));
136
+
137
+ // Vocabulary — fg
138
+ // Bound high on the ramp for the same reason as light: every tier clears
139
+ // 7:1 against --bg-active (8.68 / 10.74 / 14.78).
140
+ --fg-default: hsl(var(--color-neutral-900));
141
+ --fg-muted: hsl(var(--color-neutral-700));
142
+ --fg-subtle: hsl(var(--color-neutral-600));
143
+
144
+ --border-subtle: hsl(var(--color-neutral-175));
145
+ --border-strong: hsl(var(--color-neutral-300));
146
+
147
+ --border-ui: hsl(var(--color-neutral-400));
148
+
149
+ // Scrims — anchored to black, not the ramp: dark --color-neutral-900 is
150
+ // near-white, so binding either to it would need an index flip.
151
+ --color-scrim: hsl(0 0% 0% / 0.6);
152
+ --app-scrim-bg: hsl(0 0% 0% / 0.4);
153
+
154
+ // Status tint layers — re-tuned for dark surfaces
155
+ --color-success-light: 142 50% 18%;
156
+ --color-success-lighter: 142 40% 13%;
157
+ --color-warning-light: 32 55% 20%;
158
+ --color-warning-lighter: 32 45% 14%;
159
+ --color-info-light: 217 55% 22%;
160
+ --color-info-lighter: 217 45% 15%;
161
+
162
+ --color-error: 0 84% 65%; // Lighter red for text contrast in dark mode
163
+ --color-error-light: 0 50% 20%;
164
+ --color-error-lighter: 0 40% 14%;
165
+
166
+ // Secondary tint layers — re-tuned for dark surfaces
167
+ --color-secondary-light: 160 55% 20%;
168
+ --color-secondary-lighter: 160 45% 14%;
169
+
170
+ // Shadows — solid black, boosted alpha, dual-layer
171
+ --shadow-xs:
172
+ 0 1px 2px 0 hsl(0 0% 0% / 0.35);
173
+ --shadow-sm:
174
+ 0 1px 3px 0 hsl(0 0% 0% / 0.40),
175
+ 0 1px 2px -1px hsl(0 0% 0% / 0.25);
176
+ --shadow-md:
177
+ 0 4px 6px -1px hsl(0 0% 0% / 0.45),
178
+ 0 2px 4px -2px hsl(0 0% 0% / 0.30);
179
+ --shadow-lg:
180
+ 0 10px 15px -3px hsl(0 0% 0% / 0.50),
181
+ 0 4px 6px -4px hsl(0 0% 0% / 0.35);
182
+ --shadow-xl:
183
+ 0 20px 25px -5px hsl(0 0% 0% / 0.60),
184
+ 0 8px 10px -6px hsl(0 0% 0% / 0.40);
185
+ --shadow-2xl:
186
+ 0 25px 50px -12px hsl(0 0% 0% / 0.70);
187
+ --shadow-inner:
188
+ inset 0 2px 4px 0 hsl(0 0% 0% / 0.32);
189
+
190
+ // Surface highlight — crisp top-edge bevel on dark elevated surfaces
191
+ --surface-highlight: inset 0 1px 0 0 hsl(0 0% 100% / 0.08);
192
+ }
193
+
194
+ @mixin ln-color-chain {
195
+ // brand → semantic
196
+ --color-primary: var(--brand-primary);
197
+ --color-secondary: var(--brand-secondary);
198
+
199
+ // colour-aware shadows
200
+ --shadow-primary: 0 8px 24px -6px hsl(var(--color-primary) / 0.28);
201
+ --shadow-success: 0 8px 24px -6px hsl(var(--color-success) / 0.28);
202
+ --shadow-error: 0 8px 24px -6px hsl(var(--color-error) / 0.28);
203
+ }
204
+
205
+ // ---------------------------------------------------------------------------
206
+ // Brand — :where(:root) ONLY. Deliberately not in ln-values-light /
207
+ // ln-values-dark and deliberately not joined to the four-axis block below.
208
+ //
209
+ // Brand is a literal with no polarity opinion. Declared inside the value
210
+ // mixins it would be re-declared on every nested [data-mode] island, and a
211
+ // declaration beats inheritance at any specificity — so a light card inside
212
+ // <section data-theme="sunset" data-mode="dark"> would snap back to default
213
+ // blue. :root-only means no island re-declares it; [data-theme] at (0,1,0)
214
+ // rebinds it normally; a consumer's brand.css at (0,1,0) still wins at any
215
+ // stylesheet load order, which is brand.css's whole guarantee.
216
+ // ---------------------------------------------------------------------------
217
+ :where(:root) {
218
+ --brand-primary: 221 83% 43%;
219
+ --brand-secondary: 160 84% 36%;
220
+ }
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // Base Defaults — Lazy-evaluated primitives and surfaces.
224
+ // These live in :where(:root) (0,0,0) so they can be overridden by [data-skin]
225
+ // or [data-theme] (0,1,0) without being clobbered by nested [data-mode] islands.
226
+ // ---------------------------------------------------------------------------
227
+ :where(:root),
228
+ :where([data-mode]),
229
+ :where([data-theme]),
230
+ :where([data-skin]) {
231
+ // shadow roles
232
+ --shadow-resting: var(--shadow-sm);
233
+ --shadow-floating: var(--shadow-md);
234
+ --shadow-overlay: var(--shadow-xl);
235
+
236
+ // primitives — what mixin bodies read
237
+ --color-bg: var(--bg-base);
238
+ --color-fg: var(--fg-default);
239
+ --color-border: var(--border-subtle);
240
+ --shadow: var(--shadow-resting);
241
+ --radius: var(--radius-md);
242
+
243
+ // accent — tints computed against the LOCAL --bg-base, so one
244
+ // formula serves both themes. The two override slots are
245
+ // undeclared by default; a client declares them to win.
246
+ --color-accent: hsl(var(--color-primary));
247
+ --color-accent-fg: hsl(var(--color-white));
248
+
249
+ // Dark foreground pole for fills too light to carry white at AAA.
250
+ // A literal, never var(--color-neutral-900) — that inverts to near-white
251
+ // in dark mode, which is exactly where the ink islands live. Mirrors
252
+ // $_ln-contrast-ink in _contrast.scss; keep the two in step.
253
+ --color-ink: 222 47% 11%;
254
+
255
+ // Checkmark stroke is baked into the data URI, so it ships in both poles
256
+ // and --check-mark selects one. An ink island must repoint this or its
257
+ // checkmark stays white on a light fill, well under the 3:1 that 1.4.11
258
+ // asks of a meaningful graphic.
259
+ --check-mark-on-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
260
+ --check-mark-on-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f1729' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E");
261
+ --check-mark: var(--check-mark-on-light);
262
+ --color-accent-tint: var(--brand-primary-tint,
263
+ color-mix(in srgb, hsl(var(--color-primary)) 8%, var(--bg-base)));
264
+ --color-accent-tint-strong: var(--brand-primary-tint-strong,
265
+ color-mix(in srgb, hsl(var(--color-primary)) 16%, var(--bg-base)));
266
+
267
+ // button surface (neutral default)
268
+ --btn-bg: var(--color-bg);
269
+ --btn-fg: var(--color-fg);
270
+ --btn-border: var(--border-strong);
271
+ --btn-bg-hover: var(--bg-hover);
272
+ --btn-fg-hover: var(--color-fg);
273
+ --btn-border-hover: var(--border-strong);
274
+ }