@kolkrabbi/kol-theme 0.130.0 → 0.132.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.
package/kol-animation.css CHANGED
@@ -333,8 +333,9 @@
333
333
  * kol-component's `utilities/motion.js`, GRAB); `clamp()` holds it half its own
334
334
  * length from either end so it stops flush, never past.
335
335
  *
336
- * Longer and finer than the ColumnBrowser's 3 × 32 on a rail it should read
337
- * as a thickening of the line, not a tab stuck to it. The fade is long and
336
+ * Fine and long it should read as a thickening of the line, not a tab stuck
337
+ * to it. (This said "longer and finer than the ColumnBrowser's 3 × 32" until
338
+ * 2026-09-02; that handle takes the same 0.125 × 4.5rem now.) The fade is long and
338
339
  * unhurried at BOTH ends on a symmetric in-out: an ease-out popped the first
339
340
  * 20 % and crawled the rest, which the user read as a jerk.
340
341
  * ═════════════════════════════════════════════════════════════════════ */
@@ -370,6 +371,18 @@
370
371
  .kol-rail-grab::before { transition: none; }
371
372
  }
372
373
 
374
+ /* The ColumnBrowser's two handles wear the SAME pill (BrowsePageRulingsAndSeams,
375
+ * kol-r2b2 2026-09-02, user ruling) — `useGrabEdge` drives both. Their geometry
376
+ * and placement differ and stay with the component in
377
+ * kol-components-molecules.css (the strips sit INSIDE the border they grab, and
378
+ * there are two axes); only the reduced-motion cut belongs here, with every
379
+ * other one. The 08-28 note on the rail's pill — "Longer and finer than the
380
+ * ColumnBrowser's 3 × 32" — is stale: they are the same 0.125 × 4.5rem now. */
381
+ @media (prefers-reduced-motion: reduce) {
382
+ .kol-column-browser-resize-x::before,
383
+ .kol-column-browser-resize-y::before { transition: none; }
384
+ }
385
+
373
386
  /* ═════════════════════════════════════════════════════════════════════
374
387
  * SCROLL ENTRANCE — the reveal family (promoted from kol-website's
375
388
  * apps/web/src/styles/animations.css, 2026-08-28, on the user's "it's good to
@@ -133,7 +133,7 @@
133
133
  * sm (12px in 26–28), which is the one reason the rack's TextInput / Dropdown /
134
134
  * Selector could not collapse onto Input / Dropdown / Stepper. xs = kol-mono-8
135
135
  * (line-height 12) + 4px vertical + the shell's 1px ring = 22px, 8px sides,
136
- * the xs radius; the icon-only square is 20.
136
+ * the xs radius; the icon-only square is 22, the same height (2026-09-02).
137
137
  * Opt-in by prop only — the 2026-07-28 "dropdowns are sm at every viewport"
138
138
  * law is untouched; nothing ramps to xs by viewport. */
139
139
  .kol-control-xs { padding: 4px 8px; border-radius: var(--kol-radius-xs); }
@@ -261,13 +261,23 @@
261
261
  line-height: 0;
262
262
  }
