@kolkrabbi/kol-theme 0.50.2 → 0.52.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.
@@ -17,7 +17,13 @@
17
17
  * Dark selector matches brand's mechanism: [data-theme="dark"], .dark.
18
18
  */
19
19
 
20
- :root {
20
+ /* LIGHT is declared on the theme selectors too, not `:root` alone (0.52.0,
21
+ * nested-theme-scope): a `data-theme="light"` / `.light` SUBTREE inside a dark
22
+ * app must carry the light surfaces on its own element, or it inherits the
23
+ * root's dark values. `:root` still matches, so root-level theming and the
24
+ * system-follow mirror below are untouched. */
25
+ :root,
26
+ :is([data-theme="light"], .light) {
21
27
  /* Absolutes (theme-invariant) */
22
28
  --kol-color-absolute-white: #ffffff;
23
29
  --kol-color-absolute-black: #000000;
package/kol-color.css CHANGED
@@ -89,8 +89,6 @@
89
89
  * BORDER
90
90
  * --------------------------------------------------------------------------- */
91
91
 
92
- --kol-border-default: color-mix(in srgb, var(--kol-surface-on-primary) 8%, transparent);
93
- --kol-border-focus: color-mix(in srgb, var(--kol-accent-primary) 70%, var(--kol-surface-on-primary));
94
92
  --kol-focus-ring: var(--kol-accent-primary);
95
93
  /* The QUIET ring — 1px, inset, for dense rows where the loud ring's 2px
96
94
  * offset would bloom over its neighbours (nav rail leaves today).
@@ -105,6 +103,21 @@
105
103
  * Default is --kol-fg-32, exactly what the rails already drew, so minting
106
104
  * this changes NOTHING visually. Both rings are white (--kol-accent-primary
107
105
  * resolves to --kol-surface-on-primary); the two differ in weight, not hue. */
106
+ }
107
+
108
+ /* SURFACE-DERIVED chrome tokens live on the THEME selectors, not `:root` alone
109
+ * (0.52.0, nested-theme-scope) — same reason as the fg ramp in kol-opacity.css:
110
+ * a var() resolves where the property is declared, so a themed SUBTREE that
111
+ * flips --kol-surface-on-primary kept the root's border colour (a white 8%
112
+ * hairline on white paper). The accent family stays in the :root block above
113
+ * on purpose: kol-brand-color.css rebinds it at :root only, and a themed
114
+ * re-declaration here would hand a branded app's nested pane the neutral
115
+ * ink accent instead of the brand. */
116
+ :root,
117
+ :is([data-theme="light"], .light),
118
+ :is([data-theme="dark"], .dark) {
119
+ --kol-border-default: color-mix(in srgb, var(--kol-surface-on-primary) 8%, transparent);
120
+ --kol-border-focus: color-mix(in srgb, var(--kol-accent-primary) 70%, var(--kol-surface-on-primary));
108
121
  --kol-focus-ring-quiet: var(--kol-fg-32);
109
122
  }
110
123
 
@@ -474,10 +474,28 @@
474
474
  background-color: transparent;
475
475
  color: var(--kol-surface-on-primary);
476
476
  cursor: pointer;
477
+ position: relative; /* the bare variant's hit extent below anchors here */
477
478
  transition: background-color var(--kol-transition-base),
478
479
  border-color var(--kol-transition-base);
479
480
  }
480
481
 
482
+ /* THE TOUCH FLOOR (MobileTouchFloor, user ruling 2026-08-26): every pressable
483
+ * control clears a 24px hit box (WCAG 2.5.8 AA) and the DRAWN size never
484
+ * moves. No type floor — 10px chrome is the ruled helper/mono-10 voice. Two
485
+ * controls sat under 24: this bare switch (a 12px track in a 1px border, 14px
486
+ * tall) and the Slider's range input below (a 2px track was the whole target).
487
+ * The shells ride button geometry (26/32/40) and already clear it. The extent
488
+ * is a pseudo-element, so the layout box, the label and the track stay where
489
+ * they are; hit-testing on a pseudo lands on its originating button. */
490
+ .toggle-switch--bare::before {
491
+ content: '';
492
+ position: absolute;
493
+ inset-inline: 0;
494
+ top: 50%;
495
+ height: 24px;
496
+ translate: 0 -50%;
497
+ }
498
+
481
499
  .toggle-switch:focus-visible {
482
500
  outline: 2px solid var(--kol-focus-ring);
483
501
  outline-offset: 2px;
@@ -626,7 +644,12 @@
626
644
  appearance: none;
627
645
  background: transparent;
628
646
  cursor: pointer;
629
- height: 2px;
647
+ /* 24px, not 2px (the touch floor, user ruling 2026-08-26 — see ToggleSwitch
648
+ * above). The INPUT is the hit target and it was exactly the track's 2px;
649
+ * the drawing is unchanged: the 2px track centres inside the box by the UA's
650
+ * own `align-self: center` on the runnable track, and the thumb stays pinned
651
+ * to the track. The row (.control-slider) is already 24px, so nothing moves. */
652
+ height: 24px;
630
653
  }
