@livenetworks/ashlar 1.3.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 (232) hide show
  1. package/README.md +177 -0
  2. package/js/COMPONENTS.md +1102 -0
  3. package/js/index.js +41 -0
  4. package/js/ln-accordion/README.md +137 -0
  5. package/js/ln-accordion/ln-accordion.js +1 -0
  6. package/js/ln-accordion/src/ln-accordion.js +41 -0
  7. package/js/ln-ajax/README.md +91 -0
  8. package/js/ln-ajax/ln-ajax.js +1 -0
  9. package/js/ln-ajax/src/ln-ajax.js +277 -0
  10. package/js/ln-api-connector/README.md +150 -0
  11. package/js/ln-api-connector/ln-api-connector.js +1 -0
  12. package/js/ln-api-connector/src/ln-api-connector.js +265 -0
  13. package/js/ln-autoresize/README.md +80 -0
  14. package/js/ln-autoresize/ln-autoresize.js +1 -0
  15. package/js/ln-autoresize/src/ln-autoresize.js +47 -0
  16. package/js/ln-autosave/README.md +92 -0
  17. package/js/ln-autosave/ln-autosave.js +1 -0
  18. package/js/ln-autosave/src/ln-autosave.js +147 -0
  19. package/js/ln-circular-progress/README.md +161 -0
  20. package/js/ln-circular-progress/ln-circular-progress.js +1 -0
  21. package/js/ln-circular-progress/src/ln-circular-progress.js +133 -0
  22. package/js/ln-confirm/README.md +86 -0
  23. package/js/ln-confirm/_ln-confirm.scss +13 -0
  24. package/js/ln-confirm/ln-confirm.js +1 -0
  25. package/js/ln-confirm/src/ln-confirm.js +131 -0
  26. package/js/ln-core/crypto.js +83 -0
  27. package/js/ln-core/helpers.js +411 -0
  28. package/js/ln-core/index.js +5 -0
  29. package/js/ln-core/persist.js +71 -0
  30. package/js/ln-core/positioning.js +207 -0
  31. package/js/ln-core/reactive.js +74 -0
  32. package/js/ln-couchdb-connector/README.md +156 -0
  33. package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
  34. package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +348 -0
  35. package/js/ln-data-coordinator/README.md +165 -0
  36. package/js/ln-data-coordinator/ln-data-coordinator.js +1 -0
  37. package/js/ln-data-coordinator/src/ln-data-coordinator.js +249 -0
  38. package/js/ln-data-store/README.md +94 -0
  39. package/js/ln-data-store/ln-data-store.js +1 -0
  40. package/js/ln-data-store/src/ln-data-store.js +699 -0
  41. package/js/ln-data-table/README.md +110 -0
  42. package/js/ln-data-table/ln-data-table.js +1 -0
  43. package/js/ln-data-table/ln-data-table.scss +10 -0
  44. package/js/ln-data-table/src/ln-data-table.js +1103 -0
  45. package/js/ln-date/README.md +151 -0
  46. package/js/ln-date/ln-date.js +1 -0
  47. package/js/ln-date/src/ln-date.js +442 -0
  48. package/js/ln-dropdown/README.md +117 -0
  49. package/js/ln-dropdown/ln-dropdown.js +1 -0
  50. package/js/ln-dropdown/ln-dropdown.scss +15 -0
  51. package/js/ln-dropdown/src/ln-dropdown.js +174 -0
  52. package/js/ln-external-links/README.md +341 -0
  53. package/js/ln-external-links/ln-external-links.js +1 -0
  54. package/js/ln-external-links/src/ln-external-links.js +116 -0
  55. package/js/ln-filter/README.md +99 -0
  56. package/js/ln-filter/ln-filter.js +1 -0
  57. package/js/ln-filter/ln-filter.scss +7 -0
  58. package/js/ln-filter/src/ln-filter.js +404 -0
  59. package/js/ln-form/README.md +101 -0
  60. package/js/ln-form/ln-form.js +1 -0
  61. package/js/ln-form/src/ln-form.js +199 -0
  62. package/js/ln-http/README.md +89 -0
  63. package/js/ln-http/ln-http.js +1 -0
  64. package/js/ln-http/src/ln-http.js +219 -0
  65. package/js/ln-icons/README.md +88 -0
  66. package/js/ln-icons/ln-icons.js +1 -0
  67. package/js/ln-icons/src/ln-icons.js +169 -0
  68. package/js/ln-link/README.md +303 -0
  69. package/js/ln-link/ln-link.js +1 -0
  70. package/js/ln-link/src/ln-link.js +196 -0
  71. package/js/ln-modal/README.md +154 -0
  72. package/js/ln-modal/ln-modal.js +1 -0
  73. package/js/ln-modal/ln-modal.scss +11 -0
  74. package/js/ln-modal/src/ln-modal.js +201 -0
  75. package/js/ln-nav/README.md +70 -0
  76. package/js/ln-nav/ln-nav.js +1 -0
  77. package/js/ln-nav/src/ln-nav.js +177 -0
  78. package/js/ln-number/README.md +122 -0
  79. package/js/ln-number/ln-number.js +1 -0
  80. package/js/ln-number/src/ln-number.js +302 -0
  81. package/js/ln-popover/README.md +127 -0
  82. package/js/ln-popover/ln-popover.js +1 -0
  83. package/js/ln-popover/src/ln-popover.js +288 -0
  84. package/js/ln-progress/README.md +442 -0
  85. package/js/ln-progress/ln-progress.js +1 -0
  86. package/js/ln-progress/src/ln-progress.js +150 -0
  87. package/js/ln-search/README.md +83 -0
  88. package/js/ln-search/ln-search.js +1 -0
  89. package/js/ln-search/ln-search.scss +7 -0
  90. package/js/ln-search/src/ln-search.js +114 -0
  91. package/js/ln-sortable/README.md +95 -0
  92. package/js/ln-sortable/ln-sortable.js +1 -0
  93. package/js/ln-sortable/src/ln-sortable.js +203 -0
  94. package/js/ln-table/README.md +101 -0
  95. package/js/ln-table/ln-table-sort.js +1 -0
  96. package/js/ln-table/ln-table.js +1 -0
  97. package/js/ln-table/ln-table.scss +11 -0
  98. package/js/ln-table/src/ln-table-sort.js +168 -0
  99. package/js/ln-table/src/ln-table.js +473 -0
  100. package/js/ln-tabs/README.md +137 -0
  101. package/js/ln-tabs/ln-tabs.js +1 -0
  102. package/js/ln-tabs/src/ln-tabs.js +171 -0
  103. package/js/ln-time/README.md +81 -0
  104. package/js/ln-time/ln-time.js +1 -0
  105. package/js/ln-time/src/ln-time.js +192 -0
  106. package/js/ln-toast/README.md +122 -0
  107. package/js/ln-toast/ln-toast.js +15 -0
  108. package/js/ln-toast/src/ln-toast.js +210 -0
  109. package/js/ln-toast/template.html +14 -0
  110. package/js/ln-toggle/README.md +137 -0
  111. package/js/ln-toggle/ln-toggle.js +1 -0
  112. package/js/ln-toggle/src/ln-toggle.js +139 -0
  113. package/js/ln-tooltip/README.md +58 -0
  114. package/js/ln-tooltip/ln-tooltip.js +1 -0
  115. package/js/ln-tooltip/ln-tooltip.scss +9 -0
  116. package/js/ln-tooltip/src/ln-tooltip.js +169 -0
  117. package/js/ln-translations/README.md +96 -0
  118. package/js/ln-translations/ln-translations.js +1 -0
  119. package/js/ln-translations/src/ln-translations.js +275 -0
  120. package/js/ln-upload/README.md +180 -0
  121. package/js/ln-upload/ln-upload.js +1 -0
  122. package/js/ln-upload/ln-upload.scss +20 -0
  123. package/js/ln-upload/src/ln-upload.js +407 -0
  124. package/js/ln-validate/README.md +108 -0
  125. package/js/ln-validate/ln-validate.js +1 -0
  126. package/js/ln-validate/src/ln-validate.js +160 -0
  127. package/package.json +55 -0
  128. package/scss/base/_global.scss +83 -0
  129. package/scss/base/_reset.scss +17 -0
  130. package/scss/base/_typography.scss +125 -0
  131. package/scss/components/_accordion.scss +34 -0
  132. package/scss/components/_ajax.scss +15 -0
  133. package/scss/components/_alert.scss +5 -0
  134. package/scss/components/_app-shell.scss +15 -0
  135. package/scss/components/_avatar.scss +6 -0
  136. package/scss/components/_breadcrumbs.scss +33 -0
  137. package/scss/components/_button.scss +20 -0
  138. package/scss/components/_card.scss +10 -0
  139. package/scss/components/_chip.scss +5 -0
  140. package/scss/components/_circular-progress.scss +29 -0
  141. package/scss/components/_confirm.scss +5 -0
  142. package/scss/components/_data-table.scss +83 -0
  143. package/scss/components/_dropdown.scss +25 -0
  144. package/scss/components/_empty-state.scss +22 -0
  145. package/scss/components/_form.scss +100 -0
  146. package/scss/components/_layout.scss +8 -0
  147. package/scss/components/_link.scss +11 -0
  148. package/scss/components/_ln-table.scss +60 -0
  149. package/scss/components/_loader.scss +6 -0
  150. package/scss/components/_modal.scss +20 -0
  151. package/scss/components/_nav.scss +9 -0
  152. package/scss/components/_page-header.scss +10 -0
  153. package/scss/components/_popover.scss +10 -0
  154. package/scss/components/_progress.scss +17 -0
  155. package/scss/components/_prose.scss +5 -0
  156. package/scss/components/_scrollbar.scss +32 -0
  157. package/scss/components/_sections.scss +12 -0
  158. package/scss/components/_sidebar.scss +5 -0
  159. package/scss/components/_stat-card.scss +5 -0
  160. package/scss/components/_status-badge.scss +4 -0
  161. package/scss/components/_stepper.scss +5 -0
  162. package/scss/components/_table.scss +19 -0
  163. package/scss/components/_tabs.scss +21 -0
  164. package/scss/components/_timeline.scss +14 -0
  165. package/scss/components/_toast.scss +41 -0
  166. package/scss/components/_toggle.scss +81 -0
  167. package/scss/components/_tooltip.scss +18 -0
  168. package/scss/components/_translations.scss +111 -0
  169. package/scss/components/_upload.scss +51 -0
  170. package/scss/config/_breakpoints.scss +72 -0
  171. package/scss/config/_density.scss +117 -0
  172. package/scss/config/_icons.scss +37 -0
  173. package/scss/config/_mixins.scss +13 -0
  174. package/scss/config/_theme.scss +216 -0
  175. package/scss/config/_tokens.scss +419 -0
  176. package/scss/config/mixins/_accordion.scss +52 -0
  177. package/scss/config/mixins/_ajax.scss +39 -0
  178. package/scss/config/mixins/_alert.scss +82 -0
  179. package/scss/config/mixins/_app-shell.scss +312 -0
  180. package/scss/config/mixins/_avatar.scss +109 -0
  181. package/scss/config/mixins/_borders.scss +36 -0
  182. package/scss/config/mixins/_breadcrumbs.scss +72 -0
  183. package/scss/config/mixins/_breakpoints.scss +62 -0
  184. package/scss/config/mixins/_btn.scss +179 -0
  185. package/scss/config/mixins/_card.scss +338 -0
  186. package/scss/config/mixins/_chip.scss +66 -0
  187. package/scss/config/mixins/_circular-progress.scss +71 -0
  188. package/scss/config/mixins/_collapsible.scss +24 -0
  189. package/scss/config/mixins/_colors.scss +46 -0
  190. package/scss/config/mixins/_confirm.scss +31 -0
  191. package/scss/config/mixins/_data-table.scss +346 -0
  192. package/scss/config/mixins/_display.scss +32 -0
  193. package/scss/config/mixins/_dropdown.scss +143 -0
  194. package/scss/config/mixins/_empty-state.scss +30 -0
  195. package/scss/config/mixins/_focus.scss +55 -0
  196. package/scss/config/mixins/_footer.scss +42 -0
  197. package/scss/config/mixins/_form.scss +601 -0
  198. package/scss/config/mixins/_index.scss +58 -0
  199. package/scss/config/mixins/_interaction.scss +15 -0
  200. package/scss/config/mixins/_kbd.scss +22 -0
  201. package/scss/config/mixins/_layout.scss +117 -0
  202. package/scss/config/mixins/_link.scss +55 -0
  203. package/scss/config/mixins/_ln-table.scss +420 -0
  204. package/scss/config/mixins/_loader.scss +26 -0
  205. package/scss/config/mixins/_modal.scss +66 -0
  206. package/scss/config/mixins/_motion.scss +19 -0
  207. package/scss/config/mixins/_nav.scss +273 -0
  208. package/scss/config/mixins/_page-header.scss +69 -0
  209. package/scss/config/mixins/_popover.scss +25 -0
  210. package/scss/config/mixins/_position.scss +32 -0
  211. package/scss/config/mixins/_progress.scss +56 -0
  212. package/scss/config/mixins/_prose.scss +127 -0
  213. package/scss/config/mixins/_shadows.scss +8 -0
  214. package/scss/config/mixins/_sidebar.scss +95 -0
  215. package/scss/config/mixins/_sizing.scss +6 -0
  216. package/scss/config/mixins/_spacing.scss +19 -0
  217. package/scss/config/mixins/_stat-card.scss +68 -0
  218. package/scss/config/mixins/_status-badge.scss +83 -0
  219. package/scss/config/mixins/_stepper.scss +78 -0
  220. package/scss/config/mixins/_table.scss +215 -0
  221. package/scss/config/mixins/_tabs.scss +64 -0
  222. package/scss/config/mixins/_timeline.scss +69 -0
  223. package/scss/config/mixins/_toast.scss +148 -0
  224. package/scss/config/mixins/_tooltip.scss +111 -0
  225. package/scss/config/mixins/_transitions.scss +10 -0
  226. package/scss/config/mixins/_translations.scss +124 -0
  227. package/scss/config/mixins/_typography.scss +57 -0
  228. package/scss/config/mixins/_upload.scss +168 -0
  229. package/scss/ln-ashlar.scss +62 -0
  230. package/scss/tabler-icons.txt +5039 -0
  231. package/scss/utilities/_animations.scss +83 -0
  232. package/scss/utilities/_utilities.scss +49 -0
