fractalstyler2 0.4.0 → 0.7.0

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 (87) hide show
  1. package/README.md +114 -95
  2. package/dist/cli.js +105 -25
  3. package/dist/components/Accordion.svelte +44 -0
  4. package/dist/components/Accordion.svelte.d.ts +23 -0
  5. package/dist/components/AccordionItem.svelte +44 -0
  6. package/dist/components/AccordionItem.svelte.d.ts +21 -0
  7. package/dist/components/AppShell.svelte +86 -0
  8. package/dist/components/AppShell.svelte.d.ts +39 -0
  9. package/dist/components/ColorPicker.svelte +38 -0
  10. package/dist/components/ColorPicker.svelte.d.ts +6 -0
  11. package/dist/components/Hero.svelte +14 -0
  12. package/dist/components/Hero.svelte.d.ts +9 -0
  13. package/dist/components/LayoutPicker.svelte +34 -0
  14. package/dist/components/LayoutPicker.svelte.d.ts +6 -0
  15. package/dist/components/MotionPicker.svelte +34 -0
  16. package/dist/components/MotionPicker.svelte.d.ts +6 -0
  17. package/dist/components/PageShell.svelte +14 -0
  18. package/dist/components/PageShell.svelte.d.ts +9 -0
  19. package/dist/components/PageSplit.svelte +26 -0
  20. package/dist/components/PageSplit.svelte.d.ts +18 -0
  21. package/dist/components/ShapePicker.svelte +37 -0
  22. package/dist/components/ShapePicker.svelte.d.ts +6 -0
  23. package/dist/css/fractalstyler.css +10643 -0
  24. package/dist/css/fractalstyler.min.css +2 -0
  25. package/dist/index.d.ts +18 -6
  26. package/dist/index.js +30 -12
  27. package/dist/mcp/schemas/compile_fractals.json +3 -3
  28. package/dist/mcp/schemas/css_to_fractals.json +1 -1
  29. package/dist/mcp/schemas/generate_component.json +2 -2
  30. package/dist/mcp/schemas/instructions.md +41 -14
  31. package/dist/mcp/schemas/list_fractals.json +9 -7
  32. package/dist/mcp/schemas/validate_recipe.json +2 -2
  33. package/dist/mcp/server.d.ts +1 -1
  34. package/dist/mcp/server.js +334 -237
  35. package/dist/presets.core.d.ts +42 -0
  36. package/dist/presets.core.js +190 -0
  37. package/dist/presets.svelte.d.ts +6 -0
  38. package/dist/presets.svelte.js +21 -0
  39. package/dist/styles/_00_presets.sass +111 -0
  40. package/dist/styles/_00_themes.sass +1061 -0
  41. package/dist/styles/_00_tokens.sass +57 -17
  42. package/dist/styles/_01_config.sass +77 -70
  43. package/dist/styles/_02_dimensions.sass +174 -0
  44. package/dist/styles/_03_containers.sass +105 -0
  45. package/dist/styles/_04_layouts.sass +100 -0
  46. package/dist/styles/_05_shells.sass +374 -0
  47. package/dist/styles/_06_visuals.sass +236 -0
  48. package/dist/styles/_07_interactions.sass +112 -0
  49. package/dist/styles/_08_own.sass +4 -0
  50. package/dist/styles/canonical-markups.md +160 -0
  51. package/dist/styles/index.sass +11 -18
  52. package/dist/themes.d.ts +7 -0
  53. package/dist/themes.js +45 -0
  54. package/dist/version.d.ts +1 -0
  55. package/dist/version.js +2 -0
  56. package/package.json +26 -15
  57. package/plugin.json +11 -10
  58. package/registry.json +2002 -0
  59. package/skills/fractal-styler/SKILL.md +137 -50
  60. package/skills/fractal-styler/references/fractals.md +416 -28
  61. package/skills/fractal-styler/references/tokens.md +110 -36
  62. package/dist/styles/_02_fonts.sass +0 -13
  63. package/dist/styles/_03_responsive.sass +0 -31
  64. package/dist/styles/_04_atoms.sass +0 -155
  65. package/dist/styles/_05_molecules.sass +0 -97
  66. package/dist/styles/_06_recipes.sass +0 -189
  67. package/dist/styles/_07_base.sass +0 -44
  68. package/dist/styles/_08_blocks.sass +0 -433
  69. package/dist/styles/_09_utilities.sass +0 -208
  70. package/dist/styles/_10_layouts.sass +0 -373
  71. package/dist/styles/_11_own.sass +0 -21
  72. package/dist/styles/_fractals.sass +0 -14
  73. package/skills/style-migration/SKILL.md +0 -45
  74. package/templates/_00_tokens.sass +0 -136
  75. package/templates/_01_config.sass +0 -66
  76. package/templates/_02_fonts.sass +0 -13
  77. package/templates/_03_responsive.sass +0 -31
  78. package/templates/_04_atoms.sass +0 -155
  79. package/templates/_05_molecules.sass +0 -97
  80. package/templates/_06_recipes.sass +0 -189
  81. package/templates/_07_base.sass +0 -44
  82. package/templates/_08_blocks.sass +0 -433
  83. package/templates/_09_utilities.sass +0 -207
  84. package/templates/_10_layouts.sass +0 -373
  85. package/templates/_11_own.sass +0 -21
  86. package/templates/_fractals.sass +0 -14
  87. package/templates/index.sass +0 -18
