@kolkrabbi/kol-theme 0.1.1 → 0.3.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.
@@ -707,3 +707,144 @@ a:hover .icon-hover,
707
707
  transform: translate(0, 0) scale(1);
708
708
  opacity: 1;
709
709
  }
710
+
711
+ /* ─────────────────────────────────────────────────────────────────────
712
+ * CopyButton — atoms/CopyButton.jsx
713
+ * Copy-to-clipboard chip: clipboard icon + Copy/Copied label.
714
+ * Look extracted from CodeBlock's inline copy button; CodeBlock's
715
+ * .kol-codeblock-copy (kol-framework) now only positions it.
716
+ * ───────────────────────────────────────────────────────────────────── */
717
+ .kol-copy-btn {
718
+ display: inline-flex;
719
+ align-items: center;
720
+ gap: 6px;
721
+ padding: 6px 10px;
722
+ background: color-mix(in srgb, var(--kol-surface-primary) 80%, transparent);
723
+ border: 1px solid var(--kol-fg-16);
724
+ border-radius: 3px;
725
+ color: var(--kol-fg-64);
726
+ cursor: pointer;
727
+ font-family: var(--kol-font-family-mono, monospace);
728
+ font-size: 10px;
729
+ font-weight: 600;
730
+ letter-spacing: 0.08em;
731
+ line-height: 1;
732
+ text-transform: uppercase;
733
+ transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
734
+ }
735
+
736
+ .kol-copy-btn:hover {
737
+ color: var(--kol-surface-on-primary);
738
+ border-color: var(--kol-fg-48);
739
+ }
740
+
741
+ /* ─────────────────────────────────────────────────────────────────────
742
+ * Figure — atoms/Figure.jsx
743
+ * Caption'd media shell for long-form prose (label above, aspect-locked
744
+ * frame, figcaption below). Ported from the monorepo prose sheet; the
745
+ * label's text-transform:uppercase was dropped per the KOL no-auto-
746
+ * casing rule — author labels in their final case.
747
+ * ───────────────────────────────────────────────────────────────────── */
748
+ .kol-prose-figure {
749
+ margin-block: 2rem;
750
+ }
751
+
752
+ .kol-caption-label {
753
+ font-family: var(--kol-font-family-mono);
754
+ font-size: 12px;
755
+ font-weight: 500;
756
+ letter-spacing: 0.05em;
757
+ color: color-mix(in srgb, var(--kol-surface-on-primary) 48%, transparent);
758
+ margin-block-end: 0.5rem;
759
+ }
760
+
761
+ .kol-caption-text {
762
+ font-family: var(--kol-font-family-mono);
763
+ font-size: 14px;
764
+ font-weight: 400;
765
+ line-height: 140%;
766
+ color: color-mix(in srgb, var(--kol-surface-on-primary) 64%, transparent);
767
+ margin-block-start: 0.75rem;
768
+ }
769
+
770
+ /* ── target-file: packages/theme/kol-components-atoms.css ──────────────
771
+ * Append directly after the .kol-btn-quiet block
772
+ * (after `.kol-btn-quiet:not(:disabled):hover { opacity: 1; }`). */
773
+
774
+ /* .kol-btn-pressed — toggle-on state (Button `pressed` prop, aria-pressed).
775
+ * Hover-level fill held at rest so a pressed toggle reads as lit. Pairs
776
+ * with `quiet`: Button drops kol-btn-quiet while pressed, giving the
777
+ * tool-palette dim-at-rest → lit-when-active idiom. */
778
+ .kol-btn-pressed {
779
+ background-color: var(--kol-fg-08);
780
+ color: var(--kol-surface-on-primary);
781
+ }
782
+
783
+ /* ─────────────────────────────────────────────────────────────────────
784
+ * Type-specimen kit — TARGET: packages/theme/kol-components-atoms.css
785
+ * (the two .kol-prose-* rules may alternatively land in the prose
786
+ * section of packages/theme/kol-typography.css per the ProsePreview
787
+ * lobby spec — pick one home, not both.)
788
+ *
789
+ * Ported from kol-monorepo apps/brand/src/components/framework/
790
+ * kol-framework.css. NOT ported (already in kol-typography.css, richer
791
+ * DS versions win): .kol-prose pre, .kol-prose code, .kol-prose pre code.
792
+ * Also already in kol-components-atoms.css: .kol-prose-figure,
793
+ * .kol-caption-label, .kol-caption-text.
794
+ * No text-transform rules existed in the source CSS; the components'
795
+ * Tailwind `uppercase` classes were dropped per the KOL no-auto-casing
796
+ * rule — author labels/pullouts in their final case.
797
+ * ───────────────────────────────────────────────────────────────────── */
798
+
799
+ /* ─── TypeSample — atoms/TypeSample.jsx ───
800
+ Wrapper padding inlined in the component; adjacent-sibling hairline
801
+ separates stacked samples. */
802
+ .kol-type-sample + .kol-type-sample {
803
+ border-top: 1px solid var(--kol-fg-08);
804
+ }
805
+
806
+ /* ─── TypeSpecCard — atoms/TypeSpecCard.jsx ───
807
+ Layout inlined in the component; descendant <p> overrides give sample
808
+ prose 16px rhythm (Preflight zeroes <p> margin). */
809
+ .kol-type-spec-sample p { margin: 0 0 16px; }
810
+ .kol-type-spec-sample p:last-child { margin-bottom: 0; }
811
+
812
+ /* ─── ProsePreview — atoms/ProsePreview.jsx ───
813
+ Prose chrome beyond the base .kol-prose contract. */
814
+ .kol-prose-indented {
815
+ padding-left: 32px;
816
+ border-left: 1px solid var(--kol-fg-16);
817
+ }
818
+
819
+ .kol-prose-pullout {
820
+ padding: 16px 0;
821
+ margin: 32px 0;
822
+ border-top: 1px solid var(--kol-fg-08);
823
+ border-bottom: 1px solid var(--kol-fg-08);
824
+ }
825
+
826
+ /* =============================================================================
827
+ * TextPressure (atom)
828
+ * append to packages/theme/kol-components-atoms.css
829
+ *
830
+ * Only the outlined-ghost layer lives here — it needs a ::after pseudo-element
831
+ * and -webkit-text-stroke, neither expressible in Tailwind or inline style.
832
+ * Everything else (layout, sizing, weight) is Tailwind utilities / inline vars
833
+ * on the JSX. Stroke color comes in through the inline `--kol-text-pressure-
834
+ * stroke` custom property (defaulted here so the rule is standalone-safe).
835
+ * ============================================================================= */
836
+
837
+ .kol-text-pressure--stroke .kol-text-pressure-char {
838
+ position: relative;
839
+ }
840
+
841
+ .kol-text-pressure--stroke .kol-text-pressure-char::after {
842
+ content: attr(data-char);
843
+ position: absolute;
844
+ left: 0;
845
+ top: 0;
846
+ color: transparent;
847
+ z-index: -1;
848
+ -webkit-text-stroke-width: 3px;
849
+ -webkit-text-stroke-color: var(--kol-text-pressure-stroke, var(--kol-accent-primary));
850
+ }
@@ -253,3 +253,99 @@
253
253
  padding: 0 12px;