263
263
  /* Icon-only is a GEOMETRY condition, not a variant (2026-07-28, user-ordered):
264
- * a lone glyph gets a PINNED SQUARE per rung sm 28 / md 32 / lg 36 — equal to
265
- * the rung's button height and independent of glyph size (padding-derived
266
- * squares drifted with icon size; user law: the box never moves). */
267
- .kol-btn-icon.kol-btn-xs { width: 20px; height: 20px; padding: 0; }
268
- .kol-btn-icon.kol-btn-sm { width: 28px; height: 28px; padding: 0; }
264
+ * a lone glyph gets a PINNED SQUARE per size, equal to that size's button height
265
+ * and independent of glyph size (padding-derived squares drifted with icon size;
266
+ * user law: the box never moves).
267
+ *
268
+ * EVERY FAMILY HITS THE SAME HEIGHT AT THE SAME SIZE (user ruling 2026-09-02:
269
+ * *"xs sm md and lg all have height in pixels that has to match"* · *"so button
270
+ * and dropdown can align and input and whatever else"*). These squares read
271
+ * 20/28/32/36 while the text control on the same row — padding + that size's
272
+ * mono line-height + the 1px ring — measures 22/26/32/40. Only `md` lined up: at
273
+ * `sm` an icon button stood 2px TALLER than the Input beside it, at `lg` 4px
274
+ * shorter, at `xs` 2px shorter. Three families (control shell, text button,
275
+ * segmented) already agreed on 22/26/32/40, so the squares conform to them, not
276
+ * the other way round. Glyphs are untouched — SOLO still resolves 16/20/24. */
277
+ .kol-btn-icon.kol-btn-xs { width: 22px; height: 22px; padding: 0; }
278
+ .kol-btn-icon.kol-btn-sm { width: 26px; height: 26px; padding: 0; }
269
279
  .kol-btn-icon.kol-btn-md { width: 32px; height: 32px; padding: 0; }
270
- .kol-btn-icon.kol-btn-lg { width: 36px; height: 36px; padding: 0; }
280
+ .kol-btn-icon.kol-btn-lg { width: 40px; height: 40px; padding: 0; }
271
281
 
272
282
  .kol-btn-primary {
273
283
  background: var(--kol-surface-secondary);
@@ -338,9 +348,10 @@
338
348
  }
339
349
 
340
350
  /* Navigation (2026-07-28, user-ordered) — chrome for links that move between
341
- * pages, not tool actions. SQUARE container: padding = the rung's vertical pad
342
- * on all four sides (sm 24 / md 30 / lg 36 outer the text-button height of
343
- * the same rung, so mixed bars line up). Quiet states: rest dimmed, hover the
351
+ * pages, not tool actions. The SQUARE comes from `.kol-btn-icon` above one
352
+ * height per size, 22/26/32/40, so mixed bars line up (this rule described a
353
+ * padding-derived box, `sm 24 / md 30 / lg 36`, from before the square was
354
+ * pinned; corrected 2026-09-03). Quiet states: rest dimmed, hover the
344
355
  * ghost wash, and ACTIVE keys off aria-current="page" (NavLink sets it
345
356
  * natively) — brighter glyph on a faint wash, never the pressed fill;
346
357
  * navigation is location, not a toggled tool. */
@@ -1238,12 +1249,13 @@ a.kol-icon-frame {
1238
1249
  .kol-icon-frame-radius-full,
1239
1250
  .kol-btn-radius-full { border-radius: 9999px; }
1240
1251
 
1241
- /* pinned squares — the box never moves with glyph size (user law 2026-07-28) */
1242
- /* xs the panel rung; the ladder is one ladder (user ruling 2026-09-01: "obviously we apply xs as an option") */
1243
- .kol-icon-frame-xs { width: 20px; height: 20px; }
1244
- .kol-icon-frame-sm { width: 28px; height: 28px; }
1252
+ /* pinned squares — the box never moves with glyph size (user law 2026-07-28),
1253
+ * on the size's HEIGHT so a frame lines up with the Button, Input and Dropdown
1254
+ * beside it (user ruling 2026-09-02 see .kol-btn-icon above). 22/26/32/40. */
1255
+ .kol-icon-frame-xs { width: 22px; height: 22px; }
1256
+ .kol-icon-frame-sm { width: 26px; height: 26px; }
1245
1257
  .kol-icon-frame-md { width: 32px; height: 32px; }
1246
- .kol-icon-frame-lg { width: 36px; height: 36px; }
1258
+ .kol-icon-frame-lg { width: 40px; height: 40px; }
1247
1259
 
1248
1260
  .kol-icon-frame-primary {
1249
1261
  background: var(--kol-surface-secondary);
@@ -45,9 +45,12 @@
45
45
  * the estate is copying. The trigger is the one text control that always sits in
46
46
  * an icon row, so it takes the icon rungs: 28 / 32 / 36. Horizontal padding is
47
47
  * untouched; the vertical goes, because the flex box centres the label. */
48
- .kol-dd-trigger.kol-btn-sm { height: 28px; padding-block: 0; }
48
+ /* 22/26/32/40 since 2026-09-02 one height per size, so the trigger, the
49
+ * IconFrame and the Input on a row are the same box (see .kol-btn-icon). */
50
+ .kol-dd-trigger.kol-btn-xs { height: 22px; padding-block: 0; }
51
+ .kol-dd-trigger.kol-btn-sm { height: 26px; padding-block: 0; }
49
52
  .kol-dd-trigger.kol-btn-md { height: 32px; padding-block: 0; }
50
- .kol-dd-trigger.kol-btn-lg { height: 36px; padding-block: 0; }
53
+ .kol-dd-trigger.kol-btn-lg { height: 40px; padding-block: 0; }
51
54
  /* REST AND OPEN ARE THE ONLY STATES (2026-07-15, re-called 2026-08-09 and
52
55
  * 2026-08-28). No :hover or :active rules for the trigger live here any more —
53
56
  * kol-components-atoms.css excludes `.kol-dd-trigger` from every variant's
@@ -866,7 +869,13 @@
866
869
  * compositing layer on every overlay open, on a phone, for a separation the
867
870
  * 60% tint already carries. */
868
871
  .kol-overlay-scrim {
869
- background-color: color-mix(in srgb, #000 60%, transparent);
872
+ /* ONE SCRIM, ONE TINT (user ruling 2026-09-03: *"makes sense to me they are
873
+ * the same no?"*). Was a raw `#000` at 60 % — a literal in a token system, and
874
+ * 60 is not a ladder stop (…40 · 48 · 64 · 72…). `.kol-shell-drawer-scrim`
875
+ * already spelled it correctly at 48, so the same gesture dimmed to 60 in the
876
+ * site shell and 48 in the app shell. 48 for both: on the ladder, already
877
+ * shipping, and the class was minted to BE one tint. */
878
+ background-color: color-mix(in srgb, var(--kol-color-ab-black) 48%, transparent);
870
879
  }
871
880
 
872
881
  .kol-overlay-panel {
@@ -1351,33 +1360,76 @@
1351
1360
  cursor: row-resize;
1352
1361
  touch-action: none;
1353
1362
  }
1354
- /* THE GRAB IS A PILL, NOT A WASH (ColumnBrowserChromeCorrections, kol-r2b2
1355
- * 2026-08-28 user: "dont show me this way to grab" · "like in the sidenav" ·
1356
- * "MIDDLE smack middle" · "more smooth animation longer in and out"): the same
1357
- * affordance as the framework's `.kol-sidenav-grab::before` — 0.1875rem × 2rem,
1358
- * radius-full, fg-64, dead centre (pointer-following was built and rejected).
1359
- * Two deliberate differences: hidden at rest rather than dim (N handles standing
1360
- * at rest is noise where the SideNav has one) and 420ms rather than 150ms. */
1363
+ /* THE GRAB PILL ON THE LINE, FOLLOWING THE POINTER (BrowsePageRulingsAndSeams,
1364
+ * kol-r2b2 2026-09-02, user ruling; supersedes the "pointer-following was built
1365
+ * and rejected" note that stood here from ColumnBrowserChromeCorrections
1366
+ * 2026-08-28).
1367
+ *
1368
+ * The rejection was already contradicted by the DS itself: the rail's grab
1369
+ * (`kol-animation.css` § THE GRAB PILL, RailFlatGrabOpen, kol-mirror 2026-08-28
1370
+ * — *"make it like it is in kol-r2b2, it has animation and gsap"*) shipped the
1371
+ * pointer-follow, the 0.125 × 4.5rem geometry and the slow proximity fade the
1372
+ * SAME DAY, and its own comment noted the two handles were knowingly different.
1373
+ * One gesture, two shapes, is the ruling now. `useGrabEdge` drives both.
1374
+ *
1375
+ * THESE HANDLES ARE NOT THE SIDENAV'S, and that is the part to keep straight:
1376
+ *
1377
+ * ACROSS the rail's strip STRADDLES its line, so a strip-centred pill IS the
1378
+ * line. These strips lie INSIDE the border they grab — the x strip is
1379
+ * pulled back over the column's right edge (`margin-left: -8px`), the
1380
+ * y strip sits on the root's inner bottom edge — so a strip-centred
1381
+ * pill is always ~4px short of it. The FAR edge plus half the 1px
1382
+ * border is the line: `calc(100% + 0.5px)`.
1383
+ * AXES the rail has one vertical edge; there are two here, and the pill on
1384
+ * each travels the other way from what it resizes. The x handle reads
1385
+ * `--kol-rail-grab-y`, the y handle `--kol-rail-grab-x`.
1386
+ * REST hidden, not dim — N handles standing at rest is noise where the
1387
+ * SideNav has one. The rail's pill rests visible; these do not.
1388
+ *
1389
+ * Shared with the rail: the fine/long geometry and the 1800ms fade with its
1390
+ * 400ms rest delay and 40ms engaged delay. NOT shared, on the user's ruling
1391
+ * 2026-09-02 (*"its a bit different, its not like the sidenav"*): the CURVE is
1392
+ * kol-r2b2's ease-out, and the travel is `GRAB_COLUMN` in kol-component's
1393
+ * motion.js — a 2.8s chase on a 30px retarget, so the pill tracks the pointer
1394
+ * down the edge rather than landing and holding on the rail's 90px dwell. The
1395
+ * rail's own symmetric in-out was ruled for the rail, on a pill that rests
1396
+ * VISIBLE and only brightens; these are hidden at rest and the whole fade is
1397
+ * the reveal. `clamp()` holds the pill half its own length from each end. */
1361
1398
  .kol-column-browser-resize-x::before,
1362
1399
  .kol-column-browser-resize-y::before {
1363
1400
  content: '';
1364
1401
  position: absolute;
1365
- top: 50%;
1366
- left: 50%;
1367
1402
  translate: -50% -50%;
1368
1403
  border-radius: var(--kol-radius-full);
1369
1404
  background: var(--kol-fg-64);
1370
1405
  opacity: 0;
1371
- transition: opacity 420ms cubic-bezier(0.4, 0, 0.2, 1);
1406
+ transition: opacity 1800ms cubic-bezier(0.22, 1, 0.36, 1) 400ms, background-color 500ms ease;
1372
1407
  }
1373
- .kol-column-browser-resize-x::before { width: 0.1875rem; height: 2rem; }
1374
- .kol-column-browser-resize-y::before { width: 2rem; height: 0.1875rem; }
1375
- .kol-column-browser-resize-x:hover::before,
1408
+ .kol-column-browser-resize-x::before {
1409
+ width: 0.125rem;
1410
+ height: 4.5rem;
1411
+ left: calc(100% + 0.5px);
1412
+ top: clamp(2.25rem, var(--kol-rail-grab-y, 50%), calc(100% - 2.25rem));
1413
+ }
1414
+ .kol-column-browser-resize-y::before {
1415
+ width: 4.5rem;
1416
+ height: 0.125rem;
1417
+ top: calc(100% + 0.5px);
1418
+ left: clamp(2.25rem, var(--kol-rail-grab-x, 50%), calc(100% - 2.25rem));
1419
+ }
1420
+ /* `is-near` = the pointer is within GRAB.near of THIS handle's line (JS,
1421
+ * hysteresis at GRAB.sleep). The pill shows before you are on the 8px strip, so
1422
+ * the grab is discoverable instead of hidden. */
1423
+ .kol-column-browser-resize-x.is-near::before,
1376
1424
  .kol-column-browser-resize-x.is-dragging::before,
1377
- .kol-column-browser-resize-y:hover::before,
1425
+ .kol-column-browser-resize-y.is-near::before,
1378
1426
  .kol-column-browser-resize-y.is-dragging::before {
1379
1427
  opacity: 1;
1428
+ transition-delay: 40ms;
1380
1429
  }
1430
+ .kol-column-browser-resize-x.is-dragging::before,
1431
+ .kol-column-browser-resize-y.is-dragging::before { background: var(--kol-fg-96); }
1432
+
1381
1433
  .kol-overlay .kol-prose {
1382
1434
  max-width: var(--kol-content-measure);
1383
1435
  margin-inline: auto;
@@ -23,8 +23,10 @@
23
23
  * the next question would have meant another one.
24
24
  *
25
25
  * The axis removes the question. `wght 100 800` means any weight is a NUMBER,
26
- * not a new file — and the payload went DOWN: two variable faces at ~230 kb
26
+ * not a new file — and the payload went DOWN: two variable faces at ~148 kb
27
27
  * against 1024 kb of statics, with four weights the statics never had.
28
+ * (This read ~230 kb until 2026-09-03; measured on disk, roman 72K + italic
29
+ * 76K. 03-typography.md's 151 kb was the correct figure all along.)
28
30
  *
29
31
  * The tradeoff, stated: a variable file is one download, so the page fetches
30
32
  * the whole axis or none of it. At this size that is still less than the two
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-theme",
3
- "version": "0.130.0",
3
+ "version": "0.132.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",