@@ -0,0 +1,374 @@
1
+ // ============================================================================
2
+ // shells — L4. Canonical markups are canon: every class here implements the
3
+ // markup registered in the registry. Overlay mechanics, the docs-frame roles
4
+ // and the mobile TOC disclosure are authored to the registered behaviors.
5
+ // Motion reads the motion tokens — presets reach everything.
6
+ // ============================================================================
7
+
8
+ @use 'sass:string'
9
+ @use 'sass:list'
10
+ @use 'sass:map'
11
+ @use '01_config' as *
12
+
13
+ $md: map.get($breakpoints, md)
14
+ $lg: map.get($breakpoints, lg)
15
+ $xl: map.get($breakpoints, xl)
16
+
17
+ // --- The app-shell canon ------------------------------------------------------
18
+ .app-shell
19
+ display: flex
20
+ flex-direction: column
21
+ position: relative
22
+ min-height: 100vh
23
+
24
+ .app-header
25
+ display: flex
26
+ flex-direction: row
27
+ align-items: center
28
+ position: sticky
29
+ top: 0
30
+ z-index: var(--z-sticky)
31
+ height: var(--header-height)
32
+ padding-inline: calc(var(--space-sm) * var(--pad-scale, 1))
33
+ background: color-mix(in srgb, var(--bg-surface) 88%, transparent)
34
+ backdrop-filter: blur(12px)
35
+ -webkit-backdrop-filter: blur(12px)
36
+ border-bottom: 1px solid var(--border)
37
+
38
+ .app-main
39
+ flex: 1 1 0%
40
+ min-width: 0
41
+ min-height: calc(100vh - var(--header-height) - var(--footer-height))
42
+ display: flex
43
+ flex-direction: row
44
+
45
+ .main-section
46
+ flex: 1 1 0%
47
+ min-width: 0
48
+
49
+ // --- Role-bound rails (Amendment A1) -------------------------------------------
50
+ // Left = nav: visible ≥ lg; below, .open on .app-shell resurrects it as an
51
+ // off-canvas drawer (the header menu button toggles it). Right = TOC: visible
52
+ // ≥ xl; below, its content surfaces in .mobile-toc at the top of the page.
53
+ .sidebar-left,
54
+ .sidebar-right
55
+ display: none
56
+ flex-shrink: 0
57
+ position: sticky
58
+ top: var(--header-height)
59
+ height: calc(100vh - var(--header-height) - var(--footer-height))
60
+ overflow-y: auto
61
+ padding: calc(var(--space-sm) * var(--pad-scale, 1))
62
+
63
+ .sidebar-left
64
+ width: var(--sidebar-width)
65
+
66
+ .sidebar-right
67
+ width: var(--toc-width)
68
+
69
+ @media (max-width: #{$lg - 1})
70
+ .app-shell.open .sidebar-left
71
+ display: block
72
+ position: fixed
73
+ left: 0
74
+ z-index: var(--z-modal)
75
+ width: min(85vw, var(--sidebar-width))
76
+ height: calc(100vh - var(--header-height) - var(--footer-height))
77
+ background: var(--bg)
78
+ border-right: 1px solid var(--border)
79
+
80
+ @media #{string.unquote('(min-width: #{$lg})')}
81
+ .sidebar-left
82
+ display: block
83
+ border-right: 1px solid var(--border)
84
+
85
+ @media #{string.unquote('(min-width: #{$xl})')}
86
+ .sidebar-right
87
+ display: block
88
+ border-left: 1px solid var(--border)
89
+
90
+ .content-shell
91
+ max-width: var(--measure)
92
+ margin-inline: auto
93
+
94
+ .app-footer
95
+ display: flex
96
+ flex-direction: row
97
+ align-items: center
98
+ padding-inline: calc(var(--space-sm) * var(--pad-scale, 1))
99
+ min-height: var(--footer-height)
100
+ border-top: 1px solid var(--border)
101
+
102
+ // Page-top TOC dropdown — where the TOC lives below xl: <details class="mobile-toc">.
103
+ .mobile-toc
104
+ padding: calc(var(--space-xs) * var(--pad-scale, 1))
105
+ border: 1px solid var(--border)
106
+ border-radius: var(--radius-md)
107
+ background: var(--bg-surface)
108
+ summary
109
+ display: flex
110
+ flex-direction: row
111
+ align-items: center
112
+ justify-content: space-between
113
+ font-weight: 500
114
+ font-size: var(--text-sm)
115
+ color: var(--text-primary)
116
+ cursor: pointer
117
+ user-select: none
118
+ list-style: none
119
+ &::-webkit-details-marker
120
+ display: none
121
+ &[open]
122
+ background: var(--bg-raised)
123
+ summary
124
+ padding-bottom: calc(var(--space-2xs) * var(--pad-scale, 1))
125
+ margin-bottom: calc(var(--space-xs) * var(--gap-scale, 1))
126
+ border-bottom: 1px solid var(--border)
127
+ @media #{string.unquote('(min-width: #{$xl})')}
128
+ display: none
129
+
130
+ // --- Canonical shell roles — the tree (left rail) and the TOC (right rail) -----
131
+ .navtree
132
+ display: flex
133
+ flex-direction: column
134
+ gap: calc(var(--space-sm) * var(--gap-scale, 1))
135
+
136
+ // Flat group label — for groups that don't collapse (collapsible groups ride
137
+ // the accordion family: trigger carries the title, content carries the links).
138
+ .navtree-title
139
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
140
+ font-size: var(--text-xs)
141
+ font-weight: 600
142
+ letter-spacing: 0.05em
143
+ text-transform: uppercase
144
+ color: var(--text-muted)
145
+
146
+ .navtree-link
147
+ display: flex
148
+ align-items: center
149
+ padding-block: calc(var(--space-3xs) * var(--pad-scale, 1))
150
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
151
+ font-size: var(--text-sm)
152
+ color: var(--text-secondary)
153
+ text-decoration: none
154
+ border-radius: var(--radius-sm)
155
+ transition: background var(--motion-fast) ease, color var(--motion-fast) ease
156
+ &:hover
157
+ background: var(--state-hover-subtle)
158
+ color: var(--text-primary)
159
+ &.active
160
+ background: var(--state-selected)
161
+ color: var(--text-primary)
162
+
163
+ .navtree-sub
164
+ display: flex
165
+ flex-direction: column
166
+ gap: calc(var(--space-3xs) * var(--gap-scale, 1))
167
+ padding-left: calc(var(--space-sm) * var(--pad-scale, 1))
168
+
169
+ .toc
170
+ display: flex
171
+ flex-direction: column
172
+ gap: calc(var(--space-xs) * var(--gap-scale, 1))
173
+
174
+ .toc-title
175
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
176
+ font-size: var(--text-xs)
177
+ font-weight: 600
178
+ letter-spacing: 0.05em
179
+ text-transform: uppercase
180
+ color: var(--text-muted)
181
+
182
+ .toc-list
183
+ display: flex
184
+ flex-direction: column
185
+ gap: calc(var(--space-3xs) * var(--gap-scale, 1))
186
+ margin: 0
187
+ padding: 0
188
+ list-style: none
189
+
190
+ .toc-link
191
+ display: block
192
+ font-size: var(--text-sm)
193
+ color: var(--text-secondary)
194
+ text-decoration: none
195
+ transition: color var(--motion-fast) ease
196
+ &:hover
197
+ color: var(--text-primary)
198
+ &.active
199
+ color: var(--theme-color)
200
+ font-weight: 500
201
+
202
+ .toc-footer
203
+ margin-top: calc(var(--space-xs) * var(--gap-scale, 1))
204
+ padding-top: calc(var(--space-xs) * var(--pad-scale, 1))
205
+ border-top: 1px solid var(--border)
206
+ font-size: var(--text-xs)
207
+ color: var(--text-muted)
208
+
209
+ // --- Tabs — current = .active; triggers carry native aria-selected -------------
210
+ .tab-list
211
+ display: flex
212
+ flex-direction: row
213
+ gap: calc(var(--space-2xs) * var(--gap-scale, 1))
214
+ border-bottom: 1px solid var(--border)
215
+
216
+ .tab-trigger
217
+ padding-block: calc(var(--space-2xs) * var(--pad-scale, 1))
218
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
219
+ font-size: var(--text-sm)
220
+ color: var(--text-secondary)
221
+ background: transparent
222
+ border: 0
223
+ border-bottom: 2px solid transparent
224
+ margin-bottom: -1px
225
+ cursor: pointer
226
+ text-decoration: none
227
+ transition: color var(--motion-fast) ease, border-color var(--motion-fast) ease
228
+ &:hover
229
+ color: var(--text-primary)
230
+ &.active
231
+ color: var(--text-primary)
232
+ border-bottom-color: var(--theme-color)
233
+
234
+ // --- Page frames — padding ownership moves with full-bleed chrome ------------
235
+ .page-shell
236
+ padding-inline: var(--page-gutter)
237
+ padding-block: calc(var(--space-md) * var(--pad-scale, 1))
238
+
239
+ .page-split
240
+ display: grid
241
+ grid-template-columns: minmax(0, 1fr)
242
+ .page-main
243
+ min-width: 0
244
+ padding: var(--page-gutter)
245
+ .page-sidebar
246
+ display: none
247
+ @media #{string.unquote('(min-width: #{$md})')}
248
+ grid-template-columns: var(--sidebar-width) minmax(0, 1fr)
249
+ .page-sidebar
250
+ display: block
251
+ position: sticky
252
+ top: var(--header-height)
253
+ height: calc(100vh - var(--header-height) - var(--footer-height))
254
+ overflow-y: auto
255
+ border-right: 1px solid var(--border)
256
+
257
+ // --- Overlays — shown via .open; triggers carry native aria ------------------
258
+ .drawer
259
+ position: fixed
260
+ top: var(--header-height)
261
+ left: 0
262
+ z-index: var(--z-modal)
263
+ width: min(85vw, 320px)
264
+ height: calc(100dvh - var(--header-height))
265
+ padding: calc(var(--space-sm) * var(--pad-scale, 1))
266
+ overflow-y: auto
267
+ background: var(--bg)
268
+ border-right: 1px solid var(--border)
269
+ transform: translateX(-105%)
270
+ visibility: hidden
271
+ transition: transform var(--motion-base) var(--ease-out), visibility var(--motion-base)
272
+ &.open
273
+ transform: translateX(0)
274
+ visibility: visible
275
+
276
+ .dialog
277
+ position: fixed
278
+ top: 50%
279
+ left: 50%
280
+ translate: 0 -4px
281
+ z-index: var(--z-modal)
282
+ max-width: min(92vw, 540px)
283
+ width: 100%
284
+ background: var(--bg-dialog)
285
+ border: 1px solid var(--border)
286
+ border-radius: var(--radius-lg)
287
+ box-shadow: var(--shadow-lg)
288
+ opacity: 0
289
+ visibility: hidden
290
+ pointer-events: none
291
+ transition: opacity var(--motion-base) var(--ease-out), visibility var(--motion-base), translate var(--motion-base) var(--ease-out)
292
+ &.open,
293
+ &[open]
294
+ opacity: 1
295
+ visibility: visible
296
+ pointer-events: auto
297
+ translate: 0 0
298
+ &::backdrop
299
+ background: rgba(0, 0, 0, 0.5)
300
+
301
+ .popover
302
+ position: absolute
303
+ top: calc(100% + 6px)
304
+ left: 0
305
+ z-index: var(--z-raised)
306
+ min-width: 200px
307
+ background: var(--bg-popover)
308
+ border: 1px solid var(--border)
309
+ border-radius: var(--radius-md)
310
+ box-shadow: var(--shadow-md)
311
+ translate: 0 -4px
312
+ opacity: 0
313
+ visibility: hidden
314
+ pointer-events: none
315
+ transition: opacity var(--motion-fast) var(--ease-out), visibility var(--motion-fast), translate var(--motion-fast) var(--ease-out)
316
+ &.open
317
+ opacity: 1
318
+ visibility: visible
319
+ pointer-events: auto
320
+ translate: 0 0
321
+
322
+ .accordion
323
+ display: flex
324
+ flex-direction: column
325
+ gap: calc(var(--space-2xs) * var(--gap-scale, 1))
326
+
327
+ .accordion-item
328
+ border: 1px solid var(--border)
329
+ border-radius: var(--radius-md)
330
+ background: var(--bg-surface)
331
+ .accordion-content
332
+ display: grid
333
+ grid-template-rows: 0fr
334
+ padding: 0
335
+ transition: grid-template-rows var(--motion-base) var(--ease-out)
336
+ // The panel is what collapses. It needs min-height: 0 so the grid row can
337
+ // size it, and overflow: hidden so the content clips while closed — which
338
+ // is why it carries a name rather than being reached at by position.
339
+ .accordion-panel
340
+ overflow: hidden
341
+ min-height: 0
342
+ &.open .accordion-content
343
+ grid-template-rows: 1fr
344
+ padding: calc(var(--space-xs) * var(--pad-scale, 1))
345
+
346
+ .accordion-trigger
347
+ display: flex
348
+ flex-direction: row
349
+ align-items: center
350
+ justify-content: space-between
351
+ width: 100%
352
+ min-height: var(--control-h-md)
353
+ padding: calc(var(--space-2xs) * var(--pad-scale, 1)) calc(var(--space-xs) * var(--pad-scale, 1))
354
+ font-weight: 500
355
+ font-size: var(--text-sm)
356
+ text-align: left
357
+ background: transparent
358
+ border: 0
359
+ cursor: pointer
360
+ user-select: none
361
+ &:hover
362
+ background: var(--bg-raised)
363
+ &:focus-visible
364
+ outline: 2px solid var(--ring)
365
+ outline-offset: -2px
366
+
367
+ // --- .hero — documented sugar: .box.ycenter + gap-lg + pad-y-xl ---------------
368
+ .hero
369
+ display: flex
370
+ flex-direction: column
371
+ align-items: center
372
+ justify-content: center
373
+ gap: calc(var(--space-lg) * var(--gap-scale, 1))
374
+ padding-block: calc(var(--space-xl) * var(--pad-scale, 1))
@@ -0,0 +1,236 @@
1
+ // ============================================================================
2
+ // dress — L5. Skin and compositions. Emission order within this file follows
3
+ // Contract 5: bare dress before compositions. Components own their own hover
4
+ // states; there is no standalone .hover / .transition (registry ruling).
5
+ // All compositions read the --radius-* channels so shape presets reach them.
6
+ // ============================================================================
7
+
8
+ @use 'sass:string'
9
+ @use 'sass:list'
10
+ @use 'sass:map'
11
+ @use '01_config' as *
12
+
13
+ // --- Bare backgrounds (one declaration each) ----------------------------------
14
+ .bg
15
+ background: var(--bg)
16
+ .surface
17
+ background: var(--bg-surface)
18
+ .raised
19
+ background: var(--bg-raised)
20
+ .panel
21
+ background: var(--bg-panel)
22
+ .footer
23
+ background: var(--bg-footer)
24
+ .canvas
25
+ background: var(--bg-canvas)
26
+ .terminal
27
+ background: var(--bg-terminal)
28
+
29
+ // --- Ink ----------------------------------------------------------------------
30
+ .text-primary
31
+ color: var(--text-primary)
32
+ .text-secondary
33
+ color: var(--text-secondary)
34
+ .text-muted
35
+ color: var(--text-muted)
36
+ .text-inverse
37
+ color: var(--text-inverse)
38
+ .text-theme
39
+ color: var(--theme-color)
40
+ .text-success
41
+ color: var(--success)
42
+ .text-warning
43
+ color: var(--warning)
44
+ .text-danger
45
+ color: var(--danger)
46
+ .text-info
47
+ color: var(--info)
48
+
49
+ // Status fills, mirroring the status inks above. A dot or chip that carries the
50
+ // status as a background had no composable form before these, which made it a
51
+ // reason to open _08_own.sass.
52
+ .bg-success
53
+ background: var(--success)
54
+ .bg-warning
55
+ background: var(--warning)
56
+ .bg-danger
57
+ background: var(--danger)
58
+ .bg-info
59
+ background: var(--info)
60
+
61
+ // --- Lines (the partition-law set) ---------------------------------------------
62
+ .border
63
+ border: 1px solid var(--border)
64
+ .border-subtle
65
+ border: 1px solid var(--border-subtle)
66
+ .border-top
67
+ border-top: 1px solid var(--border)
68
+ .border-right
69
+ border-right: 1px solid var(--border)
70
+ .border-bottom
71
+ border-bottom: 1px solid var(--border)
72
+ .border-left
73
+ border-left: 1px solid var(--border)
74
+
75
+ // --- Typography -----------------------------------------------------------------
76
+ .text-xs
77
+ font-size: var(--text-xs)
78
+ .text-sm
79
+ font-size: var(--text-sm)
80
+ .text-md
81
+ font-size: var(--text-md)
82
+ .text-lg
83
+ font-size: var(--text-lg)
84
+ .text-xl
85
+ font-size: var(--text-xl)
86
+ .text-2xl
87
+ font-size: var(--text-2xl)
88
+ .text-3xl
89
+ font-size: var(--text-3xl)
90
+ .text-4xl
91
+ font-size: var(--text-4xl)
92
+
93
+ .weight-400
94
+ font-weight: 400
95
+ .weight-500
96
+ font-weight: 500
97
+ .weight-600
98
+ font-weight: 600
99
+ .weight-700
100
+ font-weight: 700
101
+
102
+ .mono
103
+ font-family: var(--font-mono)
104
+ .tt-u
105
+ text-transform: uppercase
106
+ .tt-c
107
+ text-transform: capitalize
108
+
109
+ .truncate
110
+ overflow: hidden
111
+ white-space: nowrap
112
+ text-overflow: ellipsis
113
+
114
+ .clamp-1
115
+ display: -webkit-box
116
+ -webkit-line-clamp: 1
117
+ -webkit-box-orient: vertical
118
+ overflow: hidden
119
+ .clamp-2
120
+ display: -webkit-box
121
+ -webkit-line-clamp: 2
122
+ -webkit-box-orient: vertical
123
+ overflow: hidden
124
+ .clamp-3
125
+ display: -webkit-box
126
+ -webkit-line-clamp: 3
127
+ -webkit-box-orient: vertical
128
+ overflow: hidden
129
+
130
+ .eyebrow
131
+ font-size: var(--text-sm)
132
+ text-transform: uppercase
133
+ letter-spacing: 0.06em
134
+ font-weight: 500
135
+ color: var(--text-muted)
136
+
137
+ // --- Compositions (plain classes over the vocabulary, yours to restyle) ----------
138
+ .card
139
+ display: flex
140
+ gap: calc(var(--space-sm) * var(--gap-scale, 1))
141
+ padding: calc(var(--space-md) * var(--pad-scale, 1))
142
+ background: var(--bg-surface)
143
+ border: 1px solid var(--border)
144
+ border-radius: var(--radius-md)
145
+
146
+ .field
147
+ display: flex
148
+ flex-direction: column
149
+ gap: calc(var(--space-3xs) * var(--gap-scale, 1))
150
+
151
+ .field-label
152
+ font-size: var(--text-xs)
153
+ font-weight: 500
154
+ color: var(--text-secondary)
155
+
156
+ .field-error
157
+ font-size: var(--text-xs)
158
+ color: var(--danger)
159
+
160
+ .avatar
161
+ width: 32px
162
+ height: 32px
163
+ flex-shrink: 0
164
+ border-radius: var(--radius-full)
165
+ overflow: hidden
166
+ &:is(img)
167
+ object-fit: cover
168
+ img
169
+ width: 100%
170
+ height: 100%
171
+ object-fit: cover
172
+
173
+ .divider
174
+ border: 0
175
+ border-top: 1px solid var(--border)
176
+ margin-block: calc(var(--space-sm) * var(--gap-scale, 1))
177
+
178
+ .kbd
179
+ display: inline-block
180
+ padding-inline: calc(var(--space-2xs) * var(--pad-scale, 1))
181
+ padding-block: 2px
182
+ font-family: var(--font-mono)
183
+ font-size: var(--text-xs)
184
+ line-height: 1.4
185
+ background: var(--bg-raised)
186
+ color: var(--text-primary)
187
+ border: 1px solid var(--border)
188
+ border-radius: var(--radius-sm)
189
+
190
+ .switch-track
191
+ display: inline-flex
192
+ align-items: center
193
+ width: 40px
194
+ height: 22px
195
+ padding: 2px
196
+ background: var(--bg-raised)
197
+ border: 1px solid var(--border)
198
+ border-radius: var(--radius-full)
199
+ cursor: pointer
200
+ transition: background var(--motion-fast) ease, border-color var(--motion-fast) ease
201
+
202
+ .switch-thumb
203
+ width: 16px
204
+ height: 16px
205
+ background: var(--text-inverse)
206
+ border-radius: var(--radius-full)
207
+ box-shadow: var(--shadow-sm)
208
+ transition: translate var(--motion-fast) ease
209
+
210
+ .switch-track[aria-checked='true'],
211
+ .switch-track.checked
212
+ background: var(--theme-color)
213
+ border-color: var(--theme-color)
214
+ .switch-thumb
215
+ translate: 18px 0
216
+
217
+ // --- Responsive visibility -----------------------------------------------------
218
+ .hide-mobile
219
+ @media #{string.unquote(map.get($responsive-modes, 'mob'))}
220
+ display: none
221
+
222
+ .hide-desktop
223
+ @media #{string.unquote(map.get($responsive-modes, 'desk'))}
224
+ display: none
225
+
226
+ .only-mobile
227
+ @media #{string.unquote(map.get($responsive-modes, 'desk'))}
228
+ display: none
229
+
230
+ // Shadows — token channels; per-mode values live in tokens.
231
+ .shadow-sm
232
+ box-shadow: var(--shadow-sm)
233
+ .shadow-md
234
+ box-shadow: var(--shadow-md)
235
+ .shadow-lg
236
+ box-shadow: var(--shadow-lg)
@@ -0,0 +1,112 @@
1
+ .badge
2
+ display: inline-flex
3
+ align-items: center
4
+ gap: calc(var(--space-3xs) * var(--gap-scale, 1))
5
+ padding-inline: calc(var(--space-2xs) * var(--pad-scale, 1))
6
+ padding-block: 2px
7
+ font-size: var(--text-xs)
8
+ font-weight: 500
9
+ background: var(--bg-raised)
10
+ color: var(--text-secondary)
11
+ border: 1px solid var(--border)
12
+ border-radius: var(--radius-sm)
13
+
14
+ .input
15
+ display: block
16
+ width: 100%
17
+ height: var(--control-h-md)
18
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
19
+ font-size: var(--text-sm)
20
+ line-height: 1.5
21
+ background: var(--bg-input)
22
+ color: var(--text-primary)
23
+ border: 1px solid var(--border)
24
+ border-radius: var(--radius-sm)
25
+ &:focus-visible
26
+ outline: none
27
+ border-color: var(--theme-color)
28
+ box-shadow: 0 0 0 2px var(--ring)
29
+
30
+ .select
31
+ display: block
32
+ width: 100%
33
+ height: var(--control-h-md)
34
+ padding-inline: calc(var(--space-xs) * var(--pad-scale, 1))
35
+ padding-right: 28px
36
+ font-size: var(--text-sm)
37
+ appearance: none
38
+ -webkit-appearance: none
39
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23697080' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E")
40
+ background-repeat: no-repeat
41
+ background-position: right 8px center
42
+ background-color: var(--bg-input)
43
+ color: var(--text-primary)
44
+ border: 1px solid var(--border)
45
+ border-radius: var(--radius-sm)
46
+ cursor: pointer
47
+ &:focus-visible
48
+ outline: none
49
+ border-color: var(--theme-color)
50
+ box-shadow: 0 0 0 2px var(--ring)
51
+
52
+ // --- The link family -------------------------------------------------------------
53
+ .link
54
+ color: var(--theme-color)
55
+ text-decoration: none
56
+ &:hover
57
+ text-decoration: underline
58
+
59
+ .link-plain
60
+ color: inherit
61
+ text-decoration: none
62
+
63
+ .link-parent
64
+ &:hover
65
+ .link,
66
+ .link-plain
67
+ color: var(--theme-color-alt)
68
+
69
+ // --- The button quartet (nested — never standalone) -----------------------------
70
+ .button
71
+ display: inline-flex
72
+ align-items: center
73
+ justify-content: center
74
+ height: var(--control-h-md)
75
+ padding-inline: calc(var(--space-sm) * var(--pad-scale, 1))
76
+ border: 1px solid transparent
77
+ border-radius: var(--radius-sm)
78
+ font-weight: 500
79
+ font-size: var(--text-sm)
80
+ text-decoration: none
81
+ cursor: pointer
82
+ user-select: none
83
+ transition: background var(--motion-fast) ease, border-color var(--motion-fast) ease, color var(--motion-fast) ease
84
+ &:focus-visible
85
+ outline: 2px solid var(--ring)
86
+ outline-offset: 1px
87
+ &:disabled
88
+ opacity: 0.5
89
+ cursor: not-allowed
90
+ pointer-events: none
91
+ &.primary
92
+ background: var(--theme-color)
93
+ color: var(--text-inverse)
94
+ &:hover
95
+ background: var(--theme-color-alt)
96
+ &.ghost
97
+ background: none
98
+ border: none
99
+ color: var(--text-primary)
100
+ &:hover
101
+ background: var(--bg-raised)
102
+ &.active
103
+ background: var(--state-selected)
104
+ border-color: var(--border)
105
+ color: var(--text-primary)
106
+ &.is-icon
107
+ padding: 0
108
+ background: 0
109
+ border: 0
110
+ color: var(--text-primary)
111
+ &:hover
112
+ color: var(--theme-color)
@@ -0,0 +1,4 @@
1
+ // =============================================================================
2
+ // 11_OWN — bespoke project-specific styles and micro-components.
3
+ // =============================================================================
4
+