@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.
- package/README.md +177 -0
- package/js/COMPONENTS.md +1102 -0
- package/js/index.js +41 -0
- package/js/ln-accordion/README.md +137 -0
- package/js/ln-accordion/ln-accordion.js +1 -0
- package/js/ln-accordion/src/ln-accordion.js +41 -0
- package/js/ln-ajax/README.md +91 -0
- package/js/ln-ajax/ln-ajax.js +1 -0
- package/js/ln-ajax/src/ln-ajax.js +277 -0
- package/js/ln-api-connector/README.md +150 -0
- package/js/ln-api-connector/ln-api-connector.js +1 -0
- package/js/ln-api-connector/src/ln-api-connector.js +265 -0
- package/js/ln-autoresize/README.md +80 -0
- package/js/ln-autoresize/ln-autoresize.js +1 -0
- package/js/ln-autoresize/src/ln-autoresize.js +47 -0
- package/js/ln-autosave/README.md +92 -0
- package/js/ln-autosave/ln-autosave.js +1 -0
- package/js/ln-autosave/src/ln-autosave.js +147 -0
- package/js/ln-circular-progress/README.md +161 -0
- package/js/ln-circular-progress/ln-circular-progress.js +1 -0
- package/js/ln-circular-progress/src/ln-circular-progress.js +133 -0
- package/js/ln-confirm/README.md +86 -0
- package/js/ln-confirm/_ln-confirm.scss +13 -0
- package/js/ln-confirm/ln-confirm.js +1 -0
- package/js/ln-confirm/src/ln-confirm.js +131 -0
- package/js/ln-core/crypto.js +83 -0
- package/js/ln-core/helpers.js +411 -0
- package/js/ln-core/index.js +5 -0
- package/js/ln-core/persist.js +71 -0
- package/js/ln-core/positioning.js +207 -0
- package/js/ln-core/reactive.js +74 -0
- package/js/ln-couchdb-connector/README.md +156 -0
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
- package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +348 -0
- package/js/ln-data-coordinator/README.md +165 -0
- package/js/ln-data-coordinator/ln-data-coordinator.js +1 -0
- package/js/ln-data-coordinator/src/ln-data-coordinator.js +249 -0
- package/js/ln-data-store/README.md +94 -0
- package/js/ln-data-store/ln-data-store.js +1 -0
- package/js/ln-data-store/src/ln-data-store.js +699 -0
- package/js/ln-data-table/README.md +110 -0
- package/js/ln-data-table/ln-data-table.js +1 -0
- package/js/ln-data-table/ln-data-table.scss +10 -0
- package/js/ln-data-table/src/ln-data-table.js +1103 -0
- package/js/ln-date/README.md +151 -0
- package/js/ln-date/ln-date.js +1 -0
- package/js/ln-date/src/ln-date.js +442 -0
- package/js/ln-dropdown/README.md +117 -0
- package/js/ln-dropdown/ln-dropdown.js +1 -0
- package/js/ln-dropdown/ln-dropdown.scss +15 -0
- package/js/ln-dropdown/src/ln-dropdown.js +174 -0
- package/js/ln-external-links/README.md +341 -0
- package/js/ln-external-links/ln-external-links.js +1 -0
- package/js/ln-external-links/src/ln-external-links.js +116 -0
- package/js/ln-filter/README.md +99 -0
- package/js/ln-filter/ln-filter.js +1 -0
- package/js/ln-filter/ln-filter.scss +7 -0
- package/js/ln-filter/src/ln-filter.js +404 -0
- package/js/ln-form/README.md +101 -0
- package/js/ln-form/ln-form.js +1 -0
- package/js/ln-form/src/ln-form.js +199 -0
- package/js/ln-http/README.md +89 -0
- package/js/ln-http/ln-http.js +1 -0
- package/js/ln-http/src/ln-http.js +219 -0
- package/js/ln-icons/README.md +88 -0
- package/js/ln-icons/ln-icons.js +1 -0
- package/js/ln-icons/src/ln-icons.js +169 -0
- package/js/ln-link/README.md +303 -0
- package/js/ln-link/ln-link.js +1 -0
- package/js/ln-link/src/ln-link.js +196 -0
- package/js/ln-modal/README.md +154 -0
- package/js/ln-modal/ln-modal.js +1 -0
- package/js/ln-modal/ln-modal.scss +11 -0
- package/js/ln-modal/src/ln-modal.js +201 -0
- package/js/ln-nav/README.md +70 -0
- package/js/ln-nav/ln-nav.js +1 -0
- package/js/ln-nav/src/ln-nav.js +177 -0
- package/js/ln-number/README.md +122 -0
- package/js/ln-number/ln-number.js +1 -0
- package/js/ln-number/src/ln-number.js +302 -0
- package/js/ln-popover/README.md +127 -0
- package/js/ln-popover/ln-popover.js +1 -0
- package/js/ln-popover/src/ln-popover.js +288 -0
- package/js/ln-progress/README.md +442 -0
- package/js/ln-progress/ln-progress.js +1 -0
- package/js/ln-progress/src/ln-progress.js +150 -0
- package/js/ln-search/README.md +83 -0
- package/js/ln-search/ln-search.js +1 -0
- package/js/ln-search/ln-search.scss +7 -0
- package/js/ln-search/src/ln-search.js +114 -0
- package/js/ln-sortable/README.md +95 -0
- package/js/ln-sortable/ln-sortable.js +1 -0
- package/js/ln-sortable/src/ln-sortable.js +203 -0
- package/js/ln-table/README.md +101 -0
- package/js/ln-table/ln-table-sort.js +1 -0
- package/js/ln-table/ln-table.js +1 -0
- package/js/ln-table/ln-table.scss +11 -0
- package/js/ln-table/src/ln-table-sort.js +168 -0
- package/js/ln-table/src/ln-table.js +473 -0
- package/js/ln-tabs/README.md +137 -0
- package/js/ln-tabs/ln-tabs.js +1 -0
- package/js/ln-tabs/src/ln-tabs.js +171 -0
- package/js/ln-time/README.md +81 -0
- package/js/ln-time/ln-time.js +1 -0
- package/js/ln-time/src/ln-time.js +192 -0
- package/js/ln-toast/README.md +122 -0
- package/js/ln-toast/ln-toast.js +15 -0
- package/js/ln-toast/src/ln-toast.js +210 -0
- package/js/ln-toast/template.html +14 -0
- package/js/ln-toggle/README.md +137 -0
- package/js/ln-toggle/ln-toggle.js +1 -0
- package/js/ln-toggle/src/ln-toggle.js +139 -0
- package/js/ln-tooltip/README.md +58 -0
- package/js/ln-tooltip/ln-tooltip.js +1 -0
- package/js/ln-tooltip/ln-tooltip.scss +9 -0
- package/js/ln-tooltip/src/ln-tooltip.js +169 -0
- package/js/ln-translations/README.md +96 -0
- package/js/ln-translations/ln-translations.js +1 -0
- package/js/ln-translations/src/ln-translations.js +275 -0
- package/js/ln-upload/README.md +180 -0
- package/js/ln-upload/ln-upload.js +1 -0
- package/js/ln-upload/ln-upload.scss +20 -0
- package/js/ln-upload/src/ln-upload.js +407 -0
- package/js/ln-validate/README.md +108 -0
- package/js/ln-validate/ln-validate.js +1 -0
- package/js/ln-validate/src/ln-validate.js +160 -0
- package/package.json +55 -0
- package/scss/base/_global.scss +83 -0
- package/scss/base/_reset.scss +17 -0
- package/scss/base/_typography.scss +125 -0
- package/scss/components/_accordion.scss +34 -0
- package/scss/components/_ajax.scss +15 -0
- package/scss/components/_alert.scss +5 -0
- package/scss/components/_app-shell.scss +15 -0
- package/scss/components/_avatar.scss +6 -0
- package/scss/components/_breadcrumbs.scss +33 -0
- package/scss/components/_button.scss +20 -0
- package/scss/components/_card.scss +10 -0
- package/scss/components/_chip.scss +5 -0
- package/scss/components/_circular-progress.scss +29 -0
- package/scss/components/_confirm.scss +5 -0
- package/scss/components/_data-table.scss +83 -0
- package/scss/components/_dropdown.scss +25 -0
- package/scss/components/_empty-state.scss +22 -0
- package/scss/components/_form.scss +100 -0
- package/scss/components/_layout.scss +8 -0
- package/scss/components/_link.scss +11 -0
- package/scss/components/_ln-table.scss +60 -0
- package/scss/components/_loader.scss +6 -0
- package/scss/components/_modal.scss +20 -0
- package/scss/components/_nav.scss +9 -0
- package/scss/components/_page-header.scss +10 -0
- package/scss/components/_popover.scss +10 -0
- package/scss/components/_progress.scss +17 -0
- package/scss/components/_prose.scss +5 -0
- package/scss/components/_scrollbar.scss +32 -0
- package/scss/components/_sections.scss +12 -0
- package/scss/components/_sidebar.scss +5 -0
- package/scss/components/_stat-card.scss +5 -0
- package/scss/components/_status-badge.scss +4 -0
- package/scss/components/_stepper.scss +5 -0
- package/scss/components/_table.scss +19 -0
- package/scss/components/_tabs.scss +21 -0
- package/scss/components/_timeline.scss +14 -0
- package/scss/components/_toast.scss +41 -0
- package/scss/components/_toggle.scss +81 -0
- package/scss/components/_tooltip.scss +18 -0
- package/scss/components/_translations.scss +111 -0
- package/scss/components/_upload.scss +51 -0
- package/scss/config/_breakpoints.scss +72 -0
- package/scss/config/_density.scss +117 -0
- package/scss/config/_icons.scss +37 -0
- package/scss/config/_mixins.scss +13 -0
- package/scss/config/_theme.scss +216 -0
- package/scss/config/_tokens.scss +419 -0
- package/scss/config/mixins/_accordion.scss +52 -0
- package/scss/config/mixins/_ajax.scss +39 -0
- package/scss/config/mixins/_alert.scss +82 -0
- package/scss/config/mixins/_app-shell.scss +312 -0
- package/scss/config/mixins/_avatar.scss +109 -0
- package/scss/config/mixins/_borders.scss +36 -0
- package/scss/config/mixins/_breadcrumbs.scss +72 -0
- package/scss/config/mixins/_breakpoints.scss +62 -0
- package/scss/config/mixins/_btn.scss +179 -0
- package/scss/config/mixins/_card.scss +338 -0
- package/scss/config/mixins/_chip.scss +66 -0
- package/scss/config/mixins/_circular-progress.scss +71 -0
- package/scss/config/mixins/_collapsible.scss +24 -0
- package/scss/config/mixins/_colors.scss +46 -0
- package/scss/config/mixins/_confirm.scss +31 -0
- package/scss/config/mixins/_data-table.scss +346 -0
- package/scss/config/mixins/_display.scss +32 -0
- package/scss/config/mixins/_dropdown.scss +143 -0
- package/scss/config/mixins/_empty-state.scss +30 -0
- package/scss/config/mixins/_focus.scss +55 -0
- package/scss/config/mixins/_footer.scss +42 -0
- package/scss/config/mixins/_form.scss +601 -0
- package/scss/config/mixins/_index.scss +58 -0
- package/scss/config/mixins/_interaction.scss +15 -0
- package/scss/config/mixins/_kbd.scss +22 -0
- package/scss/config/mixins/_layout.scss +117 -0
- package/scss/config/mixins/_link.scss +55 -0
- package/scss/config/mixins/_ln-table.scss +420 -0
- package/scss/config/mixins/_loader.scss +26 -0
- package/scss/config/mixins/_modal.scss +66 -0
- package/scss/config/mixins/_motion.scss +19 -0
- package/scss/config/mixins/_nav.scss +273 -0
- package/scss/config/mixins/_page-header.scss +69 -0
- package/scss/config/mixins/_popover.scss +25 -0
- package/scss/config/mixins/_position.scss +32 -0
- package/scss/config/mixins/_progress.scss +56 -0
- package/scss/config/mixins/_prose.scss +127 -0
- package/scss/config/mixins/_shadows.scss +8 -0
- package/scss/config/mixins/_sidebar.scss +95 -0
- package/scss/config/mixins/_sizing.scss +6 -0
- package/scss/config/mixins/_spacing.scss +19 -0
- package/scss/config/mixins/_stat-card.scss +68 -0
- package/scss/config/mixins/_status-badge.scss +83 -0
- package/scss/config/mixins/_stepper.scss +78 -0
- package/scss/config/mixins/_table.scss +215 -0
- package/scss/config/mixins/_tabs.scss +64 -0
- package/scss/config/mixins/_timeline.scss +69 -0
- package/scss/config/mixins/_toast.scss +148 -0
- package/scss/config/mixins/_tooltip.scss +111 -0
- package/scss/config/mixins/_transitions.scss +10 -0
- package/scss/config/mixins/_translations.scss +124 -0
- package/scss/config/mixins/_typography.scss +57 -0
- package/scss/config/mixins/_upload.scss +168 -0
- package/scss/ln-ashlar.scss +62 -0
- package/scss/tabler-icons.txt +5039 -0
- package/scss/utilities/_animations.scss +83 -0
- package/scss/utilities/_utilities.scss +49 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Theme — ln-ashlar
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
// Dark-mode overrides. Inverts the neutral scale in place, re-tunes
|
|
5
|
+
// shadows and primary tint layers.
|
|
6
|
+
//
|
|
7
|
+
// Activation (any of the three):
|
|
8
|
+
// <html data-theme="dark"> ← explicit force
|
|
9
|
+
// @media (prefers-color-scheme: dark) ← system preference
|
|
10
|
+
// :root:not([data-theme="light"]) ← opt-out of auto
|
|
11
|
+
//
|
|
12
|
+
// See docs/css/theming.md for the full guide.
|
|
13
|
+
// ==========================================================================
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Shared dark overrides — used by both activation paths.
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
@mixin ln-dark-tokens {
|
|
19
|
+
// Neutral scale — inverted
|
|
20
|
+
--color-neutral-50: 220 20% 8%;
|
|
21
|
+
--color-neutral-100: 220 16% 12%;
|
|
22
|
+
--color-neutral-150: 220 14% 18%;
|
|
23
|
+
--color-neutral-200: 220 13% 24%;
|
|
24
|
+
--color-neutral-300: 220 13% 36%;
|
|
25
|
+
--color-neutral-400: 218 11% 52%;
|
|
26
|
+
--color-neutral-500: 220 9% 60%;
|
|
27
|
+
--color-neutral-600: 220 11% 72%;
|
|
28
|
+
--color-neutral-700: 220 14% 82%;
|
|
29
|
+
--color-neutral-800: 220 20% 90%;
|
|
30
|
+
--color-neutral-900: 221 30% 97%;
|
|
31
|
+
|
|
32
|
+
// Vocabulary — bg
|
|
33
|
+
// Explicit ladder: body (darkest) < base < elevated < sunken (mid).
|
|
34
|
+
// Dark UI convention keeps elevated = lighter; the neutral-scale
|
|
35
|
+
// inversion alone would flip elevation direction, so we restate
|
|
36
|
+
// the four vocabulary entries explicitly.
|
|
37
|
+
--bg-base: hsl(220 16% 13%);
|
|
38
|
+
--bg-elevated: hsl(220 16% 17%);
|
|
39
|
+
--bg-sunken: hsl(220 16% 20%);
|
|
40
|
+
--bg-recessed: hsl(220 16% 9%);
|
|
41
|
+
|
|
42
|
+
// Vocabulary — fg
|
|
43
|
+
--fg-default: hsl(0 0% 95%);
|
|
44
|
+
--fg-muted: hsl(220 9% 60%);
|
|
45
|
+
--fg-subtle: hsl(218 11% 52%);
|
|
46
|
+
|
|
47
|
+
// Vocabulary — border (collapses old --color-border-light bump)
|
|
48
|
+
--border-subtle: hsl(220 14% 20%);
|
|
49
|
+
--border-strong: hsl(220 13% 36%);
|
|
50
|
+
--border-strong-hover: hsl(218 11% 52%);
|
|
51
|
+
|
|
52
|
+
// Scrim — keep dark overlay in dark mode (neutral-900 inverts to
|
|
53
|
+
// near-white, which would produce a LIGHT scrim; explicit override
|
|
54
|
+
// preserves conventional modal-darkening behavior).
|
|
55
|
+
--color-scrim: hsl(0 0% 0% / 0.6);
|
|
56
|
+
|
|
57
|
+
// Primary tint layers — re-tuned for dark surfaces
|
|
58
|
+
--color-primary-light: 232 60% 22%;
|
|
59
|
+
--color-primary-lighter: 232 50% 15%;
|
|
60
|
+
|
|
61
|
+
// Status tint layers — re-tuned for dark surfaces (parallel to primary)
|
|
62
|
+
--color-success-light: 142 50% 18%;
|
|
63
|
+
--color-success-lighter: 142 40% 13%;
|
|
64
|
+
--color-warning-light: 32 55% 20%;
|
|
65
|
+
--color-warning-lighter: 32 45% 14%;
|
|
66
|
+
--color-info-light: 217 55% 22%;
|
|
67
|
+
--color-info-lighter: 217 45% 15%;
|
|
68
|
+
--color-error-light: 0 50% 20%;
|
|
69
|
+
--color-error-lighter: 0 40% 14%;
|
|
70
|
+
|
|
71
|
+
// Secondary tint layers — re-tuned for dark surfaces
|
|
72
|
+
--color-secondary-light: 160 55% 20%;
|
|
73
|
+
--color-secondary-lighter: 160 45% 14%;
|
|
74
|
+
|
|
75
|
+
// Shadows — solid black, boosted alpha, no hue (cool-tint
|
|
76
|
+
// disappears on dark surfaces)
|
|
77
|
+
--shadow-xs:
|
|
78
|
+
0 1px 2px 0 hsl(0 0% 0% / 0.32);
|
|
79
|
+
--shadow-sm:
|
|
80
|
+
0 1px 3px 0 hsl(0 0% 0% / 0.40),
|
|
81
|
+
0 1px 2px -1px hsl(0 0% 0% / 0.30);
|
|
82
|
+
--shadow-md:
|
|
83
|
+
0 4px 12px -2px hsl(0 0% 0% / 0.48),
|
|
84
|
+
0 2px 4px -2px hsl(0 0% 0% / 0.32);
|
|
85
|
+
--shadow-lg:
|
|
86
|
+
0 12px 24px -6px hsl(0 0% 0% / 0.56),
|
|
87
|
+
0 8px 12px -4px hsl(0 0% 0% / 0.40);
|
|
88
|
+
--shadow-xl:
|
|
89
|
+
0 24px 48px -12px hsl(0 0% 0% / 0.64),
|
|
90
|
+
0 12px 24px -6px hsl(0 0% 0% / 0.48);
|
|
91
|
+
--shadow-2xl:
|
|
92
|
+
0 36px 72px -18px hsl(0 0% 0% / 0.72),
|
|
93
|
+
0 18px 36px -9px hsl(0 0% 0% / 0.56);
|
|
94
|
+
--shadow-inner:
|
|
95
|
+
inset 0 2px 4px 0 hsl(0 0% 0% / 0.32);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Explicit attribute activation
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
[data-theme="dark"] {
|
|
102
|
+
@include ln-dark-tokens;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// System preference activation (opt-out via data-theme="light")
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
@media (prefers-color-scheme: dark) {
|
|
109
|
+
:root:not([data-theme="light"]) {
|
|
110
|
+
@include ln-dark-tokens;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Named presets — demo theme picker. Activation:
|
|
116
|
+
// <html data-theme="ocean"> <html data-theme="sunset"> etc.
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
[data-theme="ocean"] {
|
|
120
|
+
--color-primary: 190 80% 35%;
|
|
121
|
+
--color-primary-light: 190 60% 90%;
|
|
122
|
+
--color-primary-lighter: 190 50% 95%;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
[data-theme="sunset"] {
|
|
126
|
+
--color-primary: 10 80% 50%;
|
|
127
|
+
--color-primary-light: 10 70% 92%;
|
|
128
|
+
--color-primary-lighter: 10 60% 96%;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
[data-theme="midnight"] {
|
|
132
|
+
@include ln-dark-tokens;
|
|
133
|
+
--color-primary: 265 70% 60%;
|
|
134
|
+
--color-primary-light: 265 50% 22%;
|
|
135
|
+
--color-primary-lighter: 265 40% 15%;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
[data-theme="glass"] {
|
|
139
|
+
@include ln-dark-tokens;
|
|
140
|
+
|
|
141
|
+
// Electric blue accent — luminescent on dark navy glass
|
|
142
|
+
--color-primary: 218 95% 62%;
|
|
143
|
+
--color-primary-light: 218 55% 24%;
|
|
144
|
+
--color-primary-lighter: 218 50% 16%;
|
|
145
|
+
|
|
146
|
+
// Flat — zero radius everywhere
|
|
147
|
+
--radius-sm: 0;
|
|
148
|
+
--radius-md: 0;
|
|
149
|
+
--radius-lg: 0;
|
|
150
|
+
--radius-xl: 0;
|
|
151
|
+
--radius-full: 0;
|
|
152
|
+
|
|
153
|
+
// Flat — no elevation shadows. --shadow-inner kept for recessed
|
|
154
|
+
// surfaces (code blocks, progress tracks) which read it as a depth
|
|
155
|
+
// affordance rather than elevation.
|
|
156
|
+
--shadow-xs: none;
|
|
157
|
+
--shadow-sm: none;
|
|
158
|
+
--shadow-md: none;
|
|
159
|
+
--shadow-lg: none;
|
|
160
|
+
--shadow-xl: none;
|
|
161
|
+
--shadow-2xl: none;
|
|
162
|
+
|
|
163
|
+
// ── Buttons — neutral chrome via --btn-* rebind, accent variant via
|
|
164
|
+
// cross-cutting --color-accent-bg-* companion tokens. Theme rebinds
|
|
165
|
+
// at :root only; library owns structure. See CLAUDE.md
|
|
166
|
+
// ## Theme Architecture for the contract.
|
|
167
|
+
--btn-bg: var(--bg-elevated);
|
|
168
|
+
--btn-bg-hover: var(--bg-sunken);
|
|
169
|
+
--btn-border: var(--color-accent);
|
|
170
|
+
--btn-border-hover: var(--color-accent-hover);
|
|
171
|
+
|
|
172
|
+
// ── Accent buttons — translucent fill via consumer-scope rebind
|
|
173
|
+
// Rebind --btn-* on the button itself (not at theme :root) so
|
|
174
|
+
// var(--color-primary) inside the values resolves on the button's
|
|
175
|
+
// cascade — letting .success / .error / .warning / .info status
|
|
176
|
+
// overrides reach the fill and text color. Token-only rebinds; no
|
|
177
|
+
// background/color/border-color declarations, no &:hover blocks
|
|
178
|
+
// (button-base already handles state via --btn-*-hover).
|
|
179
|
+
button[type="submit"],
|
|
180
|
+
.btn {
|
|
181
|
+
--btn-bg: hsl(var(--color-primary) / 0.2);
|
|
182
|
+
--btn-fg: hsl(var(--color-primary));
|
|
183
|
+
--btn-bg-hover: hsl(var(--color-primary) / 0.3);
|
|
184
|
+
--btn-fg-hover: hsl(var(--color-primary));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ── Nav surface — palette-only rebind ──────────────────────────
|
|
188
|
+
// @mixin nav reads --nav-link-border-color* via fallback (defaults:
|
|
189
|
+
// transparent). Glass rebinds them so hover/active draw an accent
|
|
190
|
+
// ring. --nav-list-bleed shifts the ul to the sidebar's vertical
|
|
191
|
+
// borders so dividers reach edge-to-edge; @mixin nav reads it with
|
|
192
|
+
// `0` fallback so default theme is unaffected.
|
|
193
|
+
--nav-link-border-color-hover: var(--color-accent);
|
|
194
|
+
--nav-link-border-color-active: var(--color-accent);
|
|
195
|
+
--nav-list-bleed: calc(-1 * var(--padding-x));
|
|
196
|
+
|
|
197
|
+
// Active-nav wash — Glass shifts --color-accent-tint one step
|
|
198
|
+
// darker (var(--color-primary-light) instead of -lighter) for
|
|
199
|
+
// stronger contrast on the deep dark surface. Replaces the
|
|
200
|
+
// pre-refactor descendant override on a.active. Side-effect:
|
|
201
|
+
// dropdown active items + upload drop-zone also pick up the
|
|
202
|
+
// slightly darker tint — improvement, not regression.
|
|
203
|
+
--color-accent-tint: hsl(var(--color-primary-light));
|
|
204
|
+
|
|
205
|
+
// ── Dropdown / menu-items dividers ─────────────────────────────
|
|
206
|
+
// @mixin menu-items reads SOFT --border-block-start on `li + li`
|
|
207
|
+
// and `hr` with `none` fallback. Glass rebinds the slot in scope
|
|
208
|
+
// so the divider appears for both. Scoped (not theme :root)
|
|
209
|
+
// because --border-block-start is read by ~10 other mixins
|
|
210
|
+
// (cards, tables, accordions) where the divider should NOT appear.
|
|
211
|
+
[data-ln-dropdown-menu],
|
|
212
|
+
.menu-items {
|
|
213
|
+
--border-block-start: var(--border-width) solid var(--color-border);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
@use 'mixins/breakpoints' as *;
|
|
2
|
+
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
// Design Tokens — ln-ashlar
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
// Single source of truth for all design values.
|
|
7
|
+
// All components reference these CSS variables.
|
|
8
|
+
// For theming: override at :root or scope to an element.
|
|
9
|
+
//
|
|
10
|
+
// Colors are stored as bare HSL triplets to enable alpha transparency:
|
|
11
|
+
// hsl(var(--color-primary)) → solid color
|
|
12
|
+
// hsl(var(--color-primary) / 0.5) → 50% transparent
|
|
13
|
+
//
|
|
14
|
+
// Theming example:
|
|
15
|
+
// .dark-theme { --color-bg: ...; }
|
|
16
|
+
// ==========================================================================
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
|
|
20
|
+
// -----------------------------------------------------------------------
|
|
21
|
+
// Colors — Primary
|
|
22
|
+
// -----------------------------------------------------------------------
|
|
23
|
+
--color-primary: 216 95% 42%;
|
|
24
|
+
--color-primary-light: 216 95% 93%;
|
|
25
|
+
--color-primary-lighter: 216 95% 97%;
|
|
26
|
+
|
|
27
|
+
// -----------------------------------------------------------------------
|
|
28
|
+
// Colors — Secondary (brand accent — surface/element color, NOT text)
|
|
29
|
+
// For subdued text color, see --fg-muted in the logical token section.
|
|
30
|
+
// -----------------------------------------------------------------------
|
|
31
|
+
--color-secondary: 160 76% 40%;
|
|
32
|
+
--color-secondary-light: 160 76% 93%;
|
|
33
|
+
--color-secondary-lighter: 160 76% 97%;
|
|
34
|
+
|
|
35
|
+
// -----------------------------------------------------------------------
|
|
36
|
+
// Colors — Status
|
|
37
|
+
// -----------------------------------------------------------------------
|
|
38
|
+
--color-success: 142 76% 36%;
|
|
39
|
+
--color-success-light: 142 76% 93%;
|
|
40
|
+
--color-success-lighter: 142 76% 97%;
|
|
41
|
+
|
|
42
|
+
--color-error: 0 84% 50%;
|
|
43
|
+
--color-error-light: 0 84% 93%;
|
|
44
|
+
--color-error-lighter: 0 84% 97%;
|
|
45
|
+
|
|
46
|
+
--color-warning: 32 95% 44%;
|
|
47
|
+
--color-warning-light: 32 95% 93%;
|
|
48
|
+
--color-warning-lighter: 32 95% 97%;
|
|
49
|
+
|
|
50
|
+
--color-info: 217 91% 60%;
|
|
51
|
+
--color-info-light: 217 91% 93%;
|
|
52
|
+
--color-info-lighter: 217 91% 97%;
|
|
53
|
+
|
|
54
|
+
// -----------------------------------------------------------------------
|
|
55
|
+
// Colors — Neutral scale (canonical greys)
|
|
56
|
+
// -----------------------------------------------------------------------
|
|
57
|
+
// Mixins may reach into the neutral scale directly when no semantic
|
|
58
|
+
// token matches the intent. Every such reference must be verified
|
|
59
|
+
// during dark-mode audits -- semantic tokens inherit dark adjustments
|
|
60
|
+
// automatically, direct-neutral references do not.
|
|
61
|
+
//
|
|
62
|
+
--color-neutral-50: 215 20% 98%;
|
|
63
|
+
--color-neutral-100: 215 16% 96%;
|
|
64
|
+
--color-neutral-150: 215 14% 93%;
|
|
65
|
+
--color-neutral-200: 215 13% 91%;
|
|
66
|
+
--color-neutral-300: 215 13% 83%;
|
|
67
|
+
--color-neutral-400: 215 11% 65%;
|
|
68
|
+
--color-neutral-500: 215 9% 46%;
|
|
69
|
+
--color-neutral-600: 215 11% 34%;
|
|
70
|
+
--color-neutral-700: 215 14% 24%;
|
|
71
|
+
--color-neutral-800: 215 20% 15%;
|
|
72
|
+
--color-neutral-900: 215 39% 11%;
|
|
73
|
+
|
|
74
|
+
// -----------------------------------------------------------------------
|
|
75
|
+
// Colors — Backgrounds
|
|
76
|
+
// -----------------------------------------------------------------------
|
|
77
|
+
--color-white: 0 0% 100%;
|
|
78
|
+
|
|
79
|
+
// -----------------------------------------------------------------------
|
|
80
|
+
// Size scale — canonical spacing primitives
|
|
81
|
+
// -----------------------------------------------------------------------
|
|
82
|
+
// Public API surface — full scale exposed. All padding, margin, gap,
|
|
83
|
+
// inset, and positional-offset spacing references one of these steps.
|
|
84
|
+
// Intermediate steps use t-shirt + `-up` suffix.
|
|
85
|
+
//
|
|
86
|
+
// Mixin bodies read --size-* only when a logical token (--padding-x,
|
|
87
|
+
// --padding-y, --gap) is not semantically appropriate. Otherwise they
|
|
88
|
+
// read the logical token, which is re-bound under density / theme /
|
|
89
|
+
// region scopes (see Logical tokens block below).
|
|
90
|
+
// -----------------------------------------------------------------------
|
|
91
|
+
--size-0: 0;
|
|
92
|
+
--size-2xs: 0.125rem; // 2px
|
|
93
|
+
--size-xs: 0.25rem; // 4px
|
|
94
|
+
--size-xs-up: 0.375rem; // 6px
|
|
95
|
+
--size-sm: 0.5rem; // 8px
|
|
96
|
+
--size-sm-up: 0.75rem; // 12px
|
|
97
|
+
--size-md: 1rem; // 16px
|
|
98
|
+
--size-md-up: 1.25rem; // 20px
|
|
99
|
+
--size-lg: 1.5rem; // 24px
|
|
100
|
+
--size-xl: 2rem; // 32px
|
|
101
|
+
--size-2xl: 3rem; // 48px
|
|
102
|
+
--size-3xl: 4rem; // 64px
|
|
103
|
+
|
|
104
|
+
// -----------------------------------------------------------------------
|
|
105
|
+
// Border Width
|
|
106
|
+
// -----------------------------------------------------------------------
|
|
107
|
+
// Public API surface — full scale exposed; internal usage may skip levels.
|
|
108
|
+
--border-width: 1px;
|
|
109
|
+
--border-width-strong: 2px;
|
|
110
|
+
|
|
111
|
+
// -----------------------------------------------------------------------
|
|
112
|
+
// Content widths
|
|
113
|
+
// -----------------------------------------------------------------------
|
|
114
|
+
// Public API surface — full scale exposed; internal usage may skip levels.
|
|
115
|
+
--max-w-prose: 65ch;
|
|
116
|
+
--max-w-form: 32rem;
|
|
117
|
+
--max-w-content: 48rem;
|
|
118
|
+
--max-w-container: 80rem;
|
|
119
|
+
|
|
120
|
+
// -----------------------------------------------------------------------
|
|
121
|
+
// Border Radius
|
|
122
|
+
// -----------------------------------------------------------------------
|
|
123
|
+
--radius-none: 0;
|
|
124
|
+
--radius-sm: 0.25rem; // 4px
|
|
125
|
+
--radius-md: 0.5rem; // 8px
|
|
126
|
+
--radius-lg: 0.75rem; // 12px
|
|
127
|
+
--radius-xl: 1rem; // 16px
|
|
128
|
+
--radius-full: 9999px;
|
|
129
|
+
|
|
130
|
+
// -----------------------------------------------------------------------
|
|
131
|
+
// Shadows — cool-tinted, dual-layer (v1.1)
|
|
132
|
+
// -----------------------------------------------------------------------
|
|
133
|
+
// Public API surface — full scale exposed; internal usage may skip levels.
|
|
134
|
+
--shadow-none: none;
|
|
135
|
+
|
|
136
|
+
--shadow-xs:
|
|
137
|
+
0 1px 2px 0 hsl(220 40% 15% / 0.04);
|
|
138
|
+
|
|
139
|
+
--shadow-sm:
|
|
140
|
+
0 1px 3px 0 hsl(220 40% 15% / 0.08),
|
|
141
|
+
0 1px 2px -1px hsl(220 40% 15% / 0.04);
|
|
142
|
+
|
|
143
|
+
--shadow-md:
|
|
144
|
+
0 4px 12px -2px hsl(220 40% 15% / 0.10),
|
|
145
|
+
0 2px 4px -2px hsl(220 40% 15% / 0.06);
|
|
146
|
+
|
|
147
|
+
--shadow-lg:
|
|
148
|
+
0 12px 24px -6px hsl(220 40% 15% / 0.12),
|
|
149
|
+
0 8px 12px -4px hsl(220 40% 15% / 0.08);
|
|
150
|
+
|
|
151
|
+
--shadow-xl:
|
|
152
|
+
0 24px 48px -12px hsl(220 40% 15% / 0.16),
|
|
153
|
+
0 12px 24px -6px hsl(220 40% 15% / 0.10);
|
|
154
|
+
|
|
155
|
+
--shadow-2xl:
|
|
156
|
+
0 36px 72px -18px hsl(220 40% 15% / 0.20),
|
|
157
|
+
0 18px 36px -9px hsl(220 40% 15% / 0.12);
|
|
158
|
+
|
|
159
|
+
--shadow-inner:
|
|
160
|
+
inset 0 2px 4px 0 hsl(220 40% 15% / 0.06);
|
|
161
|
+
|
|
162
|
+
// Color-aware shadows (for focus halos and coloured CTAs)
|
|
163
|
+
--shadow-primary: 0 8px 24px -6px hsl(var(--color-primary) / 0.28);
|
|
164
|
+
--shadow-success: 0 8px 24px -6px hsl(var(--color-success) / 0.28);
|
|
165
|
+
--shadow-error: 0 8px 24px -6px hsl(var(--color-error) / 0.28);
|
|
166
|
+
|
|
167
|
+
// -----------------------------------------------------------------------
|
|
168
|
+
// Transitions — durations
|
|
169
|
+
// -----------------------------------------------------------------------
|
|
170
|
+
--transition-base: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
171
|
+
--transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
172
|
+
--transition-slow: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
173
|
+
|
|
174
|
+
// -----------------------------------------------------------------------
|
|
175
|
+
// Easings — curves only (no duration)
|
|
176
|
+
// -----------------------------------------------------------------------
|
|
177
|
+
// Public API surface — full scale exposed; internal usage may skip levels.
|
|
178
|
+
--easing-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
179
|
+
--easing-decelerate: cubic-bezier(0, 0, 0.2, 1);
|
|
180
|
+
--easing-accelerate: cubic-bezier(0.4, 0, 1, 1);
|
|
181
|
+
--easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
182
|
+
|
|
183
|
+
// -----------------------------------------------------------------------
|
|
184
|
+
// Typography
|
|
185
|
+
// -----------------------------------------------------------------------
|
|
186
|
+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
187
|
+
--font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace;
|
|
188
|
+
|
|
189
|
+
--text-xs: 0.75rem; // 12px
|
|
190
|
+
--text-sm: 0.875rem; // 14px
|
|
191
|
+
--text-base: 1rem; // 16px
|
|
192
|
+
--text-lg: 1.125rem; // 18px
|
|
193
|
+
--text-xl: 1.25rem; // 20px
|
|
194
|
+
--text-2xl: 1.5rem; // 24px
|
|
195
|
+
|
|
196
|
+
// -----------------------------------------------------------------------
|
|
197
|
+
// Typography — semantic role tokens (v1.1)
|
|
198
|
+
// -----------------------------------------------------------------------
|
|
199
|
+
// Public API surface — full scale exposed; internal usage may skip levels.
|
|
200
|
+
--text-display-lg: 3.75rem; --lh-display-lg: 1.1;
|
|
201
|
+
--text-display-md: 3rem; --lh-display-md: 1.1;
|
|
202
|
+
--text-display-sm: 2.25rem; --lh-display-sm: 1.15;
|
|
203
|
+
|
|
204
|
+
--text-heading-lg: 1.875rem; --lh-heading-lg: 1.2;
|
|
205
|
+
--text-heading-md: 1.5rem; --lh-heading-md: 1.25;
|
|
206
|
+
--text-heading-sm: 1.25rem; --lh-heading-sm: 1.3;
|
|
207
|
+
|
|
208
|
+
--text-title-md: 1.125rem; --lh-title-md: 1.4;
|
|
209
|
+
--text-title-sm: 1rem; --lh-title-sm: 1.4;
|
|
210
|
+
|
|
211
|
+
--text-body-lg: 1.125rem; --lh-body-lg: 1.6;
|
|
212
|
+
--text-body-md: 1rem; --lh-body-md: 1.6;
|
|
213
|
+
--text-body-sm: 0.875rem; --lh-body-sm: 1.5;
|
|
214
|
+
|
|
215
|
+
--text-label-md: 0.875rem; --lh-label-md: 1.4;
|
|
216
|
+
--text-label-sm: 0.75rem; --lh-label-sm: 1.4;
|
|
217
|
+
|
|
218
|
+
--text-caption: 0.75rem; --lh-caption: 1.4;
|
|
219
|
+
|
|
220
|
+
// -----------------------------------------------------------------------
|
|
221
|
+
// Letter spacing
|
|
222
|
+
// -----------------------------------------------------------------------
|
|
223
|
+
--tracking-tight: -0.025em;
|
|
224
|
+
--tracking-normal: 0;
|
|
225
|
+
--tracking-wide: 0.025em;
|
|
226
|
+
|
|
227
|
+
--font-normal: 400;
|
|
228
|
+
--font-medium: 500;
|
|
229
|
+
--font-semibold: 600;
|
|
230
|
+
--font-bold: 700;
|
|
231
|
+
|
|
232
|
+
// -----------------------------------------------------------------------
|
|
233
|
+
// Z-Index Scale
|
|
234
|
+
// -----------------------------------------------------------------------
|
|
235
|
+
--z-sticky: 10;
|
|
236
|
+
--z-dropdown: 20;
|
|
237
|
+
--z-overlay: 30;
|
|
238
|
+
--z-modal: 40;
|
|
239
|
+
--z-toast: 50;
|
|
240
|
+
|
|
241
|
+
// -----------------------------------------------------------------------
|
|
242
|
+
// App shell — intrinsic dimensions (not spacing rhythm)
|
|
243
|
+
// -----------------------------------------------------------------------
|
|
244
|
+
--app-header-height: 3.5rem;
|
|
245
|
+
--app-sidebar-width: 16rem;
|
|
246
|
+
--app-scrim-bg: hsl(var(--color-neutral-900) / 0.4);
|
|
247
|
+
|
|
248
|
+
// -----------------------------------------------------------------------
|
|
249
|
+
// Logical tokens — the public contract mixins read
|
|
250
|
+
// -----------------------------------------------------------------------
|
|
251
|
+
// Rule: mixin bodies reference ONLY these tokens (and --text-*/--lh-*/
|
|
252
|
+
// --radius-*/--shadow-*/--transition-*/--easing-* role scales). Back-end
|
|
253
|
+
// scales (--size-*, --color-neutral-*) are re-bound here and in context
|
|
254
|
+
// scopes (density, theme, region overrides) — never read directly
|
|
255
|
+
// inside a component mixin.
|
|
256
|
+
//
|
|
257
|
+
// See .claude/plans/refactor-logical-tokens-architecture.md for the
|
|
258
|
+
// full contract.
|
|
259
|
+
// -----------------------------------------------------------------------
|
|
260
|
+
|
|
261
|
+
// -- Structure & rhythm -----------------------------------------------
|
|
262
|
+
--padding-x: var(--size-sm-up);
|
|
263
|
+
--padding-y: var(--size-sm);
|
|
264
|
+
--gap: var(--size-sm);
|
|
265
|
+
--radius: var(--radius-md);
|
|
266
|
+
|
|
267
|
+
// -----------------------------------------------------------------------
|
|
268
|
+
// Value vocabulary — what bg/fg/border/shadow values exist
|
|
269
|
+
// -----------------------------------------------------------------------
|
|
270
|
+
// Mixins read primitives (--color-bg, --color-fg, --color-border,
|
|
271
|
+
// --shadow). Vocabulary provides the value choices. Components rebind
|
|
272
|
+
// the primitive on their own scope to pick a different vocabulary
|
|
273
|
+
// value. Themes override vocabulary at theme :root.
|
|
274
|
+
// -----------------------------------------------------------------------
|
|
275
|
+
|
|
276
|
+
--bg-base: hsl(var(--color-white));
|
|
277
|
+
--bg-elevated: var(--bg-base);
|
|
278
|
+
--bg-sunken: hsl(var(--color-neutral-100));
|
|
279
|
+
--bg-recessed: hsl(var(--color-neutral-50));
|
|
280
|
+
|
|
281
|
+
--fg-default: hsl(var(--color-neutral-900));
|
|
282
|
+
--fg-muted: hsl(var(--color-neutral-500));
|
|
283
|
+
--fg-subtle: hsl(var(--color-neutral-400));
|
|
284
|
+
|
|
285
|
+
--border-subtle: hsl(var(--color-neutral-200));
|
|
286
|
+
--border-strong: hsl(var(--color-neutral-300));
|
|
287
|
+
--border-strong-hover: hsl(var(--color-neutral-400));
|
|
288
|
+
|
|
289
|
+
--shadow-resting: var(--shadow-sm);
|
|
290
|
+
--shadow-floating: var(--shadow-md);
|
|
291
|
+
--shadow-overlay: var(--shadow-xl);
|
|
292
|
+
|
|
293
|
+
// -- Surface colors — primitives -------------------------------------
|
|
294
|
+
// Mixins read these four primitives. Vocabulary provides the value
|
|
295
|
+
// choices (--bg-*, --fg-*, --border-*, --shadow-*). Components rebind
|
|
296
|
+
// a primitive on their own scope to pick a different vocabulary entry.
|
|
297
|
+
--color-bg: var(--bg-base);
|
|
298
|
+
--color-fg: var(--fg-default);
|
|
299
|
+
--color-border: var(--border-subtle);
|
|
300
|
+
--shadow: var(--shadow-resting);
|
|
301
|
+
--color-scrim: hsl(var(--color-neutral-900) / 0.5);
|
|
302
|
+
|
|
303
|
+
// -- Accent -----------------------------------------------------------
|
|
304
|
+
--color-accent: hsl(var(--color-primary));
|
|
305
|
+
--color-accent-fg: hsl(var(--color-white));
|
|
306
|
+
--color-accent-tint: hsl(var(--color-primary-lighter));
|
|
307
|
+
--color-accent-tint-strong: hsl(var(--color-primary-light));
|
|
308
|
+
|
|
309
|
+
// Translucent accent surface — companions for themes that opt in to a
|
|
310
|
+
// non-solid accent button. NO defaults — `@mixin btn` reads these via
|
|
311
|
+
// fallback to `--color-accent` / `--color-accent-fg`, so the default
|
|
312
|
+
// theme stays solid + white.
|
|
313
|
+
//
|
|
314
|
+
// IMPORTANT — declare at theme :root ONLY when the value is a literal
|
|
315
|
+
// (no nested var(--color-primary)). If a theme needs the translucent
|
|
316
|
+
// fill computed FROM --color-primary, the rebind must happen at
|
|
317
|
+
// consumer scope (e.g. `[data-theme="..."] button[type="submit"], .btn
|
|
318
|
+
// { --btn-bg: ...; }`) so the nested var() resolves at the button —
|
|
319
|
+
// otherwise --color-primary freezes at theme :root and the
|
|
320
|
+
// .success/.error/.warning/.info status cascade breaks. Glass uses
|
|
321
|
+
// the consumer-scope pattern; see scss/config/_theme.scss.
|
|
322
|
+
// --color-accent-bg
|
|
323
|
+
// --color-accent-bg-hover
|
|
324
|
+
// --color-accent-bg-fg
|
|
325
|
+
|
|
326
|
+
// Nav surface — companions for themes that opt in to a bordered/inset
|
|
327
|
+
// nav appearance (e.g. Glass). NO defaults — `@mixin nav` reads these
|
|
328
|
+
// via fallback to no-op values (transparent border, zero bleed), so
|
|
329
|
+
// the default theme renders unchanged. Themes rebind at theme :root.
|
|
330
|
+
// --nav-link-border-color
|
|
331
|
+
// --nav-link-border-color-hover
|
|
332
|
+
// --nav-link-border-color-active
|
|
333
|
+
// --nav-list-bleed
|
|
334
|
+
|
|
335
|
+
// -- Button surface (neutral default) --------------------------------
|
|
336
|
+
// Read by @mixin button-base across idle + hover + active. The
|
|
337
|
+
// neutral default wires here. Accent variants (submit + @mixin btn)
|
|
338
|
+
// REBIND --btn-* on the consumer element (not at :root) — this
|
|
339
|
+
// preserves the .success/.error/.warning/.info semantic-color
|
|
340
|
+
// cascade because var() resolves at the declaration site. A
|
|
341
|
+
// companion --btn-accent-* surface AT :ROOT would freeze
|
|
342
|
+
// --color-accent at :root and break that cascade; the fix is
|
|
343
|
+
// consumer-scoped rebinding, not a parallel :root surface. See
|
|
344
|
+
// scss/config/mixins/_btn.scss header for the full rationale.
|
|
345
|
+
--btn-bg: var(--color-bg);
|
|
346
|
+
--btn-fg: var(--color-fg);
|
|
347
|
+
--btn-border: var(--border-strong);
|
|
348
|
+
--btn-bg-hover: var(--bg-sunken);
|
|
349
|
+
--btn-fg-hover: var(--color-fg);
|
|
350
|
+
--btn-border-hover: var(--border-strong-hover);
|
|
351
|
+
|
|
352
|
+
// Button padding tokens
|
|
353
|
+
--btn-padding-x: var(--size-md);
|
|
354
|
+
--btn-padding-y: var(--size-sm);
|
|
355
|
+
|
|
356
|
+
// -- Typography ------------------------------------------------------
|
|
357
|
+
--font-size: var(--text-body-md);
|
|
358
|
+
--line-height: var(--lh-body-md);
|
|
359
|
+
|
|
360
|
+
// -- Motion & depth --------------------------------------------------
|
|
361
|
+
--transition: var(--transition-base);
|
|
362
|
+
|
|
363
|
+
// -- Per-side borders (SOFT — no default) ----------------------------
|
|
364
|
+
// --border-block-start, --border-block-end,
|
|
365
|
+
// --border-inline-start, --border-inline-end
|
|
366
|
+
//
|
|
367
|
+
// Read by structural mixins (card, section-card, floating-panel,
|
|
368
|
+
// stat-card, app-header, app-footer, accordion items, table cells,
|
|
369
|
+
// tab-nav, sidebar edges, page-header, etc.) with a per-mixin
|
|
370
|
+
// fallback. NOT defined here — that is intentional. A scope that
|
|
371
|
+
// re-binds e.g. `--border-block-start: none` flattens the top edge
|
|
372
|
+
// of the matched element so siblings can join with a shared rule.
|
|
373
|
+
//
|
|
374
|
+
// Joining example:
|
|
375
|
+
// .joined-stack > * + * { --border-block-start: none; }
|
|
376
|
+
|
|
377
|
+
// -- Margin (SOFT — no default) --------------------------------
|
|
378
|
+
// --margin-block, --margin-inline
|
|
379
|
+
//
|
|
380
|
+
// Read by structural rhythm rules (label-to-input gap, section
|
|
381
|
+
// margin, header→body separation, sibling stacking,
|
|
382
|
+
// element-pushing horizontal offsets) with a per-mixin rebind.
|
|
383
|
+
// NOT defined here — the value varies too widely across
|
|
384
|
+
// consumers for a single :root default to be useful. Each
|
|
385
|
+
// consumer rebinds locally:
|
|
386
|
+
//
|
|
387
|
+
// @mixin section {
|
|
388
|
+
// --margin-block: var(--size-xl);
|
|
389
|
+
// margin-bottom: var(--margin-block);
|
|
390
|
+
// }
|
|
391
|
+
//
|
|
392
|
+
// Density-compact reacts automatically: density-compact rebinds
|
|
393
|
+
// the underlying --size-* scale, and the consumer's
|
|
394
|
+
// `--margin-block: var(--size-md)` re-resolves at the consumer
|
|
395
|
+
// element under the compact scope.
|
|
396
|
+
//
|
|
397
|
+
// --margin-inline is the horizontal companion. Used for
|
|
398
|
+
// element-pushing structural offsets (icon→text gap inside a
|
|
399
|
+
// row, sibling element offsets). NOT for flex/grid sibling
|
|
400
|
+
// spacing — that is --gap.
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
// Mobile rhythm — logical tokens tighten at ≤ md viewport.
|
|
405
|
+
// Not the same as `.density-compact` (that's a user opt-in).
|
|
406
|
+
// This is viewport-driven structural compression: content dominates chrome
|
|
407
|
+
// at narrow widths. Components reading --padding-x/--padding-y/--gap
|
|
408
|
+
// react via the cascade.
|
|
409
|
+
//
|
|
410
|
+
// Interaction with .density-compact: stacks. Compact user + mobile viewport =
|
|
411
|
+
// both apply; the underlying --size-* scale is already tighter in
|
|
412
|
+
// .density-compact so logical tokens resolve to the tightest value.
|
|
413
|
+
// ---------------------------------------------------------------------------
|
|
414
|
+
@include mq-down(md) {
|
|
415
|
+
:root {
|
|
416
|
+
--padding-y: var(--size-xs); // 12px → 4px
|
|
417
|
+
--gap: var(--size-xs-up); // 8px → 6px
|
|
418
|
+
}
|
|
419
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Accordion — styled list with chevron rotation on open
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// [data-ln-accordion] { @include accordion; } // library default
|
|
5
|
+
// #my-list { @include accordion; } // custom selector
|
|
6
|
+
//
|
|
7
|
+
// Expected DOM (see docs/css/mixins.md §accordion):
|
|
8
|
+
// <ul data-ln-accordion>
|
|
9
|
+
// <li>
|
|
10
|
+
// <header data-ln-toggle-for="p1">Title</header>
|
|
11
|
+
// <main id="p1" data-ln-toggle class="collapsible">
|
|
12
|
+
// <div class="collapsible-body"><p>...</p></div>
|
|
13
|
+
// </main>
|
|
14
|
+
// </li>
|
|
15
|
+
// </ul>
|
|
16
|
+
|
|
17
|
+
@use 'spacing' as *;
|
|
18
|
+
@use 'display' as *;
|
|
19
|
+
@use 'borders' as *;
|
|
20
|
+
@use 'interaction' as *;
|
|
21
|
+
|
|
22
|
+
@mixin accordion {
|
|
23
|
+
@include border;
|
|
24
|
+
--radius: var(--radius-lg);
|
|
25
|
+
border-radius: var(--radius);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
|
|
28
|
+
> li {
|
|
29
|
+
border-block-end: var(--border-block-end, var(--border-width) solid var(--color-border));
|
|
30
|
+
|
|
31
|
+
&:last-child { border-block-end: none; }
|
|
32
|
+
|
|
33
|
+
// Trigger
|
|
34
|
+
> [data-ln-toggle-for] {
|
|
35
|
+
@include flex;
|
|
36
|
+
@include justify-between;
|
|
37
|
+
@include items-center;
|
|
38
|
+
--padding-y: var(--size-md);
|
|
39
|
+
--padding-x: var(--size-md);
|
|
40
|
+
padding: var(--padding-y) var(--padding-x);
|
|
41
|
+
@include cursor-pointer;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Content body padding — on children, not the overflow:hidden wrapper
|
|
45
|
+
.collapsible-body > * {
|
|
46
|
+
--padding-y: var(--size-sm-up);
|
|
47
|
+
--padding-x: var(--size-md);
|
|
48
|
+
padding: var(--padding-y) var(--padding-x);
|
|
49
|
+
margin: 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|