254
254
  font-size: 14px;
255
255
  }
256
+
257
+ /* ─────────────────────────────────────────────────────────────────────
258
+ * SegmentedToggle — molecules/SegmentedToggle.jsx
259
+ * Bordered strip of joined cells sharing one outer stroke, thin
260
+ * dividers between cells, filled active cell.
261
+ *
262
+ * Chrome lives HERE, not in Tailwind utilities: Tailwind never scans
263
+ * package sources, so utility-class chrome inside a published
264
+ * component silently vanishes for every consumer. Any component whose
265
+ * look depends on flex/border/rounded utilities needs a kol-* class
266
+ * in this package instead.
267
+ * ───────────────────────────────────────────────────────────────────── */
268
+ .kol-seg {
269
+ display: flex;
270
+ height: 26px;
271
+ border: 1px solid var(--kol-fg-04);
272
+ border-radius: var(--kol-radius-sm);
273
+ overflow: hidden;
274
+ }
275
+
276
+ .kol-seg--sm { height: 16px; }
277
+
278
+ .kol-seg-cell {
279
+ flex: 1;
280
+ display: inline-flex;
281
+ align-items: center;
282
+ justify-content: center;
283
+ padding: 0 10px;
284
+ background: transparent;
285
+ border: none;
286
+ cursor: pointer;
287
+ white-space: nowrap;
288
+ color: var(--kol-fg-meta);
289
+ transition: color var(--kol-transition-base),
290
+ background-color var(--kol-transition-base);
291
+ }
292
+
293
+ .kol-seg-cell + .kol-seg-cell { border-left: 1px solid var(--kol-fg-04); }
294
+
295
+ .kol-seg-cell:hover { color: var(--kol-fg-emphasis); }
296
+
297
+ .kol-seg-cell.is-active {
298
+ background: var(--kol-surface-secondary);
299
+ color: var(--kol-fg-emphasis);
300
+ }
301
+
302
+ .kol-seg-cell:focus-visible {
303
+ outline: 1px solid var(--kol-fg-emphasis);
304
+ outline-offset: -2px;
305
+ }
306
+
307
+ /* =============================================================================
308
+ * Color-doc widget chrome — ColorRamp · SpectrumGrid
309
+ *
310
+ * Almost everything is Tailwind/inline in the components; only the ONE bit
311
+ * Tailwind can't express against a dynamic grid template lives here: the
312
+ * SpectrumGrid responsive narrowing. Fold into packages/theme (e.g.
313
+ * kol-components-organisms.css) when these graduate from the lobby.
314
+ *
315
+ * How it works: SpectrumGrid declares its template inline with var() fallbacks —
316
+ * grid-template-columns: var(--kol-sg-label-w, 100px) repeat(N, minmax(0,1fr));
317
+ * gap: var(--kol-sg-gap, 4px);
318
+ * so it renders correctly with NO stylesheet loaded. On narrow viewports we just
319
+ * re-declare those two custom properties on the grid CLASS; the inline var()
320
+ * reads pick them up (the class provides the value, so a media-query override
321
+ * cascades — there's no competing inline *set* of the same property). The
322
+ * per-cell hex readout is hidden separately via Tailwind `max-[900px]:hidden`.
323
+ * ============================================================================= */
324
+
325
+ @media (max-width: 900px) {
326
+ .kol-spectrum-grid {
327
+ --kol-sg-label-w: 72px;
328
+ --kol-sg-gap: 2px;
329
+ }
330
+ }
331
+
332
+ /* SwatchControls chrome — the only bespoke CSS the component needs.
333
+ *
334
+ * The paint chips + sample chip reuse ColorSwatch's `halo` variant for the
335
+ * tuned double-ring, so the ONLY rule left is the NoneMarker's "set to none"
336
+ * affordance: a red diagonal slash on white (a two-stop 45° gradient) over a
337
+ * themed 1px ring. Neither is a Tailwind utility, so it lands here.
338
+ *
339
+ * Append to packages/theme/kol-components-molecules.css. */
340
+ .kol-swatch-none-marker {
341
+ background: linear-gradient(
342
+ 45deg,
343
+ #fff 0%,
344
+ #fff 42%,
345
+ #DC2626 42%,
346
+ #DC2626 58%,
347
+ #fff 58%,
348
+ #fff 100%
349
+ );
350
+ box-shadow: 0 0 0 1px var(--kol-fg-32);
351
+ }
@@ -218,3 +218,192 @@
218
218
  padding: 6px 10px;
