@kolkrabbi/kol-theme 0.141.0 → 0.143.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.
@@ -1834,3 +1834,113 @@
1834
1834
  color: var(--kol-tone-pressed-fg);
1835
1835
  }
1836
1836
 
1837
+
1838
+ /* ─────────────────────────── DocsToc · rail ───────────────────────────
1839
+ * The fisheye rail render of `DocsToc` (`variant="rail"`, docstoc-rail-variant,
1840
+ * kol-client-olina 2026-09-03 — built and run there before filing).
1841
+ *
1842
+ * `--m` is the gaussian magnitude (0..1) the component writes per row on
1843
+ * pointer move; EVERY visual here derives from it, so the JS sets one number
1844
+ * per row and the cascade does the rest. This is CSS rather than utilities
1845
+ * because each rule reads a custom property through `calc()` and sets a
1846
+ * child's resting state from the row's variable — neither is expressible as a
1847
+ * Tailwind class, which is the §5 test for when a rule belongs in the theme.
1848
+ * ────────────────────────────────────────────────────────────────────── */
1849
+
1850
+ .kol-toc {
1851
+ position: fixed;
1852
+ top: 50%;
1853
+ transform: translateY(-50%);
1854
+ z-index: var(--kol-z-sticky);
1855
+ display: flex;
1856
+ flex-direction: column;
1857
+ padding-block: var(--kol-spacing-8);
1858
+ }
1859
+ /* The lens scales about the edge the rail is pinned to, so the column's outer
1860
+ * edge stays a straight line while the type breathes. The wide inner padding is
1861
+ * the lens's room to grow into without the labels colliding with the page. */
1862
+ .kol-toc--right {
1863
+ right: 0;
1864
+ align-items: flex-end;
1865
+ padding-right: var(--kol-spacing-6);
1866
+ padding-left: var(--kol-spacing-16);
1867
+ }
1868
+ .kol-toc--left {
1869
+ left: 0;
1870
+ align-items: flex-start;
1871
+ padding-left: var(--kol-spacing-6);
1872
+ padding-right: var(--kol-spacing-16);
1873
+ }
1874
+
1875
+ .kol-toc-row {
1876
+ --m: 0;
1877
+ display: flex;
1878
+ align-items: center;
1879
+ gap: var(--kol-spacing-3);
1880
+ padding-block: 2px;
1881
+ text-decoration: none;
1882
+ }
1883
+ .kol-toc--right .kol-toc-row { justify-content: flex-end; }
1884
+ .kol-toc--left .kol-toc-row { flex-direction: row-reverse; justify-content: flex-end; }
1885
+
1886
+ /* Away from the pointer the row is small and quiet; under it, large and lit.
1887
+ * BOTH directions matter — grow-only reads as a bump, not a scrub. */
1888
+ .kol-toc-label {
1889
+ /* `transform` is ignored on a non-replaced INLINE element, and this label is
1890
+ * a bare <span>: the scale below did nothing at all until this line. It cost
1891
+ * the filer a round trip with the user — opacity and width worked and only
1892
+ * the scale did not. */
1893
+ display: inline-block;
1894
+ white-space: nowrap;
1895
+ opacity: calc(0.26 + 0.74 * var(--m));
1896
+ transform: scale(calc(0.78 + 0.42 * var(--m)));
1897
+ will-change: transform, opacity;
1898
+ }
1899
+ .kol-toc--right .kol-toc-label { transform-origin: right center; }
1900
+ .kol-toc--left .kol-toc-label { transform-origin: left center; }
1901
+
1902
+ .kol-toc-rule {
1903
+ height: 1px;
1904
+ background: var(--kol-fg-24);
1905
+ width: calc(8px + 26px * var(--m));
1906
+ }
1907
+
1908
+ /* The section you are actually IN reads at rest — full ink and a size step — so
1909
+ * the column says where you are before the pointer arrives. It rests where an
1910
+ * inactive row lands only under the lens. */
1911
+ .kol-toc-row[data-active] .kol-toc-label {
1912
+ opacity: calc(0.92 + 0.08 * var(--m));
1913
+ transform: scale(calc(1 + 0.2 * var(--m)));
1914
+ color: var(--kol-fg-96);
1915
+ }
1916
+ .kol-toc-row[data-active] .kol-toc-rule {
1917
+ width: calc(22px + 26px * var(--m));
1918
+ background: var(--kol-fg-64);
1919
+ }
1920
+
1921
+ /* Settle on leave — NEVER while the pointer is driving. A transition on a
1922
+ * continuous input lags behind the cursor and reads as sluggish; the component
1923
+ * stamps `data-live` on pointer-enter, which is what this selector reads. */
1924
+ .kol-toc:not([data-live]) .kol-toc-label,
1925
+ .kol-toc:not([data-live]) .kol-toc-rule {
1926
+ transition: opacity 260ms ease-out, transform 260ms ease-out, width 260ms ease-out;
1927
+ }
1928
+
1929
+ /* Graduations — the ruler between the labels. Shorter and fainter than a
1930
+ * heading's stroke at every point of the curve, so the labelled marks stay the
1931
+ * ones you read; they exist to give the lens something continuous to cross.
1932
+ * 3px pitch: ten between labels puts a section at ~52px, so a thirteen-section
1933
+ * page still stands inside a laptop viewport. */
1934
+ .kol-toc-tick { height: 3px; padding-block: 0; }
1935
+ .kol-toc-tick .kol-toc-rule {
1936
+ width: calc(5px + 11px * var(--m));
1937
+ background: var(--kol-fg-12);
1938
+ }
1939
+
1940
+ @media (prefers-reduced-motion: reduce) {
1941
+ .kol-toc-label { opacity: 1; transform: none; }
1942
+ .kol-toc-rule { width: 12px; }
1943
+ .kol-toc-row[data-active] .kol-toc-rule { width: 24px; }
1944
+ .kol-toc-tick .kol-toc-rule { width: 5px; }
1945
+ .kol-toc-label, .kol-toc-rule { transition: none; }
1946
+ }
@@ -696,3 +696,207 @@
696
696
  width: calc((100cqw - (var(--kol-catalog-n, 6) - 1) * 24px) / var(--kol-catalog-n, 6));
