@kolkrabbi/kol-theme 0.43.0 → 0.44.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-components-atoms.css +107 -59
- package/kol-components-molecules.css +122 -2
- package/kol-theme.css +12 -2
- package/package.json +1 -1
package/kol-components-atoms.css
CHANGED
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
* navigation is location, not a toggled tool. */
|
|
308
308
|
.kol-btn-nav {
|
|
309
309
|
background: transparent;
|
|
310
|
-
color: var(--kol-oq-
|
|
310
|
+
color: var(--kol-oq-80);
|
|
311
311
|
border: 1px solid transparent;
|
|
312
312
|
}
|
|
313
313
|
@media (hover: hover) {
|
|
@@ -329,6 +329,8 @@
|
|
|
329
329
|
* Button variant on the opaque tier: rest oq-12, hover/active one stop past
|
|
330
330
|
* each, same state math as the rest of the family. */
|
|
331
331
|
.kol-btn-grey {
|
|
332
|
+
/* Ladder (user ruling 2026-08-15): 12 rest → 04 hover (darker) → 32 press,
|
|
333
|
+
* then eased back down. */
|
|
332
334
|
background: var(--kol-oq-12);
|
|
333
335
|
color: var(--kol-surface-on-primary);
|
|
334
336
|
border: 1px solid transparent;
|
|
@@ -804,81 +806,117 @@ a:hover .icon-hover,
|
|
|
804
806
|
display: inline-flex;
|
|
805
807
|
align-items: center;
|
|
806
808
|
justify-content: center;
|
|
807
|
-
|
|
808
|
-
* the same rule .kol-icon-frame-{sm,md,lg} obeys at 28/32/36). This class
|
|
809
|
-
* derived its size from `padding: 0.5rem` + whatever glyph it was handed, so
|
|
810
|
-
* a 14px icon silently produced a 30px control off the ladder. 32px is md on
|
|
811
|
-
* both the icon-frame squares and the button ladder (26/32/40), and it is
|
|
812
|
-
* exactly what 0.5rem + a 16px glyph already measured — CodeBlock's button
|
|
813
|
-
* does not move. */
|
|
814
|
-
width: 32px;
|
|
815
|
-
height: 32px;
|
|
816
|
-
padding: 0;
|
|
817
|
-
/* rungs below; the base stays md so a class used without one still lands
|
|
818
|
-
* on the ladder rather than collapsing to its content */
|
|
809
|
+
padding: 0.5rem;
|
|
819
810
|
background: color-mix(in srgb, var(--kol-surface-on-primary) 2%, transparent);
|
|
820
811
|
border: none;
|
|
821
812
|
border-radius: var(--kol-radius-sm);
|
|
822
|
-
|
|
823
|
-
* over a photograph lets the image through the strokes and reads as mush.
|
|
824
|
-
* oq is a baked grey — same value, nothing bleeds through. */
|
|
825
|
-
color: var(--kol-oq-72);
|
|
813
|
+
color: color-mix(in srgb, var(--kol-surface-on-primary) 72%, transparent);
|
|
826
814
|
cursor: pointer;
|
|
827
815
|
transition: background-color var(--kol-transition-base), color var(--kol-transition-base);
|
|
828
816
|
}
|
|
829
817
|
|
|
830
818
|
.kol-copy-btn:hover {
|
|
831
819
|
background: color-mix(in srgb, var(--kol-surface-on-primary) 8%, transparent);
|
|
832
|
-
/* FULL ink on hover — no mix, no stop below 100% */
|
|
833
820
|
color: var(--kol-surface-on-primary);
|
|
834
821
|
}
|
|
835
822
|
|
|
836
|
-
/*
|
|
837
|
-
*
|
|
838
|
-
.
|
|
839
|
-
|
|
840
|
-
color: var(--kol-surface-on-primary);
|
|
841
|
-
}
|
|
823
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
824
|
+
* TWO SEPARATE CONTROLS (user ruling 2026-08-15). They shared .kol-copy-btn
|
|
825
|
+
* as a base and every edit to one moved the other; the split is the point.
|
|
826
|
+
* ───────────────────────────────────────────────────────────────────── */
|
|
842
827
|
|
|
843
|
-
/*
|
|
844
|
-
*
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
828
|
+
/* over MEDIA — boxed, opaque plate, full ink. Sits on a photograph, so it
|
|
829
|
+
* needs its own fill to stay legible and never dims at rest. */
|
|
830
|
+
.kol-media-control {
|
|
831
|
+
display: inline-flex;
|
|
832
|
+
align-items: center;
|
|
833
|
+
justify-content: center;
|
|
834
|
+
width: 32px;
|
|
835
|
+
height: 32px;
|
|
836
|
+
padding: 0;
|
|
837
|
+
border: none;
|
|
838
|
+
border-radius: var(--kol-radius-sm);
|
|
839
|
+
background: var(--kol-oq-12);
|
|
854
840
|
color: var(--kol-surface-on-primary);
|
|
841
|
+
cursor: pointer;
|
|
842
|
+
/* the house curve, not --kol-transition-base's generic material ease: it
|
|
843
|
+
* settles instead of stopping, which is what reads as smooth on the press. */
|
|
844
|
+
transition: background-color 1500ms var(--kol-ease-bounce), color 1500ms var(--kol-ease-bounce);
|
|
845
|
+
}
|
|
846
|
+
/* hover goes LIGHTER, not darker (user ruling 2026-08-15) — oq mixes ink into
|
|
847
|
+
* the surface, so up the scale is up in brightness. */
|
|
848
|
+
/* the brand anchor, with the theme's own palette as the fallback — the yellow
|
|
849
|
+
* lives in kol-brand-color.css which the consumer supplies, so the theme must
|
|
850
|
+
* not hard-depend on it. NOT --kol-accent-primary, which resolves to white. */
|
|
851
|
+
.kol-media-control:hover {
|
|
852
|
+
background: var(--kol-surface-tertiary);
|
|
853
|
+
color: var(--kol-color-yellow-300, var(--kol-palette-yellow));
|
|
854
|
+
}
|
|
855
|
+
/* The press RAMPS. The rule that is being entered owns the curve going in, so
|
|
856
|
+
* this one carries a slow ease-in-out; the base rule's bounce owns coming back
|
|
857
|
+
* out. One bezier cannot do both — the bounce covers most of its distance in
|
|
858
|
+
* the first quarter, which is exactly why the press read as instant. */
|
|
859
|
+
/* the glyph GROWS on interaction: 18 at rest, 20 on hover and press, inside the
|
|
860
|
+
* unchanged 32px box. The SOLO md rung (20) stays the base and rest scales DOWN
|
|
861
|
+
* to it — 20 × 0.9 = 18 — so the ladder value is still what the component asks
|
|
862
|
+
* for. Scale, not a size swap: the box never moves (2026-07-28 law) and an SVG
|
|
863
|
+
* re-render would not tween. */
|
|
864
|
+
.kol-media-control .kol-action-glyph {
|
|
865
|
+
transform: scale(0.9);
|
|
866
|
+
transition: transform 500ms var(--kol-ease-house);
|
|
867
|
+
}
|
|
868
|
+
.kol-media-control:hover .kol-action-glyph,
|
|
869
|
+
.kol-media-control--pressed .kol-action-glyph {
|
|
870
|
+
transform: scale(1);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.kol-media-control:active,
|
|
874
|
+
.kol-media-control--pressed {
|
|
875
|
+
background: var(--kol-oq-32);
|
|
876
|
+
transition: background-color 1500ms cubic-bezier(0.65, 0, 0.35, 1);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/* in TEXT — bare, no box, no fill. Rests on the SAME ink as the copy beside it
|
|
880
|
+
* (--kol-fg-meta = fg-48): these sit on a solid plate, not on a photograph, so
|
|
881
|
+
* the transparent scale is safe here and matching the text is worth more than
|
|
882
|
+
* the opaque rung. `--on` is a toggle's held state, not a hover. */
|
|
883
|
+
.kol-inline-control {
|
|
884
|
+
display: inline-flex;
|
|
885
|
+
align-items: center;
|
|
886
|
+
justify-content: center;
|
|
887
|
+
width: 16px;
|
|
888
|
+
height: 16px;
|
|
889
|
+
padding: 0;
|
|
890
|
+
border: none;
|
|
891
|
+
background: transparent;
|
|
892
|
+
color: var(--kol-oq-64);
|
|
893
|
+
cursor: pointer;
|
|
894
|
+
transition: color var(--kol-transition-base);
|
|
855
895
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
|
|
896
|
+
/* ONE rest tone for every inline control (user ruling 2026-08-15): the star and
|
|
897
|
+
* the trash beside it sit at the same weight until you reach for one. They part
|
|
898
|
+
* on HOVER — a neutral control brightens, the accent control goes yellow. Yellow
|
|
899
|
+
* is the accent's alone, on hover and on its on-state; spending it on every
|
|
900
|
+
* hover left the on-state with nothing of its own to say. */
|
|
901
|
+
.kol-inline-control:hover { color: var(--kol-oq-96); }
|
|
902
|
+
|
|
903
|
+
.kol-inline-control--accent:hover,
|
|
904
|
+
.kol-inline-control--on,
|
|
905
|
+
.kol-inline-control--on:hover { color: var(--kol-color-yellow-300, var(--kol-palette-yellow)); }
|
|
906
|
+
|
|
907
|
+
/* TWO GLYPHS, not one glyph and a fill (user ruling 2026-08-15: *"just create
|
|
908
|
+
* another star"*, *"leave the one alone in cards"*). `star` stays stroke-only
|
|
909
|
+
* and `star-solid` is the filled twin; a control that has an on-state names
|
|
910
|
+
* both and ActionButton crossfades them.
|
|
862
911
|
*
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
* the control reads identically whatever the image does.
|
|
912
|
+
* The alternative — filling the shared `star.svg` and unfilling it here — was
|
|
913
|
+
* tried and reverted: a glyph that ships filled renders filled in every
|
|
914
|
+
* consumer that never asked for a state, and the DS cannot see those.
|
|
867
915
|
*
|
|
868
|
-
* The
|
|
869
|
-
*
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
* (16/20/24) pairs 1:1 with them and ActionButton resolves it — the pairing is
|
|
873
|
-
* never re-typed at a call site. */
|
|
874
|
-
.kol-copy-btn-sm { width: 28px; height: 28px; }
|
|
875
|
-
.kol-copy-btn-md { width: 32px; height: 32px; }
|
|
876
|
-
.kol-copy-btn-lg { width: 36px; height: 36px; }
|
|
877
|
-
|
|
878
|
-
.kol-copy-btn--grey {
|
|
879
|
-
background: var(--kol-oq-12);
|
|
880
|
-
}
|
|
881
|
-
|
|
916
|
+
* The `--on` fill below is kept for a control that ships ONE glyph and carries
|
|
917
|
+
* its state in the class instead; it is a no-op on a stroke-only icon. */
|
|
918
|
+
.kol-inline-control svg path { transition: fill var(--kol-transition-base); }
|
|
919
|
+
.kol-inline-control--on svg path { fill: currentColor; }
|
|
882
920
|
|
|
883
921
|
/* ─────────────────────────────────────────────────────────────────────
|
|
884
922
|
* Figure — atoms/Figure.jsx
|
|
@@ -1035,6 +1073,16 @@ a.kol-icon-frame {
|
|
|
1035
1073
|
color: var(--kol-surface-on-primary);
|
|
1036
1074
|
border: 1px solid transparent;
|
|
1037
1075
|
}
|
|
1076
|
+
/* plate — the ONE exception in 05-control-chrome.md § Icon box: an affordance
|
|
1077
|
+
* sitting on a PHOTO. It needs an opaque plate and a backdrop blur to stay
|
|
1078
|
+
* legible over arbitrary pixels, and no Button variant covers it. Values are
|
|
1079
|
+
* MediaCard's, which is the instance the doc names. */
|
|
1080
|
+
.kol-icon-frame-plate {
|
|
1081
|
+
background: var(--kol-fg-absolute-12, rgba(0, 0, 0, 0.4));
|
|
1082
|
+
backdrop-filter: blur(4px);
|
|
1083
|
+
color: var(--kol-surface-on-primary);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1038
1086
|
.kol-icon-frame-grey {
|
|
1039
1087
|
background: var(--kol-oq-12);
|
|
1040
1088
|
color: var(--kol-surface-on-primary);
|
|
@@ -813,6 +813,126 @@
|
|
|
813
813
|
border-top: 1px solid var(--kol-fg-08);
|
|
814
814
|
/* 20px below the rule; the 20px above falls out of the rail body's own
|
|
815
815
|
* gap-5, so a symmetric space–divider–space lands without this file
|
|
816
|
-
* knowing anything about the rail.
|
|
817
|
-
|
|
816
|
+
* knowing anything about the rail.
|
|
817
|
+
* px, not --kol-spacing-5 — that token is rem, and spacing here is px
|
|
818
|
+
* (.kol-tag--sm, .kol-sidenav-group, .kol-control-* all set px directly). */
|
|
819
|
+
padding-top: 20px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
823
|
+
* Content family hover — molecules/ContentCard.jsx · ContentRow.jsx
|
|
824
|
+
*
|
|
825
|
+
* ONE rule, driven by a per-variant custom property the component sets
|
|
826
|
+
* (`--kol-content-hover-bg`). The alternative was a hover utility per
|
|
827
|
+
* variant in JSX, which Tailwind cannot generate from package source
|
|
828
|
+
* anyway (the SegmentedToggle lesson — component chrome belongs in
|
|
829
|
+
* kol-theme). A variant with no hover simply never sets the property,
|
|
830
|
+
* and the rule resolves to nothing.
|
|
831
|
+
*
|
|
832
|
+
* The fill is an oq-* step per 05-control-chrome.md's state model; the
|
|
833
|
+
* value itself is chosen in ContentCard/ContentRow's HOVER table.
|
|
834
|
+
* ───────────────────────────────────────────────────────────────────── */
|
|
835
|
+
@media (hover: hover) {
|
|
836
|
+
.kol-content-hover:hover {
|
|
837
|
+
background-color: var(--kol-content-hover-bg);
|
|
838
|
+
}
|
|
839
|
+
/* border is its OWN class, not a fallback chain off the bg one: a variant
|
|
840
|
+
* that steps its fill but not its frame (catalog) and one that steps its
|
|
841
|
+
* frame but not its fill (work) are both real, and an undefined var in a
|
|
842
|
+
* border-color declaration resolves to `unset` — which inherits, and quietly
|
|
843
|
+
* repaints a border nobody asked to move. */
|
|
844
|
+
.kol-content-hover-frame:hover {
|
|
845
|
+
border-color: var(--kol-content-hover-border);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
850
|
+
* ContentRow — the responsive step
|
|
851
|
+
*
|
|
852
|
+
* The row publishes its box as custom properties and reads them here, so
|
|
853
|
+
* the md: step is ONE media query instead of per-variant Tailwind variants
|
|
854
|
+
* that Tailwind cannot generate from package source anyway. A variant that
|
|
855
|
+
* publishes no `-md` value falls back to its base and never steps.
|
|
856
|
+
* ───────────────────────────────────────────────────────────────────── */
|
|
857
|
+
.kol-row {
|
|
858
|
+
gap: var(--kol-row-gap);
|
|
859
|
+
padding: var(--kol-row-pad);
|
|
860
|
+
min-height: var(--kol-row-min-h);
|
|
861
|
+
background: var(--kol-row-bg);
|
|
862
|
+
border-color: var(--kol-row-border);
|
|
863
|
+
transition: background-color 300ms var(--kol-ease-house),
|
|
864
|
+
border-color 300ms var(--kol-ease-house);
|
|
865
|
+
}
|
|
866
|
+
.kol-row > .kol-row-thumb {
|
|
867
|
+
width: var(--kol-row-thumb);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/* 768 = the ruled `md` rung (08-breakpoints/01-values.md). A media query
|
|
871
|
+
* cannot read a custom property, so the number is a literal by necessity —
|
|
872
|
+
* naming the rung is the only thing that stops it reading as arbitrary. */
|
|
873
|
+
@media (min-width: 768px) {
|
|
874
|
+
.kol-row {
|
|
875
|
+
gap: var(--kol-row-gap-md, var(--kol-row-gap));
|
|
876
|
+
padding: var(--kol-row-pad-md, var(--kol-row-pad));
|
|
877
|
+
min-height: var(--kol-row-min-h-md, var(--kol-row-min-h));
|
|
878
|
+
}
|
|
879
|
+
.kol-row > .kol-row-thumb {
|
|
880
|
+
width: var(--kol-row-thumb-md, var(--kol-row-thumb));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
885
|
+
* ContentCard — the work DRAWER
|
|
886
|
+
*
|
|
887
|
+
* A caption plate that rises over the bottom of the artwork on hover.
|
|
888
|
+
* The card is image-only at rest by design: a work shelf is a wall of
|
|
889
|
+
* images, and the caption is the reveal.
|
|
890
|
+
*
|
|
891
|
+
* Absolute, so it never adds height to the card and never reflows the
|
|
892
|
+
* shelf. Opacity only — a translucent wash over a photograph is exactly
|
|
893
|
+
* what the oq-* tier exists to avoid, but this plate is OPAQUE
|
|
894
|
+
* (surface-inverse) and it is the plate's PRESENCE that animates, not
|
|
895
|
+
* its transparency over the image.
|
|
896
|
+
* ───────────────────────────────────────────────────────────────────── */
|
|
897
|
+
.kol-card-drawer {
|
|
898
|
+
position: absolute;
|
|
899
|
+
inset-inline: 0;
|
|
900
|
+
bottom: 0;
|
|
901
|
+
z-index: 10;
|
|
902
|
+
opacity: 0;
|
|
903
|
+
transition: opacity 300ms var(--kol-ease-house);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
@media (hover: hover) {
|
|
907
|
+
.group:hover > .kol-card-drawer {
|
|
908
|
+
opacity: 1;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/* touch has no hover — the caption must not be unreachable there */
|
|
913
|
+
@media (hover: none) {
|
|
914
|
+
.kol-card-drawer {
|
|
915
|
+
opacity: 1;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/* The card's text plate steps its padding at md where the variant declares
|
|
920
|
+
* one (work: 16 → 24, matching the shipped drawer's `p-4 md:p-6`). Same
|
|
921
|
+
* custom-property mechanism as .kol-row — Tailwind cannot generate an
|
|
922
|
+
* md: variant from package source, and these are per-variant data. */
|
|
923
|
+
/* the ruled `md` rung, same as .kol-row above */
|
|
924
|
+
@media (min-width: 768px) {
|
|
925
|
+
.kol-card-plate {
|
|
926
|
+
padding: var(--kol-plate-pad-md, var(--kol-plate-pad));
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* The card's rest colours, for the same reason as .kol-row — an inline
|
|
931
|
+
* background/borderColor outranks .kol-content-hover:hover, so the step
|
|
932
|
+
* silently never rendered. */
|
|
933
|
+
.kol-card {
|
|
934
|
+
background: var(--kol-card-bg);
|
|
935
|
+
border-color: var(--kol-card-border);
|
|
936
|
+
transition: background-color 300ms var(--kol-ease-house),
|
|
937
|
+
border-color 300ms var(--kol-ease-house);
|
|
818
938
|
}
|
package/kol-theme.css
CHANGED
|
@@ -95,8 +95,18 @@
|
|
|
95
95
|
|
|
96
96
|
/* The house curve (2026-08-15) — the easing the cards actually use; was
|
|
97
97
|
* hardcoded in 5 files before this token existed. Curve only, no duration:
|
|
98
|
-
* it pairs with whatever duration the motion needs.
|
|
99
|
-
|
|
98
|
+
* it pairs with whatever duration the motion needs.
|
|
99
|
+
*
|
|
100
|
+
* BALANCED, not expo (user ruling 2026-08-15). This was easeOutExpo
|
|
101
|
+
* `cubic-bezier(0.16, 1, 0.3, 1)`, which spends ~90% of its distance in the
|
|
102
|
+
* first fifth of the duration and the rest on a settle you cannot see — so
|
|
103
|
+
* every motion read as instant no matter what duration it was given, and a
|
|
104
|
+
* small hover affordance never showed its move at all. */
|
|
105
|
+
--kol-ease-house: cubic-bezier(0.4, 0, 0.2, 1);
|
|
106
|
+
/* the bounce — overshoots past its target and settles back (y > 1 is what
|
|
107
|
+
* makes it bounce; house only decelerates). For a press that should feel
|
|
108
|
+
* springy rather than merely smooth. */
|
|
109
|
+
--kol-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
100
110
|
|
|
101
111
|
/* Content widths (2026-07-28; panel added 2026-07-30) — ONE frame, three
|
|
102
112
|
* inner caps (chess law). Every page: mx-auto max-w-shell + the one padding
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.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",
|