klods-css 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # klods-css
2
+
3
+ The klods stylesheet. Drop it in any HTML page or Rails app.
4
+
5
+ ```html
6
+ <link rel="stylesheet" href="https://unpkg.com/klods-css/dist/klods.min.css" />
7
+ ```
8
+
9
+ Or via npm:
10
+
11
+ ```sh
12
+ npm install klods-css
13
+ ```
14
+
15
+ ```css
16
+ @import "klods-css";
17
+ ```
18
+
19
+ See the [docs site](../../apps/docs) for the full reference.
package/dist/klods.css ADDED
@@ -0,0 +1,530 @@
1
+ @layer klods.reset, klods.tokens, klods.themes, klods.layout, klods.components, klods.utilities;
2
+ @layer klods.reset {
3
+ *,
4
+ *::before,
5
+ *::after {
6
+ box-sizing: border-box;
7
+ }
8
+ html {
9
+ -webkit-text-size-adjust: 100%;
10
+ text-size-adjust: 100%;
11
+ }
12
+ body {
13
+ margin: 0;
14
+ min-height: 100dvh;
15
+ font-family: var(--klods-font-sans);
16
+ font-size: var(--klods-font-size-base);
17
+ line-height: var(--klods-line-height-base);
18
+ color: var(--klods-color-fg);
19
+ background: var(--klods-color-bg);
20
+ }
21
+ img,
22
+ picture,
23
+ svg,
24
+ video {
25
+ display: block;
26
+ max-width: 100%;
27
+ }
28
+ button,
29
+ input,
30
+ select,
31
+ textarea {
32
+ font: inherit;
33
+ color: inherit;
34
+ }
35
+ a {
36
+ color: var(--klods-color-link);
37
+ }
38
+ }
39
+ @layer klods.tokens {
40
+ :root {
41
+ --klods-color-bg: #ffffff;
42
+ --klods-color-fg: #1a1a1a;
43
+ --klods-color-muted: #6b7280;
44
+ --klods-color-surface: #f5f5f7;
45
+ --klods-color-surface-2: #ececef;
46
+ --klods-color-border: #e5e7eb;
47
+ --klods-color-accent: #5b5bd6;
48
+ --klods-color-accent-fg: #ffffff;
49
+ --klods-color-link: var(--klods-color-accent);
50
+ --klods-color-danger: #d1335b;
51
+ --klods-color-success: #2f9e44;
52
+ --klods-color-warning: #d97706;
53
+ --klods-color-info: #2563eb;
54
+ --klods-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
55
+ --klods-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
56
+ --klods-font-size-base: 16px;
57
+ --klods-font-size-sm: 0.875rem;
58
+ --klods-font-size-lg: 1.125rem;
59
+ --klods-font-size-xl: 1.5rem;
60
+ --klods-font-size-2xl: 2rem;
61
+ --klods-font-size-3xl: 2.5rem;
62
+ --klods-line-height-base: 1.5;
63
+ --klods-line-height-tight: 1.2;
64
+ --klods-space-0: 0;
65
+ --klods-space-1: 0.25rem;
66
+ --klods-space-2: 0.5rem;
67
+ --klods-space-3: 0.75rem;
68
+ --klods-space-4: 1rem;
69
+ --klods-space-5: 1.5rem;
70
+ --klods-space-6: 2rem;
71
+ --klods-space-7: 3rem;
72
+ --klods-space-8: 4rem;
73
+ --klods-radius-sm: 4px;
74
+ --klods-radius-md: 8px;
75
+ --klods-radius-lg: 16px;
76
+ --klods-radius-pill: 999px;
77
+ --klods-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
78
+ --klods-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
79
+ --klods-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);
80
+ --klods-content-max: 72rem;
81
+ --klods-sidebar-width: 16rem;
82
+ --klods-header-height: 4rem;
83
+ --klods-footer-height: auto;
84
+ --klods-gutter: var(--klods-space-5);
85
+ --klods-transition: 150ms ease;
86
+ }
87
+ }
88
+ @layer klods.themes {
89
+ [data-theme=dark] {
90
+ --klods-color-bg: #0f1115;
91
+ --klods-color-fg: #ececef;
92
+ --klods-color-muted: #9aa0aa;
93
+ --klods-color-surface: #181b22;
94
+ --klods-color-surface-2: #1f232c;
95
+ --klods-color-border: #2a2f3a;
96
+ --klods-color-accent: #8a8aff;
97
+ --klods-color-accent-fg: #0f1115;
98
+ }
99
+ [data-theme=playful] {
100
+ --klods-color-bg: #fff7fb;
101
+ --klods-color-fg: #2a1a3a;
102
+ --klods-color-surface: #ffe8f3;
103
+ --klods-color-surface-2: #ffd6ea;
104
+ --klods-color-border: #f4bfd9;
105
+ --klods-color-accent: #e63990;
106
+ --klods-color-accent-fg: #ffffff;
107
+ --klods-radius-sm: 8px;
108
+ --klods-radius-md: 16px;
109
+ --klods-radius-lg: 28px;
110
+ --klods-font-sans: "Comic Sans MS", "Comic Sans", ui-rounded, system-ui, sans-serif;
111
+ }
112
+ [data-theme=brutalist] {
113
+ --klods-color-bg: #ffffff;
114
+ --klods-color-fg: #000000;
115
+ --klods-color-surface: #ffffff;
116
+ --klods-color-surface-2: #f0f0f0;
117
+ --klods-color-border: #000000;
118
+ --klods-color-accent: #ffe600;
119
+ --klods-color-accent-fg: #000000;
120
+ --klods-radius-sm: 0;
121
+ --klods-radius-md: 0;
122
+ --klods-radius-lg: 0;
123
+ --klods-radius-pill: 0;
124
+ --klods-shadow-sm: 4px 4px 0 #000;
125
+ --klods-shadow-md: 6px 6px 0 #000;
126
+ --klods-shadow-lg: 10px 10px 0 #000;
127
+ --klods-font-sans: "Courier New", ui-monospace, monospace;
128
+ }
129
+ }
130
+ @layer klods.layout {
131
+ .klods-page {
132
+ display: grid;
133
+ min-height: 100dvh;
134
+ grid-template-columns: 1fr;
135
+ grid-template-rows: auto 1fr auto;
136
+ grid-template-areas: "header" "content" "footer";
137
+ }
138
+ .klods-page--with-sidebar {
139
+ grid-template-columns: var(--klods-sidebar-width) 1fr;
140
+ grid-template-areas: "header header" "sidebar content" "footer footer";
141
+ }
142
+ .klods-page--with-sidebar.klods-page--sidebar-right {
143
+ grid-template-columns: 1fr var(--klods-sidebar-width);
144
+ grid-template-areas: "header header" "content sidebar" "footer footer";
145
+ }
146
+ .klods-header {
147
+ grid-area: header;
148
+ display: flex;
149
+ align-items: center;
150
+ gap: var(--klods-space-4);
151
+ padding: 0 var(--klods-gutter);
152
+ min-height: var(--klods-header-height);
153
+ background: var(--klods-color-surface);
154
+ border-bottom: 1px solid var(--klods-color-border);
155
+ }
156
+ .klods-sidebar {
157
+ grid-area: sidebar;
158
+ padding: var(--klods-gutter);
159
+ background: var(--klods-color-surface);
160
+ border-right: 1px solid var(--klods-color-border);
161
+ }
162
+ .klods-page--sidebar-right .klods-sidebar {
163
+ border-right: none;
164
+ border-left: 1px solid var(--klods-color-border);
165
+ }
166
+ .klods-content {
167
+ grid-area: content;
168
+ padding: var(--klods-gutter);
169
+ min-width: 0;
170
+ }
171
+ .klods-content--narrow {
172
+ max-width: var(--klods-content-max);
173
+ margin-inline: auto;
174
+ width: 100%;
175
+ }
176
+ .klods-footer {
177
+ grid-area: footer;
178
+ padding: var(--klods-gutter);
179
+ background: var(--klods-color-surface);
180
+ border-top: 1px solid var(--klods-color-border);
181
+ color: var(--klods-color-muted);
182
+ }
183
+ @media (max-width: 48rem) {
184
+ .klods-page--with-sidebar,
185
+ .klods-page--with-sidebar.klods-page--sidebar-right {
186
+ grid-template-columns: 1fr;
187
+ grid-template-areas: "header" "sidebar" "content" "footer";
188
+ }
189
+ .klods-sidebar {
190
+ border-right: none;
191
+ border-left: none;
192
+ border-bottom: 1px solid var(--klods-color-border);
193
+ }
194
+ }
195
+ }
196
+ @layer klods.components {
197
+ .klods-nav {
198
+ display: flex;
199
+ align-items: center;
200
+ gap: var(--klods-space-4);
201
+ }
202
+ .klods-nav__list {
203
+ display: flex;
204
+ flex-wrap: wrap;
205
+ align-items: center;
206
+ gap: var(--klods-space-3);
207
+ list-style: none;
208
+ padding: 0;
209
+ margin: 0;
210
+ }
211
+ .klods-nav__link {
212
+ display: inline-flex;
213
+ align-items: center;
214
+ padding: var(--klods-space-2) var(--klods-space-3);
215
+ border-radius: var(--klods-radius-sm);
216
+ color: inherit;
217
+ text-decoration: none;
218
+ transition: background var(--klods-transition);
219
+ }
220
+ .klods-nav__link:hover,
221
+ .klods-nav__link:focus-visible {
222
+ background: var(--klods-color-surface-2);
223
+ }
224
+ .klods-nav__link--active {
225
+ background: var(--klods-color-accent);
226
+ color: var(--klods-color-accent-fg);
227
+ }
228
+ .klods-card {
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: var(--klods-space-3);
232
+ padding: var(--klods-space-5);
233
+ background: var(--klods-color-surface);
234
+ border: 1px solid var(--klods-color-border);
235
+ border-radius: var(--klods-radius-md);
236
+ }
237
+ .klods-card--elevated {
238
+ border: none;
239
+ box-shadow: var(--klods-shadow-md);
240
+ }
241
+ .klods-card__title {
242
+ margin: 0;
243
+ font-size: var(--klods-font-size-lg);
244
+ line-height: var(--klods-line-height-tight);
245
+ }
246
+ .klods-card__body {
247
+ margin: 0;
248
+ }
249
+ .klods-card__footer {
250
+ display: flex;
251
+ gap: var(--klods-space-3);
252
+ padding-top: var(--klods-space-3);
253
+ border-top: 1px solid var(--klods-color-border);
254
+ }
255
+ .klods-button {
256
+ display: inline-flex;
257
+ align-items: center;
258
+ justify-content: center;
259
+ gap: var(--klods-space-2);
260
+ padding: var(--klods-space-2) var(--klods-space-4);
261
+ font: inherit;
262
+ font-weight: 600;
263
+ color: var(--klods-color-fg);
264
+ background: var(--klods-color-surface-2);
265
+ border: 1px solid var(--klods-color-border);
266
+ border-radius: var(--klods-radius-sm);
267
+ cursor: pointer;
268
+ transition: background var(--klods-transition), transform var(--klods-transition);
269
+ }
270
+ .klods-button:hover {
271
+ background: var(--klods-color-border);
272
+ }
273
+ .klods-button:active {
274
+ transform: translateY(1px);
275
+ }
276
+ .klods-button--primary {
277
+ background: var(--klods-color-accent);
278
+ color: var(--klods-color-accent-fg);
279
+ border-color: transparent;
280
+ }
281
+ .klods-button--primary:hover {
282
+ filter: brightness(0.95);
283
+ background: var(--klods-color-accent);
284
+ }
285
+ .klods-button--danger {
286
+ background: var(--klods-color-danger);
287
+ color: #fff;
288
+ border-color: transparent;
289
+ }
290
+ .klods-button--ghost {
291
+ background: transparent;
292
+ border-color: transparent;
293
+ }
294
+ .klods-button--ghost:hover {
295
+ background: var(--klods-color-surface-2);
296
+ }
297
+ .klods-badge {
298
+ display: inline-flex;
299
+ align-items: center;
300
+ padding: 0.125rem var(--klods-space-2);
301
+ font-size: var(--klods-font-size-sm);
302
+ font-weight: 600;
303
+ color: var(--klods-color-fg);
304
+ background: var(--klods-color-surface-2);
305
+ border-radius: var(--klods-radius-pill);
306
+ }
307
+ .klods-badge--accent {
308
+ background: var(--klods-color-accent);
309
+ color: var(--klods-color-accent-fg);
310
+ }
311
+ .klods-badge--success {
312
+ background: var(--klods-color-success);
313
+ color: #fff;
314
+ }
315
+ .klods-badge--danger {
316
+ background: var(--klods-color-danger);
317
+ color: #fff;
318
+ }
319
+ .klods-alert {
320
+ padding: var(--klods-space-4);
321
+ border-radius: var(--klods-radius-md);
322
+ border: 1px solid var(--klods-color-border);
323
+ background: var(--klods-color-surface);
324
+ }
325
+ .klods-alert--info {
326
+ border-color: var(--klods-color-info);
327
+ }
328
+ .klods-alert--success {
329
+ border-color: var(--klods-color-success);
330
+ }
331
+ .klods-alert--warning {
332
+ border-color: var(--klods-color-warning);
333
+ }
334
+ .klods-alert--danger {
335
+ border-color: var(--klods-color-danger);
336
+ }
337
+ .klods-prose {
338
+ max-width: 65ch;
339
+ }
340
+ .klods-prose > * + * {
341
+ margin-block-start: var(--klods-space-4);
342
+ }
343
+ .klods-prose h1,
344
+ .klods-prose h2,
345
+ .klods-prose h3 {
346
+ line-height: var(--klods-line-height-tight);
347
+ }
348
+ .klods-prose code {
349
+ font-family: var(--klods-font-mono);
350
+ font-size: 0.95em;
351
+ padding: 0.1em 0.35em;
352
+ background: var(--klods-color-surface-2);
353
+ border-radius: var(--klods-radius-sm);
354
+ }
355
+ .klods-prose pre {
356
+ font-family: var(--klods-font-mono);
357
+ padding: var(--klods-space-4);
358
+ overflow-x: auto;
359
+ background: var(--klods-color-surface-2);
360
+ border-radius: var(--klods-radius-md);
361
+ }
362
+ .klods-prose pre code {
363
+ padding: 0;
364
+ background: transparent;
365
+ }
366
+ .klods-muted {
367
+ color: var(--klods-color-muted);
368
+ }
369
+ .klods-lead {
370
+ font-size: var(--klods-font-size-lg);
371
+ color: var(--klods-color-muted);
372
+ }
373
+ }
374
+ @layer klods.utilities {
375
+ .klods-stack {
376
+ display: flex;
377
+ flex-direction: column;
378
+ gap: var(--klods-space-4);
379
+ }
380
+ .klods-cluster {
381
+ display: flex;
382
+ flex-wrap: wrap;
383
+ align-items: center;
384
+ gap: var(--klods-space-4);
385
+ }
386
+ .klods-row {
387
+ display: flex;
388
+ flex-direction: row;
389
+ align-items: center;
390
+ gap: var(--klods-space-4);
391
+ }
392
+ .klods-grid {
393
+ display: grid;
394
+ gap: var(--klods-space-4);
395
+ grid-template-columns: repeat(2, minmax(0, 1fr));
396
+ }
397
+ .klods-grid--cols-1 {
398
+ grid-template-columns: repeat(1, minmax(0, 1fr));
399
+ }
400
+ .klods-grid--cols-2 {
401
+ grid-template-columns: repeat(2, minmax(0, 1fr));
402
+ }
403
+ .klods-grid--cols-3 {
404
+ grid-template-columns: repeat(3, minmax(0, 1fr));
405
+ }
406
+ .klods-grid--cols-4 {
407
+ grid-template-columns: repeat(4, minmax(0, 1fr));
408
+ }
409
+ .klods-grid--cols-5 {
410
+ grid-template-columns: repeat(5, minmax(0, 1fr));
411
+ }
412
+ .klods-grid--cols-6 {
413
+ grid-template-columns: repeat(6, minmax(0, 1fr));
414
+ }
415
+ .klods-grid--fit {
416
+ --klods-grid-min: 16rem;
417
+ grid-template-columns: repeat(auto-fit, minmax(var(--klods-grid-min), 1fr));
418
+ }
419
+ .klods-center {
420
+ display: flex;
421
+ align-items: center;
422
+ justify-content: center;
423
+ }
424
+ .klods-spread {
425
+ display: flex;
426
+ align-items: center;
427
+ justify-content: space-between;
428
+ gap: var(--klods-space-4);
429
+ }
430
+ .klods-push {
431
+ margin-inline-start: auto;
432
+ }
433
+ .klods-fill {
434
+ flex: 1 1 auto;
435
+ min-width: 0;
436
+ min-height: 0;
437
+ }
438
+ .klods-stack--gap-0,
439
+ .klods-cluster--gap-0,
440
+ .klods-row--gap-0,
441
+ .klods-grid--gap-0 {
442
+ gap: var(--klods-space-0);
443
+ }
444
+ .klods-stack--gap-1,
445
+ .klods-cluster--gap-1,
446
+ .klods-row--gap-1,
447
+ .klods-grid--gap-1 {
448
+ gap: var(--klods-space-1);
449
+ }
450
+ .klods-stack--gap-2,
451
+ .klods-cluster--gap-2,
452
+ .klods-row--gap-2,
453
+ .klods-grid--gap-2 {
454
+ gap: var(--klods-space-2);
455
+ }
456
+ .klods-stack--gap-3,
457
+ .klods-cluster--gap-3,
458
+ .klods-row--gap-3,
459
+ .klods-grid--gap-3 {
460
+ gap: var(--klods-space-3);
461
+ }
462
+ .klods-stack--gap-4,
463
+ .klods-cluster--gap-4,
464
+ .klods-row--gap-4,
465
+ .klods-grid--gap-4 {
466
+ gap: var(--klods-space-4);
467
+ }
468
+ .klods-stack--gap-5,
469
+ .klods-cluster--gap-5,
470
+ .klods-row--gap-5,
471
+ .klods-grid--gap-5 {
472
+ gap: var(--klods-space-5);
473
+ }
474
+ .klods-stack--gap-6,
475
+ .klods-cluster--gap-6,
476
+ .klods-row--gap-6,
477
+ .klods-grid--gap-6 {
478
+ gap: var(--klods-space-6);
479
+ }
480
+ .klods-stack--gap-7,
481
+ .klods-cluster--gap-7,
482
+ .klods-row--gap-7,
483
+ .klods-grid--gap-7 {
484
+ gap: var(--klods-space-7);
485
+ }
486
+ .klods-stack--gap-8,
487
+ .klods-cluster--gap-8,
488
+ .klods-row--gap-8,
489
+ .klods-grid--gap-8 {
490
+ gap: var(--klods-space-8);
491
+ }
492
+ .klods-pad-0 {
493
+ padding: var(--klods-space-0);
494
+ }
495
+ .klods-pad-1 {
496
+ padding: var(--klods-space-1);
497
+ }
498
+ .klods-pad-2 {
499
+ padding: var(--klods-space-2);
500
+ }
501
+ .klods-pad-3 {
502
+ padding: var(--klods-space-3);
503
+ }
504
+ .klods-pad-4 {
505
+ padding: var(--klods-space-4);
506
+ }
507
+ .klods-pad-5 {
508
+ padding: var(--klods-space-5);
509
+ }
510
+ .klods-pad-6 {
511
+ padding: var(--klods-space-6);
512
+ }
513
+ .klods-pad-7 {
514
+ padding: var(--klods-space-7);
515
+ }
516
+ .klods-pad-8 {
517
+ padding: var(--klods-space-8);
518
+ }
519
+ .klods-sr-only {
520
+ position: absolute;
521
+ width: 1px;
522
+ height: 1px;
523
+ padding: 0;
524
+ margin: -1px;
525
+ overflow: hidden;
526
+ clip: rect(0, 0, 0, 0);
527
+ white-space: nowrap;
528
+ border: 0;
529
+ }
530
+ }
@@ -0,0 +1 @@
1
+ @layer klods.reset, klods.tokens, klods.themes, klods.layout, klods.components, klods.utilities;@layer klods.reset{*,*::before,*::after{box-sizing:border-box}html{-webkit-text-size-adjust:100%;text-size-adjust:100%}body{margin:0;min-height:100dvh;font-family:var(--klods-font-sans);font-size:var(--klods-font-size-base);line-height:var(--klods-line-height-base);color:var(--klods-color-fg);background:var(--klods-color-bg)}img,picture,svg,video{display:block;max-width:100%}button,input,select,textarea{font:inherit;color:inherit}a{color:var(--klods-color-link)}}@layer klods.tokens{:root{--klods-color-bg: #ffffff;--klods-color-fg: #1a1a1a;--klods-color-muted: #6b7280;--klods-color-surface: #f5f5f7;--klods-color-surface-2: #ececef;--klods-color-border: #e5e7eb;--klods-color-accent: #5b5bd6;--klods-color-accent-fg: #ffffff;--klods-color-link: var(--klods-color-accent);--klods-color-danger: #d1335b;--klods-color-success: #2f9e44;--klods-color-warning: #d97706;--klods-color-info: #2563eb;--klods-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--klods-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;--klods-font-size-base: 16px;--klods-font-size-sm: 0.875rem;--klods-font-size-lg: 1.125rem;--klods-font-size-xl: 1.5rem;--klods-font-size-2xl: 2rem;--klods-font-size-3xl: 2.5rem;--klods-line-height-base: 1.5;--klods-line-height-tight: 1.2;--klods-space-0: 0;--klods-space-1: 0.25rem;--klods-space-2: 0.5rem;--klods-space-3: 0.75rem;--klods-space-4: 1rem;--klods-space-5: 1.5rem;--klods-space-6: 2rem;--klods-space-7: 3rem;--klods-space-8: 4rem;--klods-radius-sm: 4px;--klods-radius-md: 8px;--klods-radius-lg: 16px;--klods-radius-pill: 999px;--klods-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);--klods-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);--klods-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);--klods-content-max: 72rem;--klods-sidebar-width: 16rem;--klods-header-height: 4rem;--klods-footer-height: auto;--klods-gutter: var(--klods-space-5);--klods-transition: 150ms ease}}@layer klods.themes{[data-theme=dark]{--klods-color-bg: #0f1115;--klods-color-fg: #ececef;--klods-color-muted: #9aa0aa;--klods-color-surface: #181b22;--klods-color-surface-2: #1f232c;--klods-color-border: #2a2f3a;--klods-color-accent: #8a8aff;--klods-color-accent-fg: #0f1115}[data-theme=playful]{--klods-color-bg: #fff7fb;--klods-color-fg: #2a1a3a;--klods-color-surface: #ffe8f3;--klods-color-surface-2: #ffd6ea;--klods-color-border: #f4bfd9;--klods-color-accent: #e63990;--klods-color-accent-fg: #ffffff;--klods-radius-sm: 8px;--klods-radius-md: 16px;--klods-radius-lg: 28px;--klods-font-sans: "Comic Sans MS", "Comic Sans", ui-rounded, system-ui, sans-serif}[data-theme=brutalist]{--klods-color-bg: #ffffff;--klods-color-fg: #000000;--klods-color-surface: #ffffff;--klods-color-surface-2: #f0f0f0;--klods-color-border: #000000;--klods-color-accent: #ffe600;--klods-color-accent-fg: #000000;--klods-radius-sm: 0;--klods-radius-md: 0;--klods-radius-lg: 0;--klods-radius-pill: 0;--klods-shadow-sm: 4px 4px 0 #000;--klods-shadow-md: 6px 6px 0 #000;--klods-shadow-lg: 10px 10px 0 #000;--klods-font-sans: "Courier New", ui-monospace, monospace}}@layer klods.layout{.klods-page{display:grid;min-height:100dvh;grid-template-columns:1fr;grid-template-rows:auto 1fr auto;grid-template-areas:"header" "content" "footer"}.klods-page--with-sidebar{grid-template-columns:var(--klods-sidebar-width) 1fr;grid-template-areas:"header header" "sidebar content" "footer footer"}.klods-page--with-sidebar.klods-page--sidebar-right{grid-template-columns:1fr var(--klods-sidebar-width);grid-template-areas:"header header" "content sidebar" "footer footer"}.klods-header{grid-area:header;display:flex;align-items:center;gap:var(--klods-space-4);padding:0 var(--klods-gutter);min-height:var(--klods-header-height);background:var(--klods-color-surface);border-bottom:1px solid var(--klods-color-border)}.klods-sidebar{grid-area:sidebar;padding:var(--klods-gutter);background:var(--klods-color-surface);border-right:1px solid var(--klods-color-border)}.klods-page--sidebar-right .klods-sidebar{border-right:none;border-left:1px solid var(--klods-color-border)}.klods-content{grid-area:content;padding:var(--klods-gutter);min-width:0}.klods-content--narrow{max-width:var(--klods-content-max);margin-inline:auto;width:100%}.klods-footer{grid-area:footer;padding:var(--klods-gutter);background:var(--klods-color-surface);border-top:1px solid var(--klods-color-border);color:var(--klods-color-muted)}@media(max-width: 48rem){.klods-page--with-sidebar,.klods-page--with-sidebar.klods-page--sidebar-right{grid-template-columns:1fr;grid-template-areas:"header" "sidebar" "content" "footer"}.klods-sidebar{border-right:none;border-left:none;border-bottom:1px solid var(--klods-color-border)}}}@layer klods.components{.klods-nav{display:flex;align-items:center;gap:var(--klods-space-4)}.klods-nav__list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--klods-space-3);list-style:none;padding:0;margin:0}.klods-nav__link{display:inline-flex;align-items:center;padding:var(--klods-space-2) var(--klods-space-3);border-radius:var(--klods-radius-sm);color:inherit;text-decoration:none;transition:background var(--klods-transition)}.klods-nav__link:hover,.klods-nav__link:focus-visible{background:var(--klods-color-surface-2)}.klods-nav__link--active{background:var(--klods-color-accent);color:var(--klods-color-accent-fg)}.klods-card{display:flex;flex-direction:column;gap:var(--klods-space-3);padding:var(--klods-space-5);background:var(--klods-color-surface);border:1px solid var(--klods-color-border);border-radius:var(--klods-radius-md)}.klods-card--elevated{border:none;box-shadow:var(--klods-shadow-md)}.klods-card__title{margin:0;font-size:var(--klods-font-size-lg);line-height:var(--klods-line-height-tight)}.klods-card__body{margin:0}.klods-card__footer{display:flex;gap:var(--klods-space-3);padding-top:var(--klods-space-3);border-top:1px solid var(--klods-color-border)}.klods-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--klods-space-2);padding:var(--klods-space-2) var(--klods-space-4);font:inherit;font-weight:600;color:var(--klods-color-fg);background:var(--klods-color-surface-2);border:1px solid var(--klods-color-border);border-radius:var(--klods-radius-sm);cursor:pointer;transition:background var(--klods-transition),transform var(--klods-transition)}.klods-button:hover{background:var(--klods-color-border)}.klods-button:active{transform:translateY(1px)}.klods-button--primary{background:var(--klods-color-accent);color:var(--klods-color-accent-fg);border-color:rgba(0,0,0,0)}.klods-button--primary:hover{filter:brightness(0.95);background:var(--klods-color-accent)}.klods-button--danger{background:var(--klods-color-danger);color:#fff;border-color:rgba(0,0,0,0)}.klods-button--ghost{background:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.klods-button--ghost:hover{background:var(--klods-color-surface-2)}.klods-badge{display:inline-flex;align-items:center;padding:.125rem var(--klods-space-2);font-size:var(--klods-font-size-sm);font-weight:600;color:var(--klods-color-fg);background:var(--klods-color-surface-2);border-radius:var(--klods-radius-pill)}.klods-badge--accent{background:var(--klods-color-accent);color:var(--klods-color-accent-fg)}.klods-badge--success{background:var(--klods-color-success);color:#fff}.klods-badge--danger{background:var(--klods-color-danger);color:#fff}.klods-alert{padding:var(--klods-space-4);border-radius:var(--klods-radius-md);border:1px solid var(--klods-color-border);background:var(--klods-color-surface)}.klods-alert--info{border-color:var(--klods-color-info)}.klods-alert--success{border-color:var(--klods-color-success)}.klods-alert--warning{border-color:var(--klods-color-warning)}.klods-alert--danger{border-color:var(--klods-color-danger)}.klods-prose{max-width:65ch}.klods-prose>*+*{margin-block-start:var(--klods-space-4)}.klods-prose h1,.klods-prose h2,.klods-prose h3{line-height:var(--klods-line-height-tight)}.klods-prose code{font-family:var(--klods-font-mono);font-size:.95em;padding:.1em .35em;background:var(--klods-color-surface-2);border-radius:var(--klods-radius-sm)}.klods-prose pre{font-family:var(--klods-font-mono);padding:var(--klods-space-4);overflow-x:auto;background:var(--klods-color-surface-2);border-radius:var(--klods-radius-md)}.klods-prose pre code{padding:0;background:rgba(0,0,0,0)}.klods-muted{color:var(--klods-color-muted)}.klods-lead{font-size:var(--klods-font-size-lg);color:var(--klods-color-muted)}}@layer klods.utilities{.klods-stack{display:flex;flex-direction:column;gap:var(--klods-space-4)}.klods-cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--klods-space-4)}.klods-row{display:flex;flex-direction:row;align-items:center;gap:var(--klods-space-4)}.klods-grid{display:grid;gap:var(--klods-space-4);grid-template-columns:repeat(2, minmax(0, 1fr))}.klods-grid--cols-1{grid-template-columns:repeat(1, minmax(0, 1fr))}.klods-grid--cols-2{grid-template-columns:repeat(2, minmax(0, 1fr))}.klods-grid--cols-3{grid-template-columns:repeat(3, minmax(0, 1fr))}.klods-grid--cols-4{grid-template-columns:repeat(4, minmax(0, 1fr))}.klods-grid--cols-5{grid-template-columns:repeat(5, minmax(0, 1fr))}.klods-grid--cols-6{grid-template-columns:repeat(6, minmax(0, 1fr))}.klods-grid--fit{--klods-grid-min: 16rem;grid-template-columns:repeat(auto-fit, minmax(var(--klods-grid-min), 1fr))}.klods-center{display:flex;align-items:center;justify-content:center}.klods-spread{display:flex;align-items:center;justify-content:space-between;gap:var(--klods-space-4)}.klods-push{margin-inline-start:auto}.klods-fill{flex:1 1 auto;min-width:0;min-height:0}.klods-stack--gap-0,.klods-cluster--gap-0,.klods-row--gap-0,.klods-grid--gap-0{gap:var(--klods-space-0)}.klods-stack--gap-1,.klods-cluster--gap-1,.klods-row--gap-1,.klods-grid--gap-1{gap:var(--klods-space-1)}.klods-stack--gap-2,.klods-cluster--gap-2,.klods-row--gap-2,.klods-grid--gap-2{gap:var(--klods-space-2)}.klods-stack--gap-3,.klods-cluster--gap-3,.klods-row--gap-3,.klods-grid--gap-3{gap:var(--klods-space-3)}.klods-stack--gap-4,.klods-cluster--gap-4,.klods-row--gap-4,.klods-grid--gap-4{gap:var(--klods-space-4)}.klods-stack--gap-5,.klods-cluster--gap-5,.klods-row--gap-5,.klods-grid--gap-5{gap:var(--klods-space-5)}.klods-stack--gap-6,.klods-cluster--gap-6,.klods-row--gap-6,.klods-grid--gap-6{gap:var(--klods-space-6)}.klods-stack--gap-7,.klods-cluster--gap-7,.klods-row--gap-7,.klods-grid--gap-7{gap:var(--klods-space-7)}.klods-stack--gap-8,.klods-cluster--gap-8,.klods-row--gap-8,.klods-grid--gap-8{gap:var(--klods-space-8)}.klods-pad-0{padding:var(--klods-space-0)}.klods-pad-1{padding:var(--klods-space-1)}.klods-pad-2{padding:var(--klods-space-2)}.klods-pad-3{padding:var(--klods-space-3)}.klods-pad-4{padding:var(--klods-space-4)}.klods-pad-5{padding:var(--klods-space-5)}.klods-pad-6{padding:var(--klods-space-6)}.klods-pad-7{padding:var(--klods-space-7)}.klods-pad-8{padding:var(--klods-space-8)}.klods-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "klods-css",
3
+ "version": "1.0.1",
4
+ "description": "klods stylesheet — drop-in CSS for layout, utilities and components.",
5
+ "license": "MIT",
6
+ "author": "Drue Wilding",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/druewilding/klods",
10
+ "directory": "packages/klods-css"
11
+ },
12
+ "type": "module",
13
+ "main": "dist/klods.css",
14
+ "style": "dist/klods.css",
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "README.md"
19
+ ],
20
+ "exports": {
21
+ ".": "./dist/klods.css",
22
+ "./min": "./dist/klods.min.css",
23
+ "./src/*": "./src/*"
24
+ },
25
+ "scripts": {
26
+ "build": "npm run build:css && npm run build:min",
27
+ "build:css": "sass src/klods.scss dist/klods.css --style=expanded --no-source-map",
28
+ "build:min": "sass src/klods.scss dist/klods.min.css --style=compressed --no-source-map",
29
+ "dev": "sass src/klods.scss dist/klods.css --watch --style=expanded"
30
+ },
31
+ "devDependencies": {
32
+ "sass": "^1.81.0"
33
+ }
34
+ }
@@ -0,0 +1,223 @@
1
+ // Components — first wave: nav, card, button, badge, alert, prose.
2
+ // More to follow (forms, table, modal, tabs, breadcrumbs, toast).
3
+
4
+ @layer klods.components {
5
+ // ── Nav ────────────────────────────────────────────────────────────────
6
+ .klods-nav {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: var(--klods-space-4);
10
+ }
11
+
12
+ .klods-nav__list {
13
+ display: flex;
14
+ flex-wrap: wrap;
15
+ align-items: center;
16
+ gap: var(--klods-space-3);
17
+ list-style: none;
18
+ padding: 0;
19
+ margin: 0;
20
+ }
21
+
22
+ .klods-nav__link {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ padding: var(--klods-space-2) var(--klods-space-3);
26
+ border-radius: var(--klods-radius-sm);
27
+ color: inherit;
28
+ text-decoration: none;
29
+ transition: background var(--klods-transition);
30
+ }
31
+
32
+ .klods-nav__link:hover,
33
+ .klods-nav__link:focus-visible {
34
+ background: var(--klods-color-surface-2);
35
+ }
36
+
37
+ .klods-nav__link--active {
38
+ background: var(--klods-color-accent);
39
+ color: var(--klods-color-accent-fg);
40
+ }
41
+
42
+ // ── Card ───────────────────────────────────────────────────────────────
43
+ .klods-card {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: var(--klods-space-3);
47
+ padding: var(--klods-space-5);
48
+ background: var(--klods-color-surface);
49
+ border: 1px solid var(--klods-color-border);
50
+ border-radius: var(--klods-radius-md);
51
+ }
52
+
53
+ .klods-card--elevated {
54
+ border: none;
55
+ box-shadow: var(--klods-shadow-md);
56
+ }
57
+
58
+ .klods-card__title {
59
+ margin: 0;
60
+ font-size: var(--klods-font-size-lg);
61
+ line-height: var(--klods-line-height-tight);
62
+ }
63
+
64
+ .klods-card__body {
65
+ margin: 0;
66
+ }
67
+
68
+ .klods-card__footer {
69
+ display: flex;
70
+ gap: var(--klods-space-3);
71
+ padding-top: var(--klods-space-3);
72
+ border-top: 1px solid var(--klods-color-border);
73
+ }
74
+
75
+ // ── Button ─────────────────────────────────────────────────────────────
76
+ .klods-button {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ justify-content: center;
80
+ gap: var(--klods-space-2);
81
+ padding: var(--klods-space-2) var(--klods-space-4);
82
+ font: inherit;
83
+ font-weight: 600;
84
+ color: var(--klods-color-fg);
85
+ background: var(--klods-color-surface-2);
86
+ border: 1px solid var(--klods-color-border);
87
+ border-radius: var(--klods-radius-sm);
88
+ cursor: pointer;
89
+ transition:
90
+ background var(--klods-transition),
91
+ transform var(--klods-transition);
92
+ }
93
+
94
+ .klods-button:hover {
95
+ background: var(--klods-color-border);
96
+ }
97
+
98
+ .klods-button:active {
99
+ transform: translateY(1px);
100
+ }
101
+
102
+ .klods-button--primary {
103
+ background: var(--klods-color-accent);
104
+ color: var(--klods-color-accent-fg);
105
+ border-color: transparent;
106
+ }
107
+
108
+ .klods-button--primary:hover {
109
+ filter: brightness(0.95);
110
+ background: var(--klods-color-accent);
111
+ }
112
+
113
+ .klods-button--danger {
114
+ background: var(--klods-color-danger);
115
+ color: #fff;
116
+ border-color: transparent;
117
+ }
118
+
119
+ .klods-button--ghost {
120
+ background: transparent;
121
+ border-color: transparent;
122
+ }
123
+
124
+ .klods-button--ghost:hover {
125
+ background: var(--klods-color-surface-2);
126
+ }
127
+
128
+ // ── Badge ──────────────────────────────────────────────────────────────
129
+ .klods-badge {
130
+ display: inline-flex;
131
+ align-items: center;
132
+ padding: 0.125rem var(--klods-space-2);
133
+ font-size: var(--klods-font-size-sm);
134
+ font-weight: 600;
135
+ color: var(--klods-color-fg);
136
+ background: var(--klods-color-surface-2);
137
+ border-radius: var(--klods-radius-pill);
138
+ }
139
+
140
+ .klods-badge--accent {
141
+ background: var(--klods-color-accent);
142
+ color: var(--klods-color-accent-fg);
143
+ }
144
+
145
+ .klods-badge--success {
146
+ background: var(--klods-color-success);
147
+ color: #fff;
148
+ }
149
+
150
+ .klods-badge--danger {
151
+ background: var(--klods-color-danger);
152
+ color: #fff;
153
+ }
154
+
155
+ // ── Alert ──────────────────────────────────────────────────────────────
156
+ .klods-alert {
157
+ padding: var(--klods-space-4);
158
+ border-radius: var(--klods-radius-md);
159
+ border: 1px solid var(--klods-color-border);
160
+ background: var(--klods-color-surface);
161
+ }
162
+
163
+ .klods-alert--info {
164
+ border-color: var(--klods-color-info);
165
+ }
166
+
167
+ .klods-alert--success {
168
+ border-color: var(--klods-color-success);
169
+ }
170
+
171
+ .klods-alert--warning {
172
+ border-color: var(--klods-color-warning);
173
+ }
174
+
175
+ .klods-alert--danger {
176
+ border-color: var(--klods-color-danger);
177
+ }
178
+
179
+ // ── Prose ──────────────────────────────────────────────────────────────
180
+ .klods-prose {
181
+ max-width: 65ch;
182
+ }
183
+
184
+ .klods-prose > * + * {
185
+ margin-block-start: var(--klods-space-4);
186
+ }
187
+
188
+ .klods-prose h1,
189
+ .klods-prose h2,
190
+ .klods-prose h3 {
191
+ line-height: var(--klods-line-height-tight);
192
+ }
193
+
194
+ .klods-prose code {
195
+ font-family: var(--klods-font-mono);
196
+ font-size: 0.95em;
197
+ padding: 0.1em 0.35em;
198
+ background: var(--klods-color-surface-2);
199
+ border-radius: var(--klods-radius-sm);
200
+ }
201
+
202
+ .klods-prose pre {
203
+ font-family: var(--klods-font-mono);
204
+ padding: var(--klods-space-4);
205
+ overflow-x: auto;
206
+ background: var(--klods-color-surface-2);
207
+ border-radius: var(--klods-radius-md);
208
+ }
209
+
210
+ .klods-prose pre code {
211
+ padding: 0;
212
+ background: transparent;
213
+ }
214
+
215
+ .klods-muted {
216
+ color: var(--klods-color-muted);
217
+ }
218
+
219
+ .klods-lead {
220
+ font-size: var(--klods-font-size-lg);
221
+ color: var(--klods-color-muted);
222
+ }
223
+ }
@@ -0,0 +1,3 @@
1
+ // Establish the cascade-layer order. Consumer styles outside these layers
2
+ // always win, so themes can be overridden without specificity tricks.
3
+ @layer klods.reset, klods.tokens, klods.themes, klods.layout, klods.components, klods.utilities;
@@ -0,0 +1,97 @@
1
+ // Layout primitives — the four corners.
2
+ //
3
+ // .klods-page is a CSS Grid container that can be:
4
+ // - default : header / main / footer
5
+ // - --with-sidebar : adds a left sidebar column
6
+ // - --with-sidebar.--sidebar-right : sidebar on the right
7
+
8
+ @layer klods.layout {
9
+ .klods-page {
10
+ display: grid;
11
+ min-height: 100dvh;
12
+ grid-template-columns: 1fr;
13
+ grid-template-rows: auto 1fr auto;
14
+ grid-template-areas:
15
+ "header"
16
+ "content"
17
+ "footer";
18
+ }
19
+
20
+ .klods-page--with-sidebar {
21
+ grid-template-columns: var(--klods-sidebar-width) 1fr;
22
+ grid-template-areas:
23
+ "header header"
24
+ "sidebar content"
25
+ "footer footer";
26
+ }
27
+
28
+ .klods-page--with-sidebar.klods-page--sidebar-right {
29
+ grid-template-columns: 1fr var(--klods-sidebar-width);
30
+ grid-template-areas:
31
+ "header header"
32
+ "content sidebar"
33
+ "footer footer";
34
+ }
35
+
36
+ .klods-header {
37
+ grid-area: header;
38
+ display: flex;
39
+ align-items: center;
40
+ gap: var(--klods-space-4);
41
+ padding: 0 var(--klods-gutter);
42
+ min-height: var(--klods-header-height);
43
+ background: var(--klods-color-surface);
44
+ border-bottom: 1px solid var(--klods-color-border);
45
+ }
46
+
47
+ .klods-sidebar {
48
+ grid-area: sidebar;
49
+ padding: var(--klods-gutter);
50
+ background: var(--klods-color-surface);
51
+ border-right: 1px solid var(--klods-color-border);
52
+ }
53
+
54
+ .klods-page--sidebar-right .klods-sidebar {
55
+ border-right: none;
56
+ border-left: 1px solid var(--klods-color-border);
57
+ }
58
+
59
+ .klods-content {
60
+ grid-area: content;
61
+ padding: var(--klods-gutter);
62
+ min-width: 0; // prevent grid-blowout from long content
63
+ }
64
+
65
+ .klods-content--narrow {
66
+ max-width: var(--klods-content-max);
67
+ margin-inline: auto;
68
+ width: 100%;
69
+ }
70
+
71
+ .klods-footer {
72
+ grid-area: footer;
73
+ padding: var(--klods-gutter);
74
+ background: var(--klods-color-surface);
75
+ border-top: 1px solid var(--klods-color-border);
76
+ color: var(--klods-color-muted);
77
+ }
78
+
79
+ // Collapse sidebar on small screens — stack everything.
80
+ @media (max-width: 48rem) {
81
+ .klods-page--with-sidebar,
82
+ .klods-page--with-sidebar.klods-page--sidebar-right {
83
+ grid-template-columns: 1fr;
84
+ grid-template-areas:
85
+ "header"
86
+ "sidebar"
87
+ "content"
88
+ "footer";
89
+ }
90
+
91
+ .klods-sidebar {
92
+ border-right: none;
93
+ border-left: none;
94
+ border-bottom: 1px solid var(--klods-color-border);
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,42 @@
1
+ @layer klods.reset {
2
+ *,
3
+ *::before,
4
+ *::after {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html {
9
+ -webkit-text-size-adjust: 100%;
10
+ text-size-adjust: 100%;
11
+ }
12
+
13
+ body {
14
+ margin: 0;
15
+ min-height: 100dvh;
16
+ font-family: var(--klods-font-sans);
17
+ font-size: var(--klods-font-size-base);
18
+ line-height: var(--klods-line-height-base);
19
+ color: var(--klods-color-fg);
20
+ background: var(--klods-color-bg);
21
+ }
22
+
23
+ img,
24
+ picture,
25
+ svg,
26
+ video {
27
+ display: block;
28
+ max-width: 100%;
29
+ }
30
+
31
+ button,
32
+ input,
33
+ select,
34
+ textarea {
35
+ font: inherit;
36
+ color: inherit;
37
+ }
38
+
39
+ a {
40
+ color: var(--klods-color-link);
41
+ }
42
+ }
@@ -0,0 +1,47 @@
1
+ // Themes are pure token overrides. Apply with [data-theme="..."] on <html> or any
2
+ // container. Default (no attribute) is the light theme defined in _tokens.scss.
3
+
4
+ @layer klods.themes {
5
+ [data-theme="dark"] {
6
+ --klods-color-bg: #0f1115;
7
+ --klods-color-fg: #ececef;
8
+ --klods-color-muted: #9aa0aa;
9
+ --klods-color-surface: #181b22;
10
+ --klods-color-surface-2: #1f232c;
11
+ --klods-color-border: #2a2f3a;
12
+ --klods-color-accent: #8a8aff;
13
+ --klods-color-accent-fg: #0f1115;
14
+ }
15
+
16
+ [data-theme="playful"] {
17
+ --klods-color-bg: #fff7fb;
18
+ --klods-color-fg: #2a1a3a;
19
+ --klods-color-surface: #ffe8f3;
20
+ --klods-color-surface-2: #ffd6ea;
21
+ --klods-color-border: #f4bfd9;
22
+ --klods-color-accent: #e63990;
23
+ --klods-color-accent-fg: #ffffff;
24
+ --klods-radius-sm: 8px;
25
+ --klods-radius-md: 16px;
26
+ --klods-radius-lg: 28px;
27
+ --klods-font-sans: "Comic Sans MS", "Comic Sans", ui-rounded, system-ui, sans-serif;
28
+ }
29
+
30
+ [data-theme="brutalist"] {
31
+ --klods-color-bg: #ffffff;
32
+ --klods-color-fg: #000000;
33
+ --klods-color-surface: #ffffff;
34
+ --klods-color-surface-2: #f0f0f0;
35
+ --klods-color-border: #000000;
36
+ --klods-color-accent: #ffe600;
37
+ --klods-color-accent-fg: #000000;
38
+ --klods-radius-sm: 0;
39
+ --klods-radius-md: 0;
40
+ --klods-radius-lg: 0;
41
+ --klods-radius-pill: 0;
42
+ --klods-shadow-sm: 4px 4px 0 #000;
43
+ --klods-shadow-md: 6px 6px 0 #000;
44
+ --klods-shadow-lg: 10px 10px 0 #000;
45
+ --klods-font-sans: "Courier New", ui-monospace, monospace;
46
+ }
47
+ }
@@ -0,0 +1,62 @@
1
+ @layer klods.tokens {
2
+ :root {
3
+ // ── Colour ─────────────────────────────────────────────────────────────
4
+ --klods-color-bg: #ffffff;
5
+ --klods-color-fg: #1a1a1a;
6
+ --klods-color-muted: #6b7280;
7
+ --klods-color-surface: #f5f5f7;
8
+ --klods-color-surface-2: #ececef;
9
+ --klods-color-border: #e5e7eb;
10
+ --klods-color-accent: #5b5bd6;
11
+ --klods-color-accent-fg: #ffffff;
12
+ --klods-color-link: var(--klods-color-accent);
13
+ --klods-color-danger: #d1335b;
14
+ --klods-color-success: #2f9e44;
15
+ --klods-color-warning: #d97706;
16
+ --klods-color-info: #2563eb;
17
+
18
+ // ── Typography ─────────────────────────────────────────────────────────
19
+ --klods-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
20
+ --klods-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
21
+ --klods-font-size-base: 16px;
22
+ --klods-font-size-sm: 0.875rem;
23
+ --klods-font-size-lg: 1.125rem;
24
+ --klods-font-size-xl: 1.5rem;
25
+ --klods-font-size-2xl: 2rem;
26
+ --klods-font-size-3xl: 2.5rem;
27
+ --klods-line-height-base: 1.5;
28
+ --klods-line-height-tight: 1.2;
29
+
30
+ // ── Spacing scale (rem-based, 4px steps) ───────────────────────────────
31
+ --klods-space-0: 0;
32
+ --klods-space-1: 0.25rem; // 4px
33
+ --klods-space-2: 0.5rem; // 8px
34
+ --klods-space-3: 0.75rem; // 12px
35
+ --klods-space-4: 1rem; // 16px
36
+ --klods-space-5: 1.5rem; // 24px
37
+ --klods-space-6: 2rem; // 32px
38
+ --klods-space-7: 3rem; // 48px
39
+ --klods-space-8: 4rem; // 64px
40
+
41
+ // ── Radius ─────────────────────────────────────────────────────────────
42
+ --klods-radius-sm: 4px;
43
+ --klods-radius-md: 8px;
44
+ --klods-radius-lg: 16px;
45
+ --klods-radius-pill: 999px;
46
+
47
+ // ── Shadow ─────────────────────────────────────────────────────────────
48
+ --klods-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
49
+ --klods-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
50
+ --klods-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);
51
+
52
+ // ── Layout ─────────────────────────────────────────────────────────────
53
+ --klods-content-max: 72rem;
54
+ --klods-sidebar-width: 16rem;
55
+ --klods-header-height: 4rem;
56
+ --klods-footer-height: auto;
57
+ --klods-gutter: var(--klods-space-5);
58
+
59
+ // ── Motion ─────────────────────────────────────────────────────────────
60
+ --klods-transition: 150ms ease;
61
+ }
62
+ }
@@ -0,0 +1,105 @@
1
+ // Utilities — the "I always forget how to do this in CSS" classes.
2
+ //
3
+ // Naming follows BEM-ish conventions: base class with --modifier variants.
4
+ // All gaps default to --klods-space-4 and can be overridden with --gap-{1..8}.
5
+
6
+ @layer klods.utilities {
7
+ // Vertical stack
8
+ .klods-stack {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--klods-space-4);
12
+ }
13
+
14
+ // Horizontal cluster — wraps when out of room
15
+ .klods-cluster {
16
+ display: flex;
17
+ flex-wrap: wrap;
18
+ align-items: center;
19
+ gap: var(--klods-space-4);
20
+ }
21
+
22
+ // Strict horizontal row — does not wrap
23
+ .klods-row {
24
+ display: flex;
25
+ flex-direction: row;
26
+ align-items: center;
27
+ gap: var(--klods-space-4);
28
+ }
29
+
30
+ // Equal-column grid (defaults to 2 columns; override with --cols-N)
31
+ .klods-grid {
32
+ display: grid;
33
+ gap: var(--klods-space-4);
34
+ grid-template-columns: repeat(2, minmax(0, 1fr));
35
+ }
36
+
37
+ @for $n from 1 through 6 {
38
+ .klods-grid--cols-#{$n} {
39
+ grid-template-columns: repeat(#{$n}, minmax(0, 1fr));
40
+ }
41
+ }
42
+
43
+ // Auto-fit grid (responsive cards): items at least --klods-grid-min wide
44
+ .klods-grid--fit {
45
+ --klods-grid-min: 16rem;
46
+ grid-template-columns: repeat(auto-fit, minmax(var(--klods-grid-min), 1fr));
47
+ }
48
+
49
+ // Centered content (horizontal + vertical)
50
+ .klods-center {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ }
55
+
56
+ // Spread — pushes children to the edges (justify-content: space-between)
57
+ .klods-spread {
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: space-between;
61
+ gap: var(--klods-space-4);
62
+ }
63
+
64
+ // Push-to-end helper (apply to a child of cluster/row/spread)
65
+ .klods-push {
66
+ margin-inline-start: auto;
67
+ }
68
+
69
+ // Fill the parent
70
+ .klods-fill {
71
+ flex: 1 1 auto;
72
+ min-width: 0;
73
+ min-height: 0;
74
+ }
75
+
76
+ // Gap modifiers — work on stack / cluster / row / grid
77
+ @for $i from 0 through 8 {
78
+ .klods-stack--gap-#{$i},
79
+ .klods-cluster--gap-#{$i},
80
+ .klods-row--gap-#{$i},
81
+ .klods-grid--gap-#{$i} {
82
+ gap: var(--klods-space-#{$i});
83
+ }
84
+ }
85
+
86
+ // Padding helpers
87
+ @for $i from 0 through 8 {
88
+ .klods-pad-#{$i} {
89
+ padding: var(--klods-space-#{$i});
90
+ }
91
+ }
92
+
93
+ // Visually hidden (for a11y)
94
+ .klods-sr-only {
95
+ position: absolute;
96
+ width: 1px;
97
+ height: 1px;
98
+ padding: 0;
99
+ margin: -1px;
100
+ overflow: hidden;
101
+ clip: rect(0, 0, 0, 0);
102
+ white-space: nowrap;
103
+ border: 0;
104
+ }
105
+ }
package/src/klods.scss ADDED
@@ -0,0 +1,10 @@
1
+ // klods.scss — single entry point. All output is layered so consumer styles can
2
+ // always override without specificity wars.
3
+
4
+ @use "layers";
5
+ @use "reset";
6
+ @use "tokens";
7
+ @use "themes";
8
+ @use "layout";
9
+ @use "components";
10
+ @use "utilities";