219
219
  }
220
220
  }
221
+
222
+ /*
223
+ * ─────────────────────────────────────────────────────────────────────
224
+ * FeatureSplit — src/components/organisms/FeatureSplit.jsx
225
+ * ─────────────────────────────────────────────────────────────────────
226
+ *
227
+ * Destined for kol-components-organisms.css.
228
+ *
229
+ * Structural (applied by FeatureSplit.jsx; do not use directly):
230
+ * .kol-feature-split section — surface bg + ink
231
+ * .kol-feature-split-kicker mono eyebrow, accent color
232
+ * .kol-feature-split-pull display pull headline
233
+ * .kol-feature-split-pull em italic accent inside the pull
234
+ * .kol-feature-split-body lede paragraph, 72% ink
235
+ * .kol-feature-split-meta stats strip — hairline top border
236
+ * .kol-feature-split-meta-num stat number
237
+ * .kol-feature-split-meta-label stat label — mono, 48% ink
238
+ * .kol-feature-split-visual img cover-fit media
239
+ * .kol-feature-split-visual-veil bottom gradient (caption legibility)
240
+ * .kol-feature-split-visual-caption mono caption over the media
241
+ *
242
+ * Port notes (from apps/brand kol-site.css `.site-feature*`):
243
+ * - text-transform: uppercase DROPPED from kicker / meta-label / caption —
244
+ * KOL rule: author casing at the call site.
245
+ * - Hardcoded "Right Grotesk" / "Right Grotesk Text" / "Right Grotesk Wide"
246
+ * families → var(--kol-font-family-sans) (this theme tokenizes only
247
+ * sans / sans-narrow / sans-compact; no Text/Wide tokens).
248
+ * - App `--kol-pad-page-*` padding and the shared `.site-*` full-bleed
249
+ * rule moved to Tailwind utilities in the JSX (`fullBleed` prop).
250
+ */
251
+
252
+ /* =============================================================================
253
+ * FeatureSplit
254
+ * ============================================================================= */
255
+
256
+ .kol-feature-split {
257
+ background: var(--kol-surface-primary);
258
+ color: var(--kol-surface-on-primary);
259
+ }
260
+
261
+ .kol-feature-split-kicker {
262
+ font-family: var(--kol-font-family-mono, monospace);
263
+ font-size: 18px;
264
+ font-weight: 600;
265
+ letter-spacing: 0.14em;
266
+ color: var(--kol-accent-primary);
267
+ }
268
+
269
+ .kol-feature-split-pull {
270
+ margin: 0;
271
+ font-family: var(--kol-font-family-sans);
272
+ font-weight: 700;
273
+ font-size: clamp(40px, 5.5vw, 72px);
274
+ line-height: 1.05;
275
+ letter-spacing: -0.02em;
276
+ color: var(--kol-surface-on-primary);
277
+ }
278
+
279
+ .kol-feature-split-pull em {
280
+ font-family: var(--kol-font-family-sans);
281
+ font-feature-settings: "liga", "dlig";
282
+ font-weight: 700;
283
+ font-style: italic;
284
+ color: var(--kol-accent-primary);
285
+ }
286
+
287
+ .kol-feature-split-body {
288
+ margin: 0;
289
+ font-family: var(--kol-font-family-sans);
290
+ font-weight: 400;
291
+ font-size: 16px;
292
+ line-height: 1.6;
293
+ color: color-mix(in srgb, var(--kol-surface-on-primary) 72%, transparent);
294
+ }
295
+
296
+ .kol-feature-split-meta {
297
+ border-top: 1px solid color-mix(in srgb, var(--kol-surface-on-primary) 8%, transparent);
298
+ }
299
+
300
+ .kol-feature-split-meta-num {
301
+ font-family: var(--kol-font-family-sans);
302
+ font-weight: 900;
303
+ font-size: 32px;
304
+ line-height: 1;
305
+ letter-spacing: -0.02em;
306
+ color: var(--kol-surface-on-primary);
307
+ }
308
+
309
+ .kol-feature-split-meta-label {
310
+ font-family: var(--kol-font-family-mono, monospace);
311
+ font-size: 10px;
312
+ font-weight: 600;
313
+ letter-spacing: 0.14em;
314
+ color: color-mix(in srgb, var(--kol-surface-on-primary) 48%, transparent);
315
+ }
316
+
317
+ .kol-feature-split-visual img {
318
+ width: 100%;
319
+ height: 100%;
320
+ object-fit: cover;
321
+ display: block;
322
+ }
323
+
324
+ .kol-feature-split-visual-veil {
325
+ position: absolute;
326
+ inset: 0;
327
+ background: linear-gradient(
328
+ 180deg,
329
+ transparent 0%,
330
+ transparent 60%,
331
+ color-mix(in srgb, var(--kol-surface-primary) 48%, transparent) 100%
332
+ );
333
+ pointer-events: none;
334
+ }
335
+
336
+ .kol-feature-split-visual-caption {
337
+ position: absolute;
338
+ left: 24px;
339
+ bottom: 24px;
340
+ font-family: var(--kol-font-family-mono, monospace);
341
+ font-size: 10px;
342
+ font-weight: 600;
343
+ letter-spacing: 0.14em;
344
+ color: color-mix(in srgb, var(--kol-surface-on-primary) 80%, transparent);
345
+ }
346
+
347
+ /*
348
+ * ─────────────────────────────────────────────────────────────────────
349
+ * FullBleedHero — src/components/organisms/FullBleedHero.jsx
350
+ * ─────────────────────────────────────────────────────────────────────
351
+ *
352
+ * Destined for kol-components-organisms.css.
353
+ *
354
+ * Structural (applied by FullBleedHero.jsx; do not use directly):
355
+ * .kol-full-bleed-hero section root — surface bg behind the media
356
+ * .kol-full-bleed-hero-media cover-fit media layer (Image / HlsVideo /
357
+ * plain <video> / caller-supplied node)
358
+ *
359
+ * Why CSS and not Tailwind for the media layer: the Image molecule bakes
360
+ * `max-w-full h-auto` into every <img>; an inline `h-full` utility can't
361
+ * reliably out-cascade `h-auto` (same utilities layer — stylesheet order,
362
+ * not class order, decides). This unlayered rule wins over Tailwind's
363
+ * layered utilities and pins cover-fill identically for img, video, and
364
+ * caller-supplied media nodes.
365
+ */
366
+
367
+ /* =============================================================================
368
+ * FullBleedHero
369
+ * ============================================================================= */
370
+
371
+ .kol-full-bleed-hero {
372
+ background: var(--kol-surface-primary);
373
+ }
374
+
375
+ .kol-full-bleed-hero-media {
376
+ position: absolute;
377
+ inset: 0;
378
+ width: 100%;
379
+ height: 100%;
380
+ object-fit: cover;
381
+ object-position: center;
382
+ }
383
+
384
+ /* =============================================================================
385
+ * FeaturedCarousel — src/components/organisms/FeaturedCarousel.jsx
386
+ * =============================================================================
387
+ *
388
+ * Append to packages/theme/kol-components-organisms.css.
389
+ *
390
+ * FeaturedCarousel rebuilds on the shared Carousel *core* — it reuses the
391
+ * `.kol-embla*` chrome verbatim (viewport / container / slide / controls /
392
+ * `.is-slides` wide-slide width), so NONE of that is redefined here. Frame,
393
+ * progress bar, and glass positioning are Tailwind utilities on the JSX.
394
+ *
395
+ * The one rule that can't be a utility: the media layer. The Image molecule
396
+ * bakes `h-auto` (a Tailwind layer utility), so an inline `h-full` can't
397
+ * reliably out-cascade it — the same reason FullBleedHero uses a theme rule.
398
+ * This unlayered rule wins and pins image / video / caller-node media as a
399
+ * cover-fit background over the frame.
400
+ */
401
+
402
+ .kol-featured-carousel-media {
403
+ position: absolute;
404
+ inset: 0;
405
+ width: 100%;
406
+ height: 100%;
407
+ object-fit: cover;
408
+ object-position: center;
409
+ }
@@ -1088,3 +1088,45 @@
1088
1088
  --font-narrow: 'Right Grotesk Narrow', 'Right Grotesk', sans-serif;