631
654
 
632
655
  .slider-black::-webkit-slider-runnable-track {
package/kol-opacity.css CHANGED
@@ -25,7 +25,16 @@
25
25
  * alias over one fg-* stop. `default` is a deprecated alias of `body`.
26
26
  */
27
27
 
28
- :root {
28
+ /* Declared on the THEME selectors, not `:root` alone (0.52.0, nested-theme-
29
+ * scope). A custom property resolves its var() where it is DECLARED and
30
+ * descendants inherit the frozen result — a ramp declared only on :root bakes
31
+ * the root's ink, so a subtree that flips --kol-surface-on-primary
32
+ * (data-theme / .light / .dark on a div) kept the root's --kol-fg-*.
33
+ * Re-declaring on the theme selectors re-resolves the ramp on the themed
34
+ * element itself — the mechanism .bg-surface-inverse already uses. */
35
+ :root,
36
+ :is([data-theme="light"], .light),
37
+ :is([data-theme="dark"], .dark) {
29
38
  /* ============================================================================
30
39
  * TOKENS — Standard tier (foreground on primary surface)
31
40
  * ============================================================================ */
@@ -374,7 +383,11 @@
374
383
  * descriptors are aliases, never their own colour values.
375
384
  * ============================================================================== */
376
385
 
377
- :root {
386
+ /* Theme selectors, same reason as the ramp above — the roles chain through
387
+ * fg-* and freeze the same way. */
388
+ :root,
389
+ :is([data-theme="light"], .light),
390
+ :is([data-theme="dark"], .dark) {
378
391
  --kol-fg-subtle: var(--kol-fg-24);
379
392
  --kol-fg-meta: var(--kol-fg-48);
380
393
  --kol-fg-body: var(--kol-fg-64);
package/kol-opaque.css CHANGED
@@ -13,7 +13,9 @@
13
13
  * transparency, it is a baked grey.
14
14
  *
15
15
  * Auto-themes for free: --kol-surface-on-primary and --kol-surface-primary both
16
- * flip in dark mode, so color-mix recomputes. No hardcoded light/dark blocks.
16
+ * flip in dark mode, so color-mix recomputes. No hardcoded light/dark blocks
17
+ * but the block is declared on the theme selectors, not `:root` alone (0.52.0,
18
+ * nested-theme-scope), so a themed SUBTREE recomputes too; see kol-opacity.css.
17
19
  *
18
20
  * Scale: 01, 02, 04, 08, 12, 16, 24, 32, 40, 48, 64, 80, 88, 96 (14 stops)
19
21
  *
@@ -26,7 +28,9 @@
26
28
  * - Classes (.bg-oq-*, .text-oq-*, .border-oq-* + inverse + hover) for JSX
27
29
  */
28
30
 
29
- :root {
31
+ :root,
32
+ :is([data-theme="light"], .light),
33
+ :is([data-theme="dark"], .dark) {
30
34
  /* ============================================================================
31
35
  * TOKENS — Standard tier (ink-on-primary, flattened onto primary surface)
32
36
  * ============================================================================ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-theme",
3
- "version": "0.50.2",
3
+ "version": "0.52.0",
4
4
  "description": "KOL (Kolkrabbi) design-system tokens + base CSS — brand-neutral. The canonical token/cascade layer every other KOL package and consumer builds on.",
5
5
  "license": "MIT",
6
6
  "type": "module",