@kolkrabbi/kol-theme 0.1.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.
@@ -0,0 +1,709 @@
1
+ /**
2
+ * KOL components — atom tier
3
+ *
4
+ * Shared chrome primitive for interactive controls. Every chromed control
5
+ * (Input, Stepper, Dropdown trigger, ViewToggle option, etc.) composes
6
+ * from these classes instead of reinventing bg/border/padding/transitions.
7
+ *
8
+ * ─────────────────────────────────────────────────────────────────────
9
+ * .kol-control — control shell primitive
10
+ * ─────────────────────────────────────────────────────────────────────
11
+ *
12
+ * Apply: <div class="kol-control kol-control--{variant} kol-control-{size} kol-mono-{N}">
13
+ *
14
+ * Always:
15
+ * .kol-control base (transition, radius 4px, layout border)
16
+ *
17
+ * Variant (visual treatment) — pick one:
18
+ * .kol-control--filled persistent solid bg
19
+ * (Input filled, Stepper, ViewToggle active)
20
+ * .kol-control--ghost transparent at rest, border reveals on
21
+ * hover / focus-within
22
+ * (Input ghost, hex chip, inline editable)
23
+ * .kol-control--outline bordered, transparent bg
24
+ * (Dropdown default trigger, segmented bar,
25
+ * also: forced-reveal "is-edited" state on
26
+ * what would otherwise be a ghost)
27
+ *
28
+ * Size (padding + matched type class) — pick one:
29
+ * .kol-control-sm padding 4px 12px → pair w/ kol-mono-12
30
+ * .kol-control-md padding 6px 16px → pair w/ kol-mono-14
31
+ * .kol-control-lg padding 8px 20px → pair w/ kol-mono-16
32
+ *
33
+ * State:
34
+ * [aria-disabled="true"] /
35
+ * :disabled auto opacity-50 + pointer-events-none
36
+ *
37
+ * Single visible-border tone (--kol-fg-16). No hover/focus escalation,
38
+ * no `--bordered` modifier. When you want a ghost field to render
39
+ * persistently visible (e.g. "is-edited" indicator), switch the variant
40
+ * to `--outline` — same visual, clearer semantic.
41
+ *
42
+ * Type class is JSX-applied (`kol-mono-12 / -14 / -16`) — the shell controls
43
+ * spacing + chrome, the type class controls font. Two reasons: (1) the type
44
+ * system is a separate locked surface (typography.js), and (2) consumers can
45
+ * override the type class for one-off cases (e.g. uppercase labels in helpers)
46
+ * without forking the size variant.
47
+ *
48
+ * Radius is hard-coded to var(--kol-radius-sm) (4px). Repo invariant — never
49
+ * exceed 4px.
50
+ */
51
+
52
+ .kol-control {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ border-radius: var(--kol-radius-sm);
56
+ border: 1px solid transparent;
57
+ transition: background-color 150ms ease,
58
+ border-color 150ms ease,
59
+ color 150ms ease;
60
+ cursor: pointer;
61
+ }
62
+
63
+ /* ─── Variants ─── */
64
+
65
+ .kol-control--filled {
66
+ background-color: var(--kol-surface-secondary);
67
+ color: var(--kol-surface-on-primary);
68
+ }
69
+
70
+ .kol-control--ghost {
71
+ /* Subtle resting bg so the input bounds are discoverable without
72
+ * hovering. Theme-independent darken via fg-absolute-04 (4% black);
73
+ * on dark theme this reads as a softly sunken input area, on light
74
+ * theme as a faintly tinted field. Hover/focus then reveals the
75
+ * border for affordance. */
76
+ background-color: var(--kol-fg-absolute-04);
77
+ color: var(--kol-fg-meta);
78
+ }
79
+ .kol-control--ghost:hover,
80
+ .kol-control--ghost:focus-within {
81
+ border-color: var(--kol-fg-16);
82
+ color: var(--kol-surface-on-primary);
83
+ }
84
+
85
+ .kol-control--outline {
86
+ background-color: transparent;
87
+ color: var(--kol-surface-on-primary);
88
+ border-color: var(--kol-fg-16);
89
+ }
90
+
91
+ /* Textarea modifier — flips the inline-flex shell to block so a multi-line
92
+ * textarea takes full width. Resize is disabled (textarea is fixed at its
93
+ * `rows` count, content scrolls). The kol resize-corner icon in the
94
+ * bottom-right is decorative. Used by atoms/Textarea.jsx. */
95
+ .kol-control--textarea {
96
+ display: block;
97
+ position: relative;
98
+ padding: 0; /* outer label is purely a wrapper; inner textarea owns padding */
99
+ }
100
+ .kol-control--textarea > textarea {
101
+ padding: 4px 12px;
102
+ }
103
+ .kol-control--textarea.kol-control-md > textarea { padding: 6px 16px; }
104
+ .kol-control--textarea.kol-control-lg > textarea { padding: 8px 20px; }
105
+ .kol-textarea-resize-icon {
106
+ position: absolute;
107
+ bottom: 4px;
108
+ right: 4px;
109
+ display: inline-flex;
110
+ }
111
+
112
+ /* ─── Sizes (padding only — type class applied via JSX) ─── */
113
+
114
+ .kol-control-sm { padding: 4px 12px; }
115
+ .kol-control-md { padding: 6px 16px; }
116
+ .kol-control-lg { padding: 8px 20px; }
117
+
118
+ /* ─── Disabled ─── */
119
+
120
+ .kol-control[aria-disabled="true"],
121
+ .kol-control:disabled,
122
+ .kol-control:has(:disabled) {
123
+ opacity: 0.5;
124
+ pointer-events: none;
125
+ }
126
+
127
+
128
+ /* ═══════════════════════════════════════════════════════════════
129
+ * Button — atoms/Button.jsx
130
+ *
131
+ * Variants:
132
+ * .kol-btn-primary subtle bg-fg-04 fill, daily chrome (default)
133
+ * .kol-btn-secondary heavy inverted ink, CTA-adjacent (font-weight 500)
134
+ * .kol-btn-accent brand-yellow filled CTA (font-weight 500)
135
+ * .kol-btn-outline bordered, transparent bg
136
+ *
137
+ * Sizes (padding shared with .kol-control):
138
+ * .kol-btn-sm 4px 12px → kol-mono-12
139
+ * .kol-btn-md 6px 16px → kol-mono-14
140
+ * .kol-btn-lg 8px 20px → kol-mono-16
141
+ *
142
+ * Modifiers:
143
+ * .kol-btn-animate disables default hover states (consumer drives)
144
+ * :disabled opacity-disabled + not-allowed cursor
145
+ *
146
+ * Type: applied via .kol-mono-{12,14,16} on the size variant in JSX.
147
+ * No uppercase / capitalize — author strings in the case they should
148
+ * render (per ARCHITECTURE.md §2). Radius hard 4px (--kol-radius-sm).
149
+ * ═══════════════════════════════════════════════════════════════ */
150
+
151
+ .kol-btn {
152
+ display: inline-flex;
153
+ align-items: center;
154
+ justify-content: center;
155
+ border-radius: var(--kol-radius-sm);
156
+ white-space: nowrap;
157
+ transition: background-color var(--kol-transition-base),
158
+ color var(--kol-transition-base),
159
+ border-color var(--kol-transition-base);
160
+ cursor: pointer;
161
+ }
162
+
163
+ .kol-btn-primary {
164
+ background: var(--kol-surface-secondary);
165
+ color: var(--kol-surface-on-primary);
166
+ border: 1px solid transparent;
167
+ }
168
+ .kol-btn-primary:not(.kol-btn-animate):hover {
169
+ background-color: var(--kol-fg-08);
170
+ color: var(--kol-surface-on-primary);
171
+ }
172
+
173
+ .kol-btn-secondary {
174
+ background: var(--kol-surface-on-primary);
175
+ color: var(--kol-surface-primary);
176
+ border: 1px solid transparent;
177
+ font-weight: 500;
178
+ }
179
+ .kol-btn-secondary:not(.kol-btn-animate):hover {
180
+ background-color: color-mix(in srgb, var(--kol-surface-on-primary) 20%, transparent);
181
+ color: var(--kol-surface-on-primary);
182
+ border-color: transparent;
183
+ }
184
+
185
+ .kol-btn-accent {
186
+ background: var(--kol-accent-primary);
187
+ color: var(--kol-accent-on-primary);
188
+ border: 1px solid transparent;
189
+ font-weight: 500;
190
+ }
191
+ .kol-btn-accent:not(.kol-btn-animate):hover {
192
+ background-color: var(--kol-accent-primary-strong);
193
+ color: var(--kol-accent-on-primary);
194
+ }
195
+
196
+ .kol-btn-outline {
197
+ background: transparent;
198
+ color: var(--kol-surface-on-primary);
199
+ border: 1px solid var(--kol-fg-16);
200
+ }
201
+ .kol-btn-outline:not(.kol-btn-animate):hover {
202
+ background-color: var(--kol-fg-08);
203
+ border-color: color-mix(in srgb, var(--kol-surface-on-primary) 25%, transparent);
204
+ color: var(--kol-surface-on-primary);
205
+ }
206
+
207
+ .kol-btn-ghost {
208
+ background: transparent;
209
+ color: var(--kol-fg-48);
210
+ border: 1px solid transparent;
211
+ }
212
+ .kol-btn-ghost:not(.kol-btn-animate):hover {
213
+ background-color: var(--kol-fg-08);
214
+ color: var(--kol-surface-on-primary);
215
+ }
216
+
217
+ .kol-btn-sm { padding: 4px 12px; }
218
+ .kol-btn-md { padding: 6px 16px; }
219
+ .kol-btn-lg { padding: 8px 20px; }
220
+
221
+ .kol-btn:disabled,
222
+ .kol-btn[disabled] {
223
+ opacity: var(--kol-opacity-disabled);
224
+ cursor: not-allowed;
225
+ }
226
+
227
+ .kol-btn-animate {
228
+ /* Consumer-driven hover behavior; disables default :hover rules above. */
229
+ }
230
+
231
+ /* .kol-btn-quiet — secondary-action icon button: dimmed at rest, brightens
232
+ * on hover, stays dimmed when disabled (no hover lift on a non-actionable
233
+ * state). For icon-only buttons in panel chrome (add layer, delete, etc.)
234
+ * that shouldn't compete with primary content visually. */
235
+ .kol-btn-quiet {
236
+ opacity: var(--kol-opacity-disabled);
237
+ transition: opacity 150ms ease;
238
+ }
239
+ .kol-btn-quiet:not(:disabled):hover {
240
+ opacity: 1;
241
+ }
242
+
243
+ /* Icon-swap animation (Button.jsx iconLeft / iconRight with hover icon) */
244
+
245
+ .kol-icon-swap-container {
246
+ position: relative;
247
+ display: inline-flex;
248
+ overflow: hidden;
249
+ }
250
+
251
+ .kol-icon-default {
252
+ position: absolute;
253
+ transition: opacity var(--kol-transition-base),
254
+ transform var(--kol-transition-base);
255
+ }
256
+
257
+ .kol-icon-hover {
258
+ position: absolute;
259
+ opacity: 0;
260
+ transform: translateY(4px);
261
+ transition: opacity var(--kol-transition-base),
262
+ transform var(--kol-transition-base);
263
+ }
264
+
265
+ .kol-btn:hover .kol-icon-default {
266
+ opacity: 0;
267
+ transform: translateY(-4px);
268
+ }
269
+
270
+ .kol-btn:hover .kol-icon-hover {
271
+ opacity: 1;
272
+ transform: translateY(0);
273
+ }
274
+
275
+
276
+ /* ═══════════════════════════════════════════════════════════════
277
+ * Toggle Bracket — molecules/ToggleBracket.jsx
278
+ *
279
+ * Default-variant chrome comes from .kol-control--filled. The active
280
+ * state overrides bg + color via this modifier — preserves the
281
+ * accent-yellow identity while the rest of the chrome stays shell.
282
+ * Plain variant is bare-text with no shell (defined inline in JSX).
283
+ * ═══════════════════════════════════════════════════════════════ */
284
+
285
+ .toggle-bracket--active {
286
+ background-color: var(--kol-accent-primary);
287
+ color: var(--kol-accent-on-primary);
288
+ }
289
+
290
+
291
+ /* ═══════════════════════════════════════════════════════════════
292
+ * Toggle Switch — atoms/ToggleSwitch.jsx
293
+ *
294
+ * Custom-shape control (not shell-based — slidey indicator geometry).
295
+ * Default + plain variants. ON state inverts: pill bg
296
+ * absolute-white, indicator absolute-black (theme-invariant).
297
+ * ═══════════════════════════════════════════════════════════════ */
298
+
299
+ .toggle-switch {
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: space-between;
303
+ gap: 12px;
304
+ padding: 10px 14px;
305
+ border-radius: 4px;
306
+ border: 1px solid color-mix(in srgb, var(--kol-surface-on-primary) 12%, transparent);
307
+ background-color: transparent;
308
+ color: var(--kol-surface-on-primary);
309
+ transition: background-color var(--kol-transition-base),
310
+ border-color var(--kol-transition-base);
311
+ }
312
+
313
+ .toggle-switch:hover,
314
+ .toggle-switch:focus-visible {
315
+ border-color: color-mix(in srgb, var(--kol-surface-on-primary) 18%, transparent);
316
+ }
317
+
318
+ .toggle-switch-label {
319
+ font-family: var(--kol-font-family-mono);
320
+ font-size: 11px;
321
+ text-transform: uppercase;
322
+ letter-spacing: 0.08em;
323
+ }
324
+
325
+ .toggle-switch-indicator {
326
+ width: 20px;
327
+ height: 12px;
328
+ border-radius: var(--kol-radius-full);
329
+ background-color: color-mix(in srgb, var(--kol-surface-on-primary) 16%, transparent);
330
+ position: relative;
331
+ transition: background-color var(--kol-transition-base);
332
+ }
333
+
334
+ .toggle-switch-indicator::after {
335
+ content: '';
336
+ position: absolute;
337
+ top: 2px;
338
+ left: 2px;
339
+ width: 8px;
340
+ height: 8px;
341
+ border-radius: var(--kol-radius-full);
342
+ background-color: var(--kol-surface-primary);
343
+ transition: transform var(--kol-transition-base),
344
+ background-color var(--kol-transition-base);
345
+ }
346
+
347
+ .toggle-switch[data-state='on'] .toggle-switch-indicator {
348
+ background-color: var(--kol-color-absolute-white);
349
+ }
350
+
351
+ .toggle-switch[data-state='on'] .toggle-switch-indicator::after {
352
+ transform: translateX(8px);
353
+ background-color: var(--kol-color-absolute-black);
354
+ }
355
+
356
+ .toggle-switch--plain {
357
+ padding: 0;
358
+ border: none;
359
+ background-color: transparent;
360
+ }
361
+
362
+ .toggle-switch--plain:hover,
363
+ .toggle-switch--plain:focus-visible {
364
+ background-color: transparent;
365
+ border-color: transparent;
366
+ }
367
+
368
+
369
+ /* ═══════════════════════════════════════════════════════════════
370
+ * Toggle Checkbox — atoms/ToggleCheckbox.jsx
371
+ *
372
+ * Custom-shape control. Active state inverts: box bg absolute-white,
373
+ * no border, check stroke absolute-black (theme-invariant).
374
+ * ═══════════════════════════════════════════════════════════════ */
375
+
376
+ .toggle-checkbox {
377
+ display: inline-flex;
378
+ align-items: center;
379
+ gap: 8px;
380
+ cursor: pointer;
381
+ }
382
+
383
+ .toggle-checkbox input {
384
+ display: none;
385
+ }
386
+
387
+ .toggle-checkbox-indicator {
388
+ display: inline-flex;
389
+ align-items: center;
390
+ justify-content: center;
391
+ width: 16px;
392
+ height: 16px;
393
+ border-radius: 3px;
394
+ border: 1px solid color-mix(in srgb, var(--kol-surface-on-primary) 25%, transparent);
395
+ background-color: transparent;
396
+ transition: background-color var(--kol-transition-base),
397
+ border-color var(--kol-transition-base);
398
+ }
399
+
400
+ .toggle-checkbox-indicator svg {
401
+ width: 10px;
402
+ height: 8px;
403
+ stroke: var(--kol-color-absolute-black);
404
+ opacity: 0;
405
+ transition: opacity var(--kol-transition-base);
406
+ }
407
+
408
+ .toggle-checkbox.is-active .toggle-checkbox-indicator {
409
+ background-color: var(--kol-color-absolute-white);
410
+ border-color: transparent;
411
+ }
412
+
413
+ .toggle-checkbox.is-active .toggle-checkbox-indicator svg {
414
+ opacity: 1;
415
+ }
416
+
417
+
418
+ /* ═══════════════════════════════════════════════════════════════
419
+ * Slider — atoms/Slider.jsx
420
+ *
421
+ * Range-input with custom track + thumb pseudo-elements. Two variants
422
+ * post-2026-04-30 restructure (bordered `default` retired):
423
+ *
424
+ * default bare track + boxed value (was `minimal`). Most-used —
425
+ * Pattern Lab cols/rows/gap, Compositor sliders, Type Lab.
426
+ * subtle filled rounded chip — for inspector-style controls.
427
+ *
428
+ * Track color is exposed as `--kol-slider-track` (set on `.slider-black`)
429
+ * so consumers can override per-instance via inline style or className.
430
+ * Default = fg-64 (dim grey); subtle overrides to full ink.
431
+ * ═══════════════════════════════════════════════════════════════ */
432
+
433
+ .control-slider {
434
+ display: inline-flex;
435
+ flex-direction: row;
436
+ align-items: center;
437
+ padding: 0;
438
+ border-radius: 0;
439
+ background-color: transparent;
440
+ border: none;
441
+ height: 24px;
442
+ transition: color var(--kol-transition-base);
443
+ }
444
+
445
+ .control-slider label { color: var(--kol-fg-80); }
446
+ .control-slider span {
447
+ color: var(--kol-surface-on-primary);
448
+ padding: 8px 0;
449
+ border-radius: 4px;
450
+ background-color: var(--kol-surface-secondary);
451
+ width: 64px;
452
+ text-align: center;
453
+ flex-shrink: 0;
454
+ }
455
+
456
+ .control-slider-subtle {
457
+ display: inline-flex;
458
+ flex-direction: row;
459
+ align-items: center;
460
+ padding: 6px 16px;
461
+ border-radius: 4px;
462
+ background-color: var(--kol-surface-secondary);
463
+ border: none;
464
+ transition: background-color var(--kol-transition-base),
465
+ color var(--kol-transition-base);
466
+ }
467
+
468
+ .control-slider-subtle label {
469
+ color: var(--kol-fg-48);
470
+ }
471
+
472
+ .control-slider-subtle .slider-black {
473
+ --kol-slider-track: var(--kol-surface-on-primary);
474
+ }
475
+
476
+ .slider-black {
477
+ --kol-slider-track: var(--kol-fg-64);
478
+ -webkit-appearance: none;
479
+ appearance: none;
480
+ background: transparent;
481
+ cursor: pointer;
482
+ height: 2px;
483
+ }
484
+
485
+ .slider-black::-webkit-slider-runnable-track {
486
+ background: var(--kol-slider-track);
487
+ height: 2px;
488
+ border-radius: 0;
489
+ }
490
+
491
+ .slider-black::-moz-range-track {
492
+ background: var(--kol-slider-track);
493
+ height: 2px;
494
+ border-radius: 0;
495
+ }
496
+
497
+ .slider-black::-webkit-slider-thumb {
498
+ -webkit-appearance: none;
499
+ appearance: none;
500
+ background: var(--kol-surface-on-primary);
501
+ height: 12px;
502
+ width: 12px;
503
+ border-radius: 50%;
504
+ margin-top: -5px;
505
+ border: none;
506
+ }
507
+
508
+ .slider-black::-moz-range-thumb {
509
+ appearance: none;
510
+ background: var(--kol-surface-on-primary);
511
+ height: 12px;
512
+ width: 12px;
513
+ border-radius: 50%;
514
+ border: none;
515
+ }
516
+
517
+
518
+ /* ═══════════════════════════════════════════════════════════════
519
+ * Sidenav primitives — promoted from kol-framework.css 2026-04-30.
520
+ *
521
+ * .kol-sidenav-hop row primitive (icon + label, full-width)
522
+ * .kol-sidenav-hop-icon icon slot inside the hop
523
+ * .kol-sidenav-hop-label label slot — collapses to display:none in
524
+ * rail mode (responsive cascade in framework.css)
525
+ * .kol-sidenav-link nav link with active-dot indicator
526
+ * .kol-sidenav-group small vertical wrapper
527
+ *
528
+ * Layout/sizing/responsive collapse rules stay in kol-framework.css
529
+ * (they're page-grid concerns, not component chrome).
530
+ * ═══════════════════════════════════════════════════════════════ */
531
+
532
+ .kol-sidenav-hop {
533
+ color: var(--kol-fg-80);
534
+ text-transform: uppercase;
535
+ letter-spacing: 0.06em;
536
+ transition: color 150ms ease, background 150ms ease;
537
+ }
538
+
539
+ .kol-sidenav-hop:hover {
540
+ color: var(--kol-fg-96);
541
+ }
542
+
543
+ .kol-sidenav-hop.is-active {
544
+ color: var(--kol-surface-on-primary);
545
+ }
546
+
547
+ .kol-sidenav-hop-icon {
548
+ color: var(--kol-fg-80);
549
+ transition: color 150ms ease;
550
+ }
551
+
552
+ .kol-sidenav-hop:hover .kol-sidenav-hop-icon {
553
+ color: var(--kol-surface-on-primary);
554
+ }
555
+
556
+ .kol-sidenav-hop.is-active .kol-sidenav-hop-icon {
557
+ color: var(--kol-accent-primary);
558
+ }
559
+
560
+ .kol-sidenav-group {
561
+ padding: 4px 0 4px;
562
+ }
563
+
564
+ .kol-sidenav-link.is-active {
565
+ color: var(--kol-surface-on-primary);
566
+ }
567
+
568
+ .kol-sidenav-link.is-active::before {
569
+ content: "";
570
+ position: absolute;
571
+ left: var(--kol-sidenav-dot-left, 2px);
572
+ top: 50%;
573
+ transform: translateY(-50%);
574
+ width: 4px;
575
+ height: 4px;
576
+ border-radius: 50%;
577
+ background: var(--kol-accent-primary);
578
+ }
579
+
580
+
581
+ /* ═══════════════════════════════════════════════════════════════
582
+ * Page section divider — promoted from kol-framework.css.
583
+ * Helper class on the Divider atom when used as a PageSection lead-in.
584
+ * Hides on the first PageSection of a page.
585
+ * ═══════════════════════════════════════════════════════════════ */
586
+
587
+ .kol-page-section-divider {
588
+ margin-top: -64px;
589
+ margin-bottom: 64px;
590
+ }
591
+
592
+ .kol-page-section:first-of-type > .kol-page-section-divider {
593
+ display: none;
594
+ }
595
+
596
+
597
+ /* ═══════════════════════════════════════════════════════════════
598
+ * Section label typography — promoted from residual kol-components.css.
599
+ * Used by molecules/SectionLabel.jsx. Mono variants + compact variants.
600
+ * Typography-adjacent; lives here because consumed by atom-tier
601
+ * components (SectionLabel etc.).
602
+ * ═══════════════════════════════════════════════════════════════ */
603
+
604
+ .kol-label-mono-sm {
605
+ font-family: var(--kol-font-family-mono);
606
+ font-weight: 470;
607
+ font-size: clamp(14px, 1.5vw, 24px);
608
+ line-height: 100%;
609
+ text-transform: uppercase;
610
+ letter-spacing: 0.05em;
611
+ color: var(--kol-surface-on-primary);
612
+ }
613
+
614
+ .kol-label-mono-md {
615
+ font-family: var(--kol-font-family-mono);
616
+ font-weight: 470;
617
+ font-size: clamp(12px, 1vw, 16px);
618
+ line-height: 125%;
619
+ text-transform: uppercase;
620
+ letter-spacing: 0.05em;
621
+ color: var(--kol-surface-on-primary);
622
+ }
623
+
624
+ .kol-label-mono-xs {
625
+ font-family: var(--kol-font-family-mono);
626
+ font-weight: 470;
627
+ font-size: clamp(10px, 0.8vw, 14px);
628
+ line-height: 100%;
629
+ text-transform: uppercase;
630
+ letter-spacing: 0.05em;
631
+ color: var(--kol-surface-on-primary);
632
+ }
633
+
634
+ .kol-label-compact-lg {
635
+ font-family: var(--kol-font-family-mono);
636
+ font-weight: 500;
637
+ font-size: clamp(24px, 2vw, 28px);
638
+ line-height: 100%;
639
+ text-transform: uppercase;
640
+ letter-spacing: 0.03em;
641
+ color: var(--kol-surface-on-primary);
642
+ }
643
+
644
+ .kol-label-compact-md {
645
+ font-family: var(--kol-font-family-mono);
646
+ font-weight: 500;
647
+ font-size: clamp(12px, 1vw, 16px);
648
+ line-height: 100%;
649
+ text-transform: uppercase;
650
+ letter-spacing: 0.03em;
651
+ color: var(--kol-surface-on-primary);
652
+ }
653
+
654
+ .kol-label {
655
+ font-family: var(--kol-font-family-mono);
656
+ font-weight: 470;
657
+ font-size: clamp(14px, 1.5vw, 24px);
658
+ line-height: 100%;
659
+ text-transform: uppercase;
660
+ letter-spacing: 0.05em;
661
+ color: var(--kol-surface-on-primary);
662
+ }
663
+
664
+ .kol-label-compact {
665
+ font-family: var(--kol-font-family-mono);
666
+ font-weight: 500;
667
+ font-size: clamp(12px, 1vw, 16px);
668
+ line-height: 100%;
669
+ text-transform: uppercase;
670
+ letter-spacing: 0.03em;
671
+ color: var(--kol-surface-on-primary);
672
+ }
673
+
674
+
675
+ /* ═══════════════════════════════════════════════════════════════
676
+ * Icon-swap utility — promoted from residual kol-components.css.
677
+ * Used by molecules/SectionLabel.jsx and any <button>/<a> with
678
+ * .icon-default / .icon-hover children.
679
+ * (Distinct from .kol-icon-swap-* used internally by atoms/Button.jsx
680
+ * — see Button section above.)
681
+ * ═══════════════════════════════════════════════════════════════ */
682
+
683
+ .icon-default {
684
+ transform: translate(0, 0) scale(1);
685
+ opacity: 1;
686
+ transition: transform var(--kol-transition-base) ease,
687
+ opacity var(--kol-transition-base) ease;
688
+ }
689
+
690
+ .icon-hover {
691
+ transform: translate(-100%, -100%) scale(0.8);
692
+ opacity: 0;
693
+ transition: transform var(--kol-transition-base) ease,
694
+ opacity var(--kol-transition-base) ease;
695
+ }
696
+
697
+ button:hover .icon-default,
698
+ a:hover .icon-default,
699
+ .section-label-wrapper:hover .icon-default {
700
+ transform: translate(100%, 100%) scale(0.8);
701
+ opacity: 0;
702
+ }
703
+
704
+ button:hover .icon-hover,
705
+ a:hover .icon-hover,
706
+ .section-label-wrapper:hover .icon-hover {
707
+ transform: translate(0, 0) scale(1);
708
+ opacity: 1;
709
+ }