1089
1089
  /* --font-mono lives in kol-typography-mono.css — keeps mono concerns in one file. */
1090
1090
  }
1091
+
1092
+ /* TARGET: packages/theme/kol-typography.css — append to the `.kol-prose` section
1093
+ * ---------------------------------------------------------------------------
1094
+ * PortableTextRenderer (organism) leans on three prose hooks this repo's prose
1095
+ * sheet is missing. Figure's `.kol-prose-figure` / `.kol-caption-label` /
1096
+ * `.kol-caption-text` already exist; these three do not. The renderer degrades
1097
+ * gracefully without them (segmentTitle → plain inline text, caption → normal
1098
+ * paragraph, links → inherited color), so this is polish, not a hard dep.
1099
+ *
1100
+ * NOTE ON PLACEMENT: these are prose *typography* classes, so their home is
1101
+ * kol-typography.css, NOT the kol-components-{atoms,molecules,organisms}.css
1102
+ * component-chrome sheets. Flagged so it lands in the right file.
1103
+ */
1104
+
1105
+ /* inline mark — emphasised run inside a paragraph */
1106
+ .kol-segment-title {
1107
+ font-family: var(--kol-font-family-sans-compact);
1108
+ font-weight: 500;
1109
+ color: var(--kol-surface-on-primary);
1110
+ }
1111
+
1112
+ /* standalone caption block (the `caption` block type) */
1113
+ .kol-prose .caption {
1114
+ margin: -12px 0 24px;
1115
+ font-family: var(--kol-font-family-mono);
1116
+ font-size: 12px;
1117
+ line-height: 16px;
1118
+ letter-spacing: 0.02em;
1119
+ color: var(--kol-fg-48, color-mix(in srgb, var(--kol-surface-on-primary) 48%, transparent));
1120
+ }
1121
+
1122
+ /* inline links (the `link` mark) */
1123
+ .kol-prose a {
1124
+ color: inherit;
1125
+ text-decoration: underline;
1126
+ text-underline-offset: 3px;
1127
+ text-decoration-color: var(--kol-fg-32, color-mix(in srgb, var(--kol-surface-on-primary) 32%, transparent));
1128
+ transition: text-decoration-color 0.15s ease;
1129
+ }
1130
+ .kol-prose a:hover {
1131
+ text-decoration-color: currentColor;
1132
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-theme",
3
- "version": "0.1.1",
3
+ "version": "0.3.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",