@@ -0,0 +1,19 @@
1
+ // Spacing — accepts CSS variable or value
2
+
3
+ @mixin p($val) { padding: $val; }
4
+ @mixin px($val) { padding-left: $val; padding-right: $val; }
5
+ @mixin py($val) { padding-top: $val; padding-bottom: $val; }
6
+ @mixin pt($val) { padding-top: $val; }
7
+ @mixin pb($val) { padding-bottom: $val; }
8
+ @mixin pl($val) { padding-left: $val; }
9
+ @mixin pr($val) { padding-right: $val; }
10
+
11
+ @mixin m($val) { margin: $val; }
12
+ @mixin mx($val) { margin-left: $val; margin-right: $val; }
13
+ @mixin my($val) { margin-top: $val; margin-bottom: $val; }
14
+ @mixin mt($val) { margin-top: $val; }
15
+ @mixin mb($val) { margin-bottom: $val; }
16
+ @mixin ml($val) { margin-left: $val; }
17
+ @mixin mr($val) { margin-right: $val; }
18
+
19
+ @mixin gap($val) { gap: $val; }
@@ -0,0 +1,68 @@
1
+ @use 'spacing' as *;
2
+ @use 'display' as *;
3
+ @use 'typography' as *;
4
+ @use 'colors' as *;
5
+ @use 'borders' as *;
6
+ @use 'transitions' as *;
7
+
8
+ @mixin stat-card {
9
+ --shadow: var(--shadow-resting);
10
+ @include flex-col;
11
+ --gap: var(--size-xs);
12
+ gap: var(--gap);
13
+ --padding-y: var(--size-lg);
14
+ --padding-x: var(--size-lg);
15
+ padding: var(--padding-y) var(--padding-x);
16
+ background: var(--color-bg);
17
+ --radius: var(--radius-lg);
18
+ border-radius: var(--radius);
19
+ box-shadow: var(--shadow);
20
+ border-block-start: var(--border-block-start, var(--border-width) solid var(--color-border));
21
+ border-block-end: var(--border-block-end, var(--border-width) solid var(--color-border));
22
+ border-inline-start: var(--border-inline-start, var(--border-width) solid var(--color-border));
23
+ border-inline-end: var(--border-inline-end, var(--border-width) solid var(--color-border));
24
+ @include transition;
25
+
26
+ > [data-ln-stat-label] {
27
+ --color-fg: var(--fg-muted);
28
+ @include typography(label-md);
29
+ color: var(--color-fg);
30
+ text-transform: uppercase;
31
+ letter-spacing: var(--tracking-wide);
32
+ margin: 0;
33
+ }
34
+
35
+ > [data-ln-stat-value] {
36
+ @include typography(heading-lg);
37
+ font-weight: var(--font-bold);
38
+ font-variant-numeric: tabular-nums;
39
+ color: var(--color-fg);
40
+ margin: 0;
41
+ }
42
+
43
+ > [data-ln-stat-trend] {
44
+ @include flex-row;
45
+ @include items-center;
46
+ --gap: var(--size-xs);
47
+ gap: var(--gap);
48
+ @include typography(body-sm);
49
+ --margin-block: var(--size-xs);
50
+ margin: var(--margin-block) 0 0;
51
+
52
+ svg.ln-icon {
53
+ width: 1rem;
54
+ height: 1rem;
55
+ }
56
+
57
+ &[data-ln-stat-trend="up"] {
58
+ color: hsl(var(--color-success));
59
+ }
60
+ &[data-ln-stat-trend="down"] {
61
+ color: hsl(var(--color-error));
62
+ }
63
+ &[data-ln-stat-trend="neutral"] {
64
+ --color-fg: var(--fg-subtle);
65
+ color: var(--color-fg);
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,83 @@
1
+ @use 'colors' as *;
2
+ @use 'motion' as *;
3
+
4
+ // Status Badge — inline semantic indicator with colored dot
5
+ //
6
+ // Usage:
7
+ // <span class="badge success">Active</span>
8
+ // <span class="badge warning live">Syncing</span>
9
+ // <button class="badge error">Blocked</button>
10
+ //
11
+ // Variants (override --color-primary):
12
+ // .success → --color-success
13
+ // .warning → --color-warning
14
+ // .error → --color-error
15
+ // .info → --color-info
16
+ // .neutral → --color-neutral-400
17
+ //
18
+ // Live: .badge.live adds pulse animation to the dot
19
+
20
+ // ─── Base ──────────────────────────────────────────────
21
+ @mixin badge {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ gap: 0;
25
+ border-radius: var(--radius-full);
26
+ padding: 0.2em 0.65em;
27
+ font-size: var(--text-xs);
28
+ font-weight: var(--font-medium);
29
+ @include tinted-surface(0.12);
30
+ line-height: 1.5;
31
+
32
+ // Colored dot
33
+ &::before {
34
+ content: '';
35
+ display: block;
36
+ width: 0.45em;
37
+ height: 0.45em;
38
+ border-radius: 50%;
39
+ background: currentColor;
40
+ margin-right: 0.4em;
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ // When on <button> — override global gray hover
45
+ &:is(button) {
46
+ cursor: pointer;
47
+ transition: background var(--transition-fast);
48
+ border: none;
49
+ font-family: inherit;
50
+
51
+ &:hover {
52
+ background: color-mix(in srgb, var(--color-accent) 20%, transparent);
53
+ }
54
+
55
+ &:active {
56
+ background: color-mix(in srgb, var(--color-accent) 28%, transparent);
57
+ }
58
+ }
59
+ }
60
+
61
+ // ─── Live / pulse ──────────────────────────────────────
62
+ // Ring radius in `em` so it scales with badge font-size.
63
+ // 0.9em ≈ 2× the dot width — visibly extends beyond the dot.
64
+ // `70%, 100%` holds the final (invisible) frame for a short
65
+ // rest between beats, giving a heartbeat rhythm instead of
66
+ // a constant fade.
67
+ @mixin badge-live {
68
+ @keyframes badge-pulse {
69
+ 0% {
70
+ box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 70%, transparent);
71
+ }
72
+ 70%,
73
+ 100% {
74
+ box-shadow: 0 0 0 0.6em color-mix(in srgb, var(--color-accent) 0%, transparent);
75
+ }
76
+ }
77
+
78
+ &::before {
79
+ @include motion-safe {
80
+ animation: badge-pulse 1.8s ease-out infinite;
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,78 @@
1
+ @use 'display' as *;
2
+ @use 'typography' as *;
3
+
4
+ @mixin stepper {
5
+ display: flex;
6
+ gap: 0;
7
+ counter-reset: ln-step;
8
+
9
+ > li {
10
+ counter-increment: ln-step;
11
+ flex: 1;
12
+ position: relative;
13
+ @include flex-col;
14
+ @include items-center;
15
+ gap: var(--gap);
16
+ min-width: 0;
17
+
18
+ // Numbered circle bullet
19
+ &::before {
20
+ content: counter(ln-step);
21
+ @include flex-center;
22
+ width: 2rem;
23
+ height: 2rem;
24
+ border-radius: 50%;
25
+ background: var(--color-border);
26
+ --color-fg: var(--fg-muted);
27
+ color: var(--color-fg);
28
+ @include typography(label-md);
29
+ font-weight: var(--font-semibold);
30
+ z-index: 1;
31
+ }
32
+
33
+ // Connector line to next step
34
+ &:not(:last-child)::after {
35
+ content: '';
36
+ position: absolute;
37
+ top: var(--size-md); // Geometric — connector vertical center matches bullet radius.
38
+ // Geometric — connector horizontal endpoints clear bullet edge.
39
+ left: calc(50% + var(--size-md));
40
+ right: calc(-50% + var(--size-md));
41
+ height: 2px;
42
+ background: var(--color-border);
43
+ }
44
+
45
+ > [data-ln-step-label] {
46
+ @include typography(label-md);
47
+ --color-fg: var(--fg-muted);
48
+ color: var(--color-fg);
49
+ text-align: center;
50
+ }
51
+
52
+ // States
53
+ &[data-ln-step="complete"] {
54
+ &::before {
55
+ background: var(--color-accent);
56
+ color: var(--color-accent-fg);
57
+ }
58
+ &::after {
59
+ background: var(--color-accent);
60
+ }
61
+ > [data-ln-step-label] {
62
+ color: var(--color-fg);
63
+ }
64
+ }
65
+
66
+ &[data-ln-step="current"] {
67
+ &::before {
68
+ background: var(--color-accent);
69
+ color: var(--color-accent-fg);
70
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 20%, transparent);
71
+ }
72
+ > [data-ln-step-label] {
73
+ color: var(--color-fg);
74
+ font-weight: var(--font-semibold);
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,215 @@
1
+ @use 'display' as *;
2
+ @use 'spacing' as *;
3
+ @use 'sizing' as *;
4
+ @use 'typography' as *;
5
+ @use 'colors' as *;
6
+ @use 'borders' as *;
7
+ @use 'transitions' as *;
8
+ @use 'position' as *;
9
+
10
+ // ─── Base table ─────────────────────────────────────────────────
11
+
12
+ @mixin table-base {
13
+ @include w-full;
14
+ background: var(--color-bg);
15
+ --radius: var(--radius-lg);
16
+ border-radius: var(--radius);
17
+ // `overflow: clip` not `overflow: hidden` — clips at rounded corners
18
+ // without establishing a scroll container, so sticky descendants
19
+ // (e.g. `@mixin data-table` thead/tfoot) bind to the outer
20
+ // `.app-main > section` scroll surface instead of being trapped
21
+ // inside the <table> element. Same rationale as `@mixin section-card`
22
+ // and `@mixin ln-table`.
23
+ overflow: clip;
24
+ --shadow: var(--shadow-resting);
25
+ box-shadow: var(--shadow);
26
+ border-collapse: collapse;
27
+ font-variant-numeric: tabular-nums;
28
+
29
+ thead {
30
+ --color-bg: var(--bg-sunken);
31
+ background: var(--color-bg);
32
+ border-block-end: var(--border-block-end, var(--border-width-strong) solid var(--color-border));
33
+ }
34
+
35
+ th {
36
+ @include text-left;
37
+ padding: var(--padding-y) var(--padding-x);
38
+ @include font-semibold;
39
+ font-size: var(--text-label-sm);
40
+ line-height: var(--line-height);
41
+ letter-spacing: 0.4px;
42
+ @include uppercase;
43
+ color: var(--color-fg);
44
+ }
45
+
46
+ tbody tr {
47
+ @include transition;
48
+ min-height: var(--density-row-h);
49
+
50
+ &:hover {
51
+ // Default hover stays --bg-sunken for standalone tables. Data-table
52
+ // re-binds --color-bg locally (see _data-table.scss) so its hover
53
+ // disambiguates from chrome that also uses --bg-sunken.
54
+ --color-bg: var(--bg-sunken);
55
+ background: var(--color-bg);
56
+ }
57
+ }
58
+
59
+ td {
60
+ padding: var(--padding-y) var(--padding-x);
61
+ @include border-b;
62
+ font-size: var(--font-size);
63
+ line-height: var(--line-height);
64
+ vertical-align: top;
65
+ }
66
+
67
+ tr:last-child td {
68
+ @include border-none;
69
+ }
70
+
71
+ td.numeric,
72
+ th.numeric {
73
+ @include text-right;
74
+ font-variant-numeric: tabular-nums;
75
+ }
76
+
77
+ td.center,
78
+ th.center {
79
+ @include text-center;
80
+ }
81
+
82
+ td.nowrap,
83
+ th.nowrap {
84
+ @include whitespace-nowrap;
85
+ }
86
+ }
87
+
88
+ // ─── Responsive (mobile stacked layout) ─────────────────────────
89
+ // Requires data-label attribute on <td> for column headers.
90
+
91
+ @mixin table-responsive {
92
+ th {
93
+ @include hidden;
94
+ }
95
+
96
+ tbody tr {
97
+ @include block;
98
+ // Structural gap between stacked row-cards.
99
+ --margin-block: var(--size-md);
100
+ margin-bottom: var(--margin-block);
101
+ @include border;
102
+ border-radius: var(--radius);
103
+ @include overflow-hidden;
104
+ }
105
+
106
+ td {
107
+ @include block;
108
+ @include text-right;
109
+ // Stacked rows need taller vertical rhythm than desktop table cells.
110
+ --padding-y: var(--size-sm-up);
111
+ --padding-x: var(--size-md);
112
+ padding: var(--padding-y) var(--padding-x);
113
+ @include border-b;
114
+ @include relative;
115
+ padding-left: 50%;
116
+
117
+ &:last-child {
118
+ @include border-none;
119
+ }
120
+
121
+ &::before {
122
+ content: attr(data-label);
123
+ @include absolute;
124
+ top: 0;
125
+ bottom: 0;
126
+ left: var(--size-md); // Geometric — ::before label inset matches td padding-x.
127
+ // Geometric — label width less the gutter to value column.
128
+ width: calc(50% - var(--size-lg));
129
+ @include flex;
130
+ @include items-center;
131
+ @include text-left;
132
+ @include font-semibold;
133
+ --color-fg: var(--fg-muted);
134
+ color: var(--color-fg);
135
+ @include text-xs;
136
+ @include uppercase;
137
+ @include truncate;
138
+ }
139
+ }
140
+ }
141
+
142
+ // ─── Variants ───────────────────────────────────────────────────
143
+
144
+ @mixin table-striped {
145
+ tbody tr:nth-child(odd) {
146
+ --color-bg: var(--bg-sunken);
147
+ background: var(--color-bg);
148
+ }
149
+ }
150
+
151
+ @mixin table-section-header {
152
+ --color-bg: var(--bg-sunken);
153
+ background: var(--color-bg);
154
+ @include font-semibold;
155
+ @include text-sm;
156
+ --color-fg: var(--fg-muted);
157
+ color: var(--color-fg);
158
+ letter-spacing: 0.3px;
159
+
160
+ &:hover {
161
+ background-color: var(--bg-sunken);
162
+ }
163
+ }
164
+
165
+ @mixin table-action {
166
+ @include inline-flex;
167
+ @include items-center;
168
+ @include justify-center;
169
+ --padding-y: var(--size-xs);
170
+ --padding-x: var(--size-sm);
171
+ padding: var(--padding-y) var(--padding-x);
172
+ @include text-sm;
173
+ @include transition-colors;
174
+
175
+ &:hover {
176
+ --color-bg: var(--bg-sunken);
177
+ background: var(--color-bg);
178
+ }
179
+
180
+ svg {
181
+ @include size(1.5rem);
182
+ }
183
+ }
184
+
185
+ // ─── Column filter button ──────────────────────────────────────
186
+ // Button inside <th> that triggers a filter popover/dropdown.
187
+ // Convention: add class="filter" to the trigger button.
188
+ // ln-table.js sets data-ln-filter-active on the <th> when active.
189
+
190
+ @mixin table-filter-button {
191
+ th .filter {
192
+ @include inline-flex;
193
+ @include items-center;
194
+ float: right;
195
+ --btn-padding-y: var(--size-2xs);
196
+ --btn-padding-x: var(--size-2xs);
197
+ @include rounded-sm;
198
+ opacity: 0.5;
199
+
200
+ &:hover {
201
+ opacity: 1;
202
+ --color-bg: var(--bg-sunken);
203
+ background: var(--color-bg);
204
+ }
205
+ }
206
+
207
+ th [data-ln-dropdown] {
208
+ float: right;
209
+ }
210
+
211
+ th[data-ln-filter-active] .filter {
212
+ opacity: 1;
213
+ color: var(--color-accent);
214
+ }
215
+ }
@@ -0,0 +1,64 @@
1
+ @use 'display' as *;
2
+ @use 'typography' as *;
3
+ @use 'borders' as *;
4
+ @use 'transitions' as *;
5
+ @use 'interaction' as *;
6
+
7
+ // Tabs — underline style
8
+
9
+ @mixin tabs-nav {
10
+ @include flex;
11
+ @include border-b;
12
+
13
+ [data-ln-tab][data-active] {
14
+ color: var(--color-accent);
15
+ border-bottom-color: var(--color-accent);
16
+ background: none;
17
+ }
18
+
19
+ [data-ln-tab][disabled] {
20
+ --color-fg: var(--fg-subtle);
21
+ color: var(--color-fg);
22
+ @include cursor-not-allowed;
23
+ @include opacity-50;
24
+
25
+ &:hover {
26
+ background: none;
27
+ border-bottom-color: transparent;
28
+ }
29
+ }
30
+ }
31
+
32
+ @mixin tabs-tab {
33
+ --color-fg: var(--fg-muted);
34
+ all: unset;
35
+ box-sizing: border-box;
36
+ --padding-y: var(--size-sm);
37
+ --padding-x: var(--size-md);
38
+ padding: var(--padding-y) var(--padding-x);
39
+ @include text-sm;
40
+ @include font-medium;
41
+ color: var(--color-fg);
42
+ @include cursor-pointer;
43
+ @include transition;
44
+ border-bottom: 2px solid transparent;
45
+ margin-bottom: -1px;
46
+
47
+ &:hover {
48
+ color: var(--color-accent);
49
+ background-color: color-mix(in srgb, var(--color-accent) 5%, transparent);
50
+ border-bottom-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
51
+ }
52
+
53
+ &:focus,
54
+ &:active,
55
+ &:visited {
56
+ background: none;
57
+ }
58
+ }
59
+
60
+ @mixin tabs-panel {
61
+ --padding-y: var(--size-lg);
62
+ --padding-x: var(--size-lg);
63
+ padding: var(--padding-y) var(--padding-x);
64
+ }
@@ -0,0 +1,69 @@
1
+ @use 'display' as *;
2
+ @use 'typography' as *;
3
+
4
+ @mixin timeline {
5
+ position: relative;
6
+
7
+ // Vertical rail — concentric with the bullet on both axes.
8
+ // X: bullet center = 0.125rem + 0.375rem = 0.5rem; rail = 0.5rem - 1px.
9
+ // Y: start/end at the first/last bullet center = 0.525rem from li edge.
10
+ &::before {
11
+ content: '';
12
+ position: absolute;
13
+ top: calc(var(--lh-caption) * var(--text-caption) / 2);
14
+ bottom: calc(var(--lh-caption) * var(--text-caption) / 2);
15
+ left: calc(var(--size-sm) - var(--border-width)); // Geometric — rail x-position aligned with bullet center.
16
+ width: 2px;
17
+ background: var(--color-border);
18
+ }
19
+
20
+ > li {
21
+ position: relative;
22
+ --padding-x: var(--size-xl);
23
+ padding-left: var(--padding-x);
24
+ --padding-y: var(--size-lg);
25
+ padding-bottom: var(--padding-y);
26
+
27
+ &:last-child {
28
+ padding-bottom: 0;
29
+ }
30
+
31
+ // Bullet — centered on the first line of <time> (caption role).
32
+ // Line-box height = var(--lh-caption) * var(--text-caption) = 1.05rem.
33
+ // Line center = 0.525rem; bullet is 0.75rem tall so top = 0.15rem.
34
+ &::before {
35
+ content: '';
36
+ position: absolute;
37
+ top: calc((var(--lh-caption) * var(--text-caption) - var(--size-sm-up)) / 2); // Geometric — bullet vertical alignment to caption baseline.
38
+ left: var(--size-2xs); // Geometric — bullet x-position inside li padding.
39
+ width: 0.75rem;
40
+ height: 0.75rem;
41
+ border-radius: 50%;
42
+ background: var(--color-accent);
43
+ box-shadow: 0 0 0 3px var(--color-bg);
44
+ }
45
+
46
+ > time {
47
+ display: block;
48
+ @include typography(caption);
49
+ --color-fg: var(--fg-subtle);
50
+ color: var(--color-fg);
51
+ --margin-block: var(--size-xs);
52
+ margin-bottom: var(--margin-block);
53
+ }
54
+
55
+ > h4 {
56
+ @include typography(title-sm);
57
+ color: var(--color-fg);
58
+ margin: 0;
59
+ }
60
+
61
+ > p {
62
+ @include typography(body-sm);
63
+ --color-fg: var(--fg-muted);
64
+ color: var(--color-fg);
65
+ --margin-block: var(--size-xs);
66
+ margin: var(--margin-block) 0 0;
67
+ }
68
+ }
69
+ }