697
697
  }
698
698
 
699
+
700
+ /* ─────────────────────────── LayerStack ───────────────────────────────
701
+ * The layers panel (editor-panels-the-held-specs A1, kol-fxr 2026-09-03).
702
+ * Values are the engine's `.kol-compose-layer-*` rules verbatim, renamed:
703
+ * the DS owns this chrome now, and two owners of one class name is the drift
704
+ * this estate keeps paying for. CSS rather than utilities because the states,
705
+ * the drop indicators (pseudo-elements) and the hover-reveal (a descendant
706
+ * rule off `[data-layer-stack]:hover`) are not expressible as classes on the
707
+ * element.
708
+ * ───────────────────────────────────────────────────────────────────── */
709
+
710
+ .kol-layer-stack-line {
711
+ display: flex;
712
+ align-items: center;
713
+ gap: 2px;
714
+ }
715
+ .kol-layer-stack-collapse {
716
+ width: 16px;
717
+ height: 16px;
718
+ flex: 0 0 16px;
719
+ display: inline-flex;
720
+ align-items: center;
721
+ justify-content: center;
722
+ background: transparent;
723
+ border: none;
724
+ cursor: pointer;
725
+ color: var(--kol-fg-64);
726
+ padding: 0;
727
+ }
728
+ .kol-layer-stack-collapse:hover { color: var(--kol-surface-on-primary); }
729
+ /* Chevrons are focus chrome, not resting chrome (Figma model): hidden until
730
+ the pointer is inside the stack, then every container row shows its own. */
731
+ .kol-layer-stack-collapse { opacity: 0; transition: opacity 120ms; }
732
+ [data-layer-stack]:hover .kol-layer-stack-collapse { opacity: 1; }
733
+ /* Indent nested rows one chevron slot per level — a child's type icon aligns
734
+ under its parent's icon, not its name. Top-level rows sit flush. */
735
+ .kol-layer-stack-nest { padding-left: 16px; }
736
+
737
+ .kol-layer-stack-row {
738
+ display: flex;
739
+ align-items: center;
740
+ flex: 1 1 auto;
741
+ min-width: 0;
742
+ padding: 4px 60px 4px 8px; /* right padding reserves the two absolutely-
743
+ positioned toggle buttons */
744
+ color: var(--kol-fg-64);
745
+ border-radius: 4px;
746
+ cursor: grab;
747
+ position: relative;
748
+ }
749
+ .kol-layer-stack-row:hover {
750
+ background: var(--kol-fg-04);
751
+ color: var(--kol-surface-on-primary);
752
+ }
753
+ /* Selected = accent highlight; a selected container also tints its expanded
754
+ children block one shade lighter (Figma model). Hover stays grey. */
755
+ .kol-layer-stack-row.is-active {
756
+ background: color-mix(in srgb, var(--kol-accent-primary) 26%, transparent);
757
+ color: var(--kol-fg-emphasis);
758
+ }
759
+ .kol-layer-stack-row.is-tinted {
760
+ background: color-mix(in srgb, var(--kol-accent-primary) 11%, transparent);
761
+ }
762
+ /* Hidden layer — dim the icon + name only; the slashed eye stays legible. */
763
+ .kol-layer-stack-row.is-hidden .kol-layer-stack-main { opacity: 0.4; }
764
+ .kol-layer-stack-row.is-dragging { opacity: 0.4; cursor: grabbing; }
765
+ .kol-layer-stack-row[draggable]:active { cursor: grabbing; }
766
+
767
+ /* Drop indicator — 2px accent line at the top or bottom of the target row. */
768
+ .kol-layer-stack-row.is-drop-above::before,
769
+ .kol-layer-stack-row.is-drop-below::after {
770
+ content: '';
771
+ position: absolute;
772
+ left: 4px;
773
+ right: 4px;
774
+ height: 2px;
775
+ background: var(--kol-accent-primary);
776
+ pointer-events: none;
777
+ z-index: 1;
778
+ }
779
+ .kol-layer-stack-row.is-drop-above::before { top: -1px; }
780
+ .kol-layer-stack-row.is-drop-below::after { bottom: -1px; }
781
+
782
+ .kol-layer-stack-main {
783
+ display: flex;
784
+ align-items: center;
785
+ gap: 8px;
786
+ flex: 1 1 auto;
787
+ min-width: 0;
788
+ background: transparent;
789
+ border: none;
790
+ cursor: pointer;
791
+ color: inherit;
792
+ padding: 0;
793
+ text-align: left;
794
+ }
795
+ .kol-layer-stack-icon {
796
+ display: inline-flex;
797
+ align-items: center;
798
+ justify-content: center;
799
+ width: 18px;
800
+ height: 18px;
801
+ flex-shrink: 0;
802
+ }
803
+
804
+ /* The eye and the lock: absolute in the row's reserved right padding, hidden
805
+ until the row is hovered, PINNED visible when the layer is hidden / locked
806
+ or the row is active (`.is-pinned`), so a toggled state is never a secret. */
807
+ .kol-layer-stack-toggle {
808
+ position: absolute;
809
+ top: 0;
810
+ bottom: 0;
811
+ width: 28px;
812
+ display: inline-flex;
813
+ align-items: center;
814
+ justify-content: center;
815
+ border: none;
816
+ background: transparent;
817
+ border-radius: 4px;
818
+ padding: 0;
819
+ cursor: pointer;
820
+ color: var(--kol-oq-48);
821
+ opacity: 0;
822
+ transition: opacity 120ms;
823
+ }
824
+ .kol-layer-stack-toggle--eye { right: 28px; }
825
+ .kol-layer-stack-toggle--lock { right: 0; }
826
+ .kol-layer-stack-row:hover .kol-layer-stack-toggle,
827
+ .kol-layer-stack-toggle.is-pinned { opacity: 1; }
828
+ .kol-layer-stack-toggle:hover { color: var(--kol-fg-emphasis); background: var(--kol-fg-08); }
829
+ .kol-layer-stack-toggle.is-on { color: var(--kol-accent-primary); }
830
+
831
+ /* ── ColumnBrowser · the mobile four-zone row ──────────────────────────
832
+ * ColumnBrowserMobileViews §1 (kol-r2b2, 2026-09-03). Height follows zone 2,
833
+ * the 44px thumbnail: 60px, not the DS Table's `12px 16px`, which is right for
834
+ * a 14px glyph and three times too airy for a thumbnail. The divider starts at
835
+ * ZONE 3's left edge — 14 disclosure + 8 gap + 44 icon + 8 gap = 74 — which is
836
+ * what both references draw and what a utility cannot express, since it is a
837
+ * pseudo-element inset on a sibling boundary.
838
+ * ─────────────────────────────────────────────────────────────────────── */
839
+ .kol-column-browser-row--zones {
840
+ min-height: 60px;
841
+ position: relative;
842
+ }
843
+ .kol-column-browser-row--zones + .kol-column-browser-row--zones::before {
844
+ content: '';
845
+ position: absolute;
846
+ top: 0;
847
+ left: 74px; /* zone 3's left edge */
848
+ right: 0;
849
+ height: 1px;
850
+ background: var(--kol-oq-08);
851
+ pointer-events: none;
852
+ }
853
+ /* the thumbnail fills its box and crops — a media tile is the image, not a
854
+ letterboxed one */
855
+ .kol-column-browser-thumb img,
856
+ .kol-column-browser-thumb video {
857
+ width: 100%;
858
+ height: 100%;
859
+ object-fit: cover;
860
+ display: block;
861
+ }
862
+
863
+ /* ── ColumnBrowser · the mobile grid (item 14) ─────────────────────────
864
+ * 3-up below `md`. For a media bucket the thumbnail IS the tile, so the box is
865
+ * square and the name sits under it; counts, not dates (§2). */
866
+ .kol-column-browser-grid {
867
+ display: grid;
868
+ grid-template-columns: repeat(3, minmax(0, 1fr));
869
+ gap: var(--kol-spacing-3);
870
+ padding: var(--kol-spacing-3);
871
+ }
872
+ .kol-column-browser-tile {
873
+ display: flex;
874
+ flex-direction: column;
875
+ gap: var(--kol-spacing-1);
876
+ min-width: 0;
877
+ cursor: pointer;
878
+ background: transparent;
879
+ border: none;
880
+ padding: 0;
881
+ text-align: left;
882
+ }
883
+ .kol-column-browser-tile-box {
884
+ aspect-ratio: 1;
885
+ border-radius: 5px;
886
+ background: var(--kol-oq-04);
887
+ display: flex;
888
+ align-items: center;
889
+ justify-content: center;
890
+ overflow: hidden;
891
+ }
892
+ .kol-column-browser-tile-box img,
893
+ .kol-column-browser-tile-box video {
894
+ width: 100%;
895
+ height: 100%;
896
+ object-fit: cover;
897
+ display: block;
898
+ }
899
+ .kol-column-browser-tile.is-selected .kol-column-browser-tile-box {
900
+ outline: 2px solid var(--kol-accent-primary);
901
+ outline-offset: 1px;
902
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-theme",
3
- "version": "0.141.0",
3
+ "version": "0.143.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",