@kolkrabbi/kol-component 0.233.0 → 0.235.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.
Files changed (93) hide show
  1. package/package.json +3 -3
  2. package/src/atoms/ActionButton.jsx +1 -1
  3. package/src/atoms/AnimatedTitle.jsx +1 -1
  4. package/src/atoms/AudioPlayer.jsx +1 -1
  5. package/src/atoms/Avatar.jsx +1 -1
  6. package/src/atoms/Badge.jsx +1 -1
  7. package/src/atoms/Figure.jsx +1 -1
  8. package/src/atoms/FileIcon.jsx +1 -1
  9. package/src/atoms/Kbd.jsx +1 -1
  10. package/src/atoms/Pill.jsx +1 -1
  11. package/src/atoms/Tag.jsx +12 -1
  12. package/src/atoms/Textarea.jsx +2 -2
  13. package/src/atoms/ToggleSwitch.jsx +1 -1
  14. package/src/atoms/XYPad.jsx +1 -1
  15. package/src/hooks/useDragResize.js +16 -4
  16. package/src/molecules/AlignmentGrid.jsx +1 -1
  17. package/src/molecules/AudioSheet.jsx +1 -1
  18. package/src/molecules/CodeBlock.jsx +1 -1
  19. package/src/molecules/ColorRamp.jsx +1 -1
  20. package/src/molecules/ContentItem.jsx +1 -1
  21. package/src/molecules/ContentRow.jsx +1 -1
  22. package/src/molecules/CopyButton.jsx +1 -1
  23. package/src/molecules/DocFrontmatter.jsx +1 -1
  24. package/src/molecules/DocPage.jsx +1 -1
  25. package/src/molecules/DocsToc.jsx +1 -1
  26. package/src/molecules/Dropdown.jsx +1 -1
  27. package/src/molecules/DropdownTagFilter.jsx +1 -0
  28. package/src/molecules/EmptyState.jsx +1 -1
  29. package/src/molecules/FieldRow.jsx +1 -1
  30. package/src/molecules/ImageBlock.jsx +1 -1
  31. package/src/molecules/KindPreview.jsx +1 -1
  32. package/src/molecules/MediaTile.jsx +1 -1
  33. package/src/molecules/MenuPopover.jsx +1 -1
  34. package/src/molecules/OptionRow.jsx +1 -1
  35. package/src/molecules/PageHeader.jsx +1 -1
  36. package/src/molecules/PlaybackBar.jsx +1 -1
  37. package/src/molecules/ProfileCard.jsx +1 -1
  38. package/src/molecules/QuantityInput.jsx +1 -1
  39. package/src/molecules/QuickLookFrame.jsx +1 -1
  40. package/src/molecules/RowMenuButton.jsx +1 -1
  41. package/src/molecules/SectionText.jsx +1 -1
  42. package/src/molecules/ShapeDropdown.jsx +1 -1
  43. package/src/molecules/ShellDrawer.jsx +1 -1
  44. package/src/molecules/SortControls.jsx +1 -1
  45. package/src/molecules/SpecList.jsx +1 -1
  46. package/src/molecules/SplitToolButton.jsx +2 -2
  47. package/src/molecules/Stepper.jsx +1 -1
  48. package/src/molecules/SwatchControls.jsx +2 -2
  49. package/src/molecules/TabsRow.jsx +1 -1
  50. package/src/molecules/TiltBento.jsx +1 -1
  51. package/src/molecules/VideoBlock.jsx +1 -1
  52. package/src/molecules/VideoSheet.jsx +1 -1
  53. package/src/organisms/Canvas.jsx +3 -3
  54. package/src/organisms/ColumnBrowser.jsx +1 -1
  55. package/src/organisms/ContentCollection.jsx +1 -1
  56. package/src/organisms/CurveEditor.jsx +1 -1
  57. package/src/organisms/DocumentEditor.jsx +1 -1
  58. package/src/organisms/FeaturedCarousel.jsx +1 -1
  59. package/src/organisms/FramedMediaBand.jsx +1 -1
  60. package/src/organisms/GalleryCarousel.jsx +1 -1
  61. package/src/organisms/KeyframeEditor.jsx +1 -1
  62. package/src/organisms/LayerStack.jsx +2 -2
  63. package/src/organisms/MediaLibrary.jsx +2 -2
  64. package/src/organisms/MediaLibraryExplorer.jsx +1 -1
  65. package/src/organisms/MediaLibraryPages.jsx +1 -1
  66. package/src/organisms/MediaTileGallery.jsx +1 -1
  67. package/src/organisms/RecordManager.jsx +1 -1
  68. package/src/organisms/SectionCards.jsx +1 -1
  69. package/src/organisms/SectionCta.jsx +1 -1
  70. package/src/organisms/SectionFaq.jsx +1 -1
  71. package/src/organisms/SectionHero.jsx +1 -1
  72. package/src/organisms/SectionNewsletter.jsx +1 -1
  73. package/src/organisms/SectionSplit.jsx +1 -1
  74. package/src/organisms/SettingsPanel.jsx +8 -8
  75. package/src/organisms/ShellSearchOverlay.jsx +26 -16
  76. package/src/organisms/ShortcutsOverlay.jsx +1 -1
  77. package/src/organisms/SpectrumControls.jsx +4 -4
  78. package/src/organisms/SpectrumGrid.jsx +1 -1
  79. package/src/organisms/Table.jsx +4 -2
  80. package/src/organisms/ToolPalette.jsx +1 -1
  81. package/src/utilities/AsciiCursor.jsx +1 -1
  82. package/src/utilities/AssetGrid.jsx +1 -1
  83. package/src/utilities/ButtonGroup.jsx +1 -1
  84. package/src/utilities/CropOverlay.jsx +1 -1
  85. package/src/utilities/CurveOverlay.jsx +1 -1
  86. package/src/utilities/ErrorBoundary.jsx +1 -1
  87. package/src/utilities/ExitPreview.jsx +1 -1
  88. package/src/utilities/FullscreenOverlay.jsx +1 -1
  89. package/src/utilities/OverlayGlassPanel.jsx +1 -1
  90. package/src/utilities/Popover.jsx +1 -1
  91. package/src/utilities/ProsePreview.jsx +1 -1
  92. package/src/utilities/TiltCard.jsx +1 -1
  93. package/src/utilities/TransparentX.jsx +1 -1
@@ -419,7 +419,7 @@ function isTypingTarget(el) {
419
419
  }
420
420
 
421
421
  /**
422
- * PanZoomViewport — infinite-canvas viewport (pan + zoom), and the one that
422
+ * PanZoomViewport — An infinite canvas to pan and zoom. infinite-canvas viewport (pan + zoom), and the one that
423
423
  * publishes `CanvasZoomContext`.
424
424
  *
425
425
  * Pan: hold Space + drag (cursor grab/grabbing), or two-finger trackpad
@@ -787,7 +787,7 @@ export function useFrameGeom(containerRef, virtualWidth = CANVAS_VIRTUAL_W) {
787
787
  }
788
788
 
789
789
  /**
790
- * CanvasRuler — top + left rulers in virtual-canvas px, mapped through the
790
+ * CanvasRuler — Rulers along the canvas edges. top + left rulers in virtual-canvas px, mapped through the
791
791
  * measured frame geometry (see useFrameGeom).
792
792
  *
793
793
  * Dragging off a ruler starts a new guide: the ruler only ANNOUNCES the
@@ -900,7 +900,7 @@ function GuideLine({ axis, screenPos, interactive, onGrab }) {
900
900
  }
901
901
 
902
902
  /**
903
- * CanvasGuides — ruler guides rendered at the viewport level so each line
903
+ * CanvasGuides — Guide lines across the whole canvas. ruler guides rendered at the viewport level so each line
904
904
  * spans the entire visible canvas area instead of clipping to the letterbox
905
905
  * frame. Positions are stored in virtual canvas px and threaded down as props
906
906
  * — the viewport is chrome and owns no guide state; the screen mapping is the
@@ -12,7 +12,7 @@ import useMarquee from '../hooks/useMarquee.js'
12
12
  import { GRAB_COLUMN } from '../utilities/motion.js'
13
13
 
14
14
  /**
15
- * ColumnBrowser — Finder-style Miller columns over a flat key space (kol-r2b2's
15
+ * ColumnBrowser — Finder-style columns over a bucket. Finder-style Miller columns over a flat key space (kol-r2b2's
16
16
  * `src/ColumnBrowser.jsx`, built and ruled there first — user 2026-08-27: "make
17
17
  * it locally first, then ship it" — and shipped verbatim; ticket ColumnBrowser).
18
18
  * The listing surface's FOLDER view: it replaces the folder rows above the
@@ -1,7 +1,7 @@
1
1
  import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
2
2
 
3
3
  /**
4
- * ContentCollection — the container half of the content-card system: the
4
+ * ContentCollection — A grid or list of content items. the container half of the content-card system: the
5
5
  * grid/list switch plus the motion that belongs to it. Animation lives in
6
6
  * the wrapper — the only place it can (06-content-card-system.md §6);
7
7
  * cards never animate themselves.
@@ -109,7 +109,7 @@ function TermRow({ term, onSet, onRemove, canRemove }) {
109
109
  }
110
110
 
111
111
  /**
112
- * CurveEditor — curve authoring: a kind picker, per-kind ranges and
112
+ * CurveEditor — Author a curve by kind and expression. curve authoring: a kind picker, per-kind ranges and
113
113
  * EXPRESSION fields, and the epicycle term list.
114
114
  *
115
115
  * Lifted from kol-fxr's editor (`compose/inspectors/CurveEditor.jsx`,
@@ -11,7 +11,7 @@ import { splitFrontmatter, joinFrontmatter } from '@kolkrabbi/kol-markdown'
11
11
  import { readDraft, writeDraft, clearDraft } from '../utilities/localDrafts.js'
12
12
 
13
13
  /**
14
- * DocumentEditor — write a text file: open one, or make a new one (media D1 plan v2, 2026-09-26).
14
+ * DocumentEditor — Open or write a text file. write a text file: open one, or make a new one (media D1 plan v2, 2026-09-26).
15
15
  *
16
16
  * The concept is kol-olina's brand notes page (NoteEdit): a title, a markdown body, Write / Preview,
17
17
  * attachments from the bucket, a page for writing something NEW rather than a button hidden in a
@@ -85,7 +85,7 @@ function SlideMedia({ media, active = true, onEnded, onTimeUpdate }) {
85
85
  * the one hero (SectionHeroRound2); this stays as its engine and renders
86
86
  * unchanged. Removed from the barrel at the next major.
87
87
  *
88
- * FeaturedCarousel — a full-width carousel of featured media: each wide slide
88
+ * FeaturedCarousel — A full-width carousel of featured media. a full-width carousel of featured media: each wide slide
89
89
  * is a fixed-height frame with an image or HLS-video background and a centered
90
90
  * OverlayGlassPanel (title / description / CTA), plus prev/next and optional
91
91
  * autoplay with a progress bar.
@@ -1,7 +1,7 @@
1
1
  import Image from '../atoms/Image'
2
2
 
3
3
  /**
4
- * FramedMediaBand — full-width media breather band: a centered, aspect-locked
4
+ * FramedMediaBand — A full-width band with one framed image. full-width media breather band: a centered, aspect-locked
5
5
  * frame (bordered surface-secondary panel, rounded) holding one object-cover
6
6
  * image. Extracted from the foundry TypefacePage, where it sat inlined 5x
7
7
  * verbatim between content sections. The double radius (`rounded` panel,
@@ -9,7 +9,7 @@ import MediaViewer from './MediaViewer.jsx'
9
9
  const DRAG_THRESHOLD_SQ = 25
10
10
 
11
11
  /**
12
- * GalleryCarousel — the project-detail media gallery: a horizontal, drag-scroll
12
+ * GalleryCarousel — A shelf of media that opens fullscreen. the project-detail media gallery: a horizontal, drag-scroll
13
13
  * shelf of image/video tiles where clicking a tile opens THE shared fullscreen
14
14
  * MediaViewer starting at that tile.
15
15
  *
@@ -22,7 +22,7 @@ export const DEFAULT_KEYFRAMES = [
22
22
  ]
23
23
 
24
24
  /**
25
- * KeyframeEditor — a keyframe list over a pose track, kept sorted by `t`.
25
+ * KeyframeEditor — A sorted list of keyframes. a keyframe list over a pose track, kept sorted by `t`.
26
26
  *
27
27
  * { t: 0..1, rot: [x, y, z] RADIANS, pos: [x, y, z], scale, ease }
28
28
  *
@@ -207,7 +207,7 @@ function CanvasRow({ IconC, active, collapsed, onToggleCollapse, onSelect }) {
207
207
  }
208
208
 
209
209
  /**
210
- * LayerStack — the layers panel: a z-stacked tree of rows with HTML5 drag to
210
+ * LayerStack — The layers panel. the layers panel: a z-stacked tree of rows with HTML5 drag to
211
211
  * reorder AND reparent in one gesture, hover-revealed eye + lock toggles,
212
212
  * inline rename, collapsible containers, and a Canvas root row above it all.
213
213
  *
@@ -440,7 +440,7 @@ export default function LayerStack({
440
440
  }
441
441
 
442
442
  /**
443
- * AddLayerButton — the `+` that opens a menu of layer types. Lives in the
443
+ * AddLayerButton — Add a layer from a menu. the `+` that opens a menu of layer types. Lives in the
444
444
  * panel's tab row, not the stack footer (the source's placement). One entry
445
445
  * may expand inline to a kind picker so adding "a shape" doesn't silently
446
446
  * default to the first kind.
@@ -19,7 +19,7 @@ import { SettingsChipRow, chipCls } from './SettingsPanel.jsx'
19
19
  import { filterMedia } from '../utilities/mediaSearch.js'
20
20
 
21
21
  /**
22
- * MediaLibrary — a browser over an object bucket, in two views over one
22
+ * MediaLibrary — Browse and pick files from a bucket. a browser over an object bucket, in two views over one
23
23
  * headless core. Consolidates four consumer forks (kol-ds-fxr, kol-labs-single,
24
24
  * kol-client-kolkrabbi, kol-website/brand — 9 files, ~1542 lines) that had
25
25
  * already diverged: only fxr carried the canvas-taint fix, only labs carried
@@ -263,7 +263,7 @@ function sortFiles(files, { by, dir }) {
263
263
  }
264
264
 
265
265
  /**
266
- * MediaLibraryProvider — the headless core: one list call, then a
266
+ * MediaLibraryProvider — The data core behind the media views. the headless core: one list call, then a
267
267
  * PREFIX-SCOPED view over it: the folders directly under the prefix, the
268
268
  * files at that level (or the whole subtree in `flat`), the kind allow-list,
269
269
  * the search, the sort with direction, and paging.
@@ -4,7 +4,7 @@ import { useModal } from '../molecules/Modal.jsx'
4
4
  import useMediaQuery from '../hooks/useMediaQuery.js'
5
5
 
6
6
  /**
7
- * MediaLibraryExplorer — the media surface, and since 2026-09-22 a thin name for it.
7
+ * MediaLibraryExplorer — The media browser. the media surface, and since 2026-09-22 a thin name for it.
8
8
  *
9
9
  * IT USED TO BE THE MERGE ITSELF: it held a BROWSE · FILES switch and mounted one of two pages,
10
10
  * each of which listed the bucket, drew its own header and printed its own count. The user's read
@@ -596,7 +596,7 @@ function FileEditorHost({ o, client, bucket, onClose, onSaved, assets }) {
596
596
  }
597
597
 
598
598
  /**
599
- * MediaInspector — the full-screen viewer for one file in a set: image, video
599
+ * MediaInspector — View one file at full size. the full-screen viewer for one file in a set: image, video
600
600
  * (scrubbable, audio on), audio, or a document page, in one `QuickLookFrame`, with
601
601
  * prev / next fixed at the viewport edges.
602
602
  *
@@ -2,7 +2,7 @@ import { useState } from 'react'
2
2
  import MediaViewer from './MediaViewer.jsx'
3
3
 
4
4
  /**
5
- * MediaTileGallery — a stack or grid of framed media tiles that open THE
5
+ * MediaTileGallery — Media tiles that open a fullscreen viewer. a stack or grid of framed media tiles that open THE
6
6
  * shared fullscreen MediaViewer at the clicked tile, paged across all items
7
7
  * (the monorepo's FullscreenGallery recreated on the shared viewer instead of
8
8
  * its nav-less single image; the AssetFigure/AssetGrid deps are dropped —
@@ -35,7 +35,7 @@ const ToolbarIcon = ({ name, label, onClick, active = false, triggerClassName })
35
35
  )
36
36
 
37
37
  /**
38
- * RecordManager — full-screen CMS record surface (lobby: RecordManager,
38
+ * RecordManager — A full-screen CMS record editor. full-screen CMS record surface (lobby: RecordManager,
39
39
  * reference: Framer CMS). A reorderable record table plus a slide-over detail
40
40
  * panel of FieldRows.
41
41
  *
@@ -6,7 +6,7 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
6
6
  import { minHeightClass } from './sectionHeights.js'
7
7
 
8
8
  /**
9
- * SectionCards — the "N-up feature cards" band: a `SectionText` header over a
9
+ * SectionCards — A header over a row of feature cards. the "N-up feature cards" band: a `SectionText` header over a
10
10
  * responsive row of `SectionCardItem` cards, capped by an optional centred
11
11
  * action row. `FeaturesCardSection` is this component under its old name and
12
12
  * prop names (`headerLabel` → `headline`, `headerDescription` → `body`,
@@ -5,7 +5,7 @@ import SectionText from '../molecules/SectionText.jsx'
5
5
  import { minHeightClass } from './sectionHeights.js'
6
6
 
7
7
  /**
8
- * SectionCta — the editorial two-column contact/CTA band: a large display
8
+ * SectionCta — A closing call-to-action band. the editorial two-column contact/CTA band: a large display
9
9
  * wordmark on the left (e.g. "/ CONNECT") and a right column of stacked
10
10
  * label-over-value rows, each a `SectionText` (label in the helper voice,
11
11
  * value as a heading-01; a row with `href` renders its value as a link).
@@ -6,7 +6,7 @@ import SectionText from '../molecules/SectionText.jsx'
6
6
  import { minHeightClass } from './sectionHeights.js'
7
7
 
8
8
  /**
9
- * SectionFaq — a `SectionText` header over an `Accordion` of question /
9
+ * SectionFaq — Questions and answers in an accordion. a `SectionText` header over an `Accordion` of question /
10
10
  * answer items. The one NEW surface in the section family (SectionSet,
11
11
  * 2026-08-26) — the behaviour already shipped in the Accordion molecule; this
12
12
  * is the section around it.
@@ -85,7 +85,7 @@ function MediaLayer({ media }) {
85
85
  }
86
86
 
87
87
  /**
88
- * SectionHero — the full-bleed media hero: cover-fit background media (image
88
+ * SectionHero — Full-bleed media hero with a glass panel. the full-bleed media hero: cover-fit background media (image
89
89
  * or video) filling a fixed-height section, an optional surface scrim, and
90
90
  * the text in a glass panel over it. `FullBleedHero` is this component under
91
91
  * its old name (alias kept).
@@ -8,7 +8,7 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
8
8
  import { minHeightClass } from './sectionHeights.js'
9
9
 
10
10
  /**
11
- * SectionNewsletter — the newsletter card of the section family
11
+ * SectionNewsletter — A newsletter signup card. the newsletter card of the section family
12
12
  * (SectionNewsletter, kol-website 2026-08-27 — user: the newsletter as a card
13
13
  * in the family, same ladder, same cap, content centred on y, not its own
14
14
  * thing). `SectionText` (label · headline · body, centred) with the email
@@ -6,7 +6,7 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
6
6
  import { minHeightClass } from './sectionHeights.js'
7
7
 
8
8
  /**
9
- * SectionSplit — the media-and-text split section, on `SectionText` (the
9
+ * SectionSplit — Text beside media. the media-and-text split section, on `SectionText` (the
10
10
  * text column) beside the media frame. Two columns at/above 901px, one
11
11
  * stacked column below. `FeatureSplit` is this component under its old name
12
12
  * and old prop names (kept as an alias — see FeatureSplit.jsx).
@@ -9,7 +9,7 @@ import FullscreenOverlay from '../utilities/FullscreenOverlay.jsx'
9
9
  import { Tooltip } from '../utilities/Popover.jsx'
10
10
 
11
11
  /**
12
- * SettingsPanel — a settings surface for the thing you are looking at: you
12
+ * SettingsPanel — Settings beside the thing they change. a settings surface for the thing you are looking at: you
13
13
  * change how a list looks WHILE looking at it, so it is a slide-over (or an
14
14
  * overlay), never a route (SettingsPanel, kol-r2b2 2026-08-26 — the
15
15
  * per-bucket display settings: kinds allow-list, structure, loading, layout).
@@ -107,7 +107,7 @@ export default function SettingsPanel({
107
107
  }
108
108
 
109
109
  /**
110
- * SettingsRow — a `LabeledControl inline` (SettingsPanelApproved, 2026-08-27):
110
+ * SettingsRow — One labelled setting. a `LabeledControl inline` (SettingsPanelApproved, 2026-08-27):
111
111
  * uppercase label (`kol-helper-10` tracked, meta ink) in a 160px column, the
112
112
  * control fills the rest. A switch sits at the far right (`align="end"`, the
113
113
  * default); a dropdown fills the row (`align="fill"`). No hint sentences on the
@@ -127,7 +127,7 @@ export function SettingsRow({ label, hint, align = 'end', labelWidth = 160, chil
127
127
  )
128
128
  }
129
129
 
130
- /** SettingsSwitch — the row's on/off control: the DS ToggleSwitch, bare, sm.
130
+ /** SettingsSwitch — An on/off setting. the row's on/off control: the DS ToggleSwitch, bare, sm.
131
131
  * `disabledHint` rides a DS `Tooltip` so a switch that cannot act says why;
132
132
  * inside a row's `hint` it wins while hovered, as the native `title` did. */
133
133
  export function SettingsSwitch({ on = false, onChange, disabled = false, disabledHint, label, title }) {
@@ -144,7 +144,7 @@ export function SettingsSwitch({ on = false, onChange, disabled = false, disable
144
144
  return tip ? <Tooltip label={tip}>{toggle}</Tooltip> : toggle
145
145
  }
146
146
 
147
- /** LabeledControlSection — a section of LabeledControls: the EYEBROW
147
+ /** LabeledControlSection — A titled section of labelled controls. a section of LabeledControls: the EYEBROW
148
148
  * (`kol-eyebrow text-fg-80`) standing apart from the rows (gap-3), the rows in
149
149
  * their own stack — `rowGap` 1 for switch rows (24 tall already), 2 for
150
150
  * dropdown rows. `divided` = a hairline above (between sections).
@@ -161,7 +161,7 @@ export function LabeledControlSection({ label, divided = false, rowGap = 2, chil
161
161
  )
162
162
  }
163
163
 
164
- /** SettingsChoice — the row's one-of-N control: the DS Dropdown, sm · primary
164
+ /** SettingsChoice — A one-of-many setting. the row's one-of-N control: the DS Dropdown, sm · primary
165
165
  * (SettingsPanelEyebrowAndDropdowns — user: "put the toggles inside a dropdown,
166
166
  * because it's super messy like it is"). Options are values or `{ value, label }`;
167
167
  * width is the call site's (`className="w-40"`).
@@ -189,7 +189,7 @@ export const CHIP_CLS = 'kol-control kol-control-sm kol-mono-12'
189
189
  export const chipCls = (on) => `${CHIP_CLS} ${on ? 'kol-control--filled' : 'text-meta hover:text-emphasis'}`
190
190
 
191
191
  /**
192
- * SettingsMulti — a many-of-N control as ONE Dropdown (SettingsPanelApproved,
192
+ * SettingsMulti — A many-of-many setting in one dropdown. a many-of-N control as ONE Dropdown (SettingsPanelApproved,
193
193
  * 2026-08-27 — the kinds row): the trigger reads `N of M <noun>`, every entry
194
194
  * toggles and `✓` marks the ones that are on. No grouping.
195
195
  * @param {Array} options [{ value, label }]
@@ -210,7 +210,7 @@ export function SettingsMulti({ options = [], selected = [], onToggle, noun = 'k
210
210
  }
211
211
 
212
212
  /**
213
- * SettingsChipRow — a wrap of toggle chips with optional counts (an
213
+ * SettingsChipRow — A row of toggle chips. a wrap of toggle chips with optional counts (an
214
214
  * allow-list: every chip sets a default, never a gate). `allChip` puts an
215
215
  * "all" chip first — the same control chip, filled when every option is on
216
216
  * (SettingsPanelEyebrowAndDropdowns — user: "Show all in ghost mode? makes no
@@ -247,7 +247,7 @@ export function SettingsChipRow({ options = [], selected = [], onToggle, allChip
247
247
  )
248
248
  }
249
249
 
250
- /** SettingsFooter — a Divider, then one `IconFrame refresh` (primary · sm) at the
250
+ /** SettingsFooter — Reset settings to their defaults. a Divider, then one `IconFrame refresh` (primary · sm) at the
251
251
  * right = reset to defaults (SettingsPanelApproved, 2026-08-27). No status word,
252
252
  * no text button. `customised` is accepted for compatibility and unused.
253
253
  *
@@ -59,7 +59,7 @@ export function HighlightMatch({ label, query, ranges }) {
59
59
  }
60
60
 
61
61
  /**
62
- * ShellSearchOverlay — the ⌘K command palette: fullscreen dim + centered
62
+ * ShellSearchOverlay — The ⌘K search palette. the ⌘K command palette: fullscreen dim + centered
63
63
  * panel, a bare SearchInput on top, result rows beneath (HighlightMatch
64
64
  * label, dim hint line, right-aligned group label). Distinct from Modal
65
65
  * (prompt/confirm only) — this is the search/command primitive.
@@ -69,7 +69,7 @@ export function HighlightMatch({ label, query, ranges }) {
69
69
  * The ⌘K binding itself lives in the shell's key handler, not here.
70
70
  *
71
71
  * Keyboard: ArrowUp/ArrowDown rove the active row (mouse hover roves too),
72
- * Enter selects it (index starts at 0 → Enter-selects-first preserved),
72
+ * Enter opens it (the top row from the first keystroke), ⌘/Ctrl+Enter opens every hit,
73
73
  * Escape closes. Focus trap: focus moves into the input on open, returns to
74
74
  * the opener on close, and Tab is pinned — rows are combobox options driven
75
75
  * via aria-activedescendant, never tab stops.
@@ -168,13 +168,12 @@ export default function ShellSearchOverlay({
168
168
  /* ⌘ENTER OPENS EVERY HIT (user 2026-09-30: *"enter would focus searched item, and maybe
169
169
  * command enter would open the results page"*) — only where the consumer has a place for them. */
170
170
  if ((e.metaKey || e.ctrlKey) && onOpenResults && query) { onOpenResults(query); onClose?.(); return }
171
- /* Enter COMMITS the query and expands. It only selects when the user has
172
- * actually arrowed to a row — `activeIndex` starts at 0, so "a row is
173
- * highlighted" is true from the first keystroke and testing `active >= 0`
174
- * made Enter navigate to whatever happened to be first. Committing a
175
- * query must never be a navigation you didn't choose. */
176
- /* An empty query has nothing to commit — Enter goes to the top suggestion. */
177
- if (active >= 0 && (navigated || !query)) select(results[active])
171
+ /* ENTER OPENS THE HIGHLIGHTED ROW (user 2026-10-01: *"I think enter should also take you to
172
+ * the atom but something like command enter take you to the index"* — reverses the
173
+ * 2026-08-01 "Enter commits, it only selects once you have arrowed"). The top row is drawn
174
+ * highlighted from the first keystroke, so Enter goes where the highlight says. With no
175
+ * rows there is nothing to open and Enter commits the query. */
176
+ if (active >= 0) select(results[active])
178
177
  else onExpand?.()
179
178
  } else if (e.key === 'Tab') {
180
179
  /* Focus trap — the input is the palette's only tab stop. */
@@ -283,17 +282,28 @@ export default function ShellSearchOverlay({
283
282
  </ul>
284
283
  )}
285
284
  {/* THE FOOTER SAYS WHAT ENTER DOES — always, not only once typing. */}
286
- {!expanded && ((!query && results.length > 0) || (query && enterLabel)) && (
285
+ {!expanded && (results.length > 0 || (query && (enterLabel || onOpenResults))) && (
287
286
  <div className="border-t border-fg-08 py-2">
288
- <p className="flex items-center gap-2 kol-helper-12 text-fg-48 mx-2 px-4 border-x border-transparent">
289
- <Kbd icon="corner-down-left" />
290
- {query ? enterLabel : 'Go to page'}
291
- </p>
287
+ {/* Enter's line names what Enter does NOW: a row is highlighted → it opens that row;
288
+ * no rows → it commits the query. */}
289
+ {(results.length > 0 || enterLabel) && (
290
+ <p className="flex items-center gap-2 kol-helper-12 text-fg-48 mx-2 px-4 border-x border-transparent">
291
+ <Kbd icon="corner-down-left" />
292
+ {results.length > 0 ? 'Go to page' : enterLabel}
293
+ </p>
294
+ )}
295
+ {/* THE RESULTS LINE IS A LINK (user 2026-10-01: *"make 'all results...' at the bottom
296
+ * also be a link to the results page"*) — the same door ⌘Enter opens. */}
292
297
  {query && onOpenResults && (
293
- <p className="flex items-center gap-2 kol-helper-12 text-fg-48 mx-2 px-4 border-x border-transparent pt-1">
298
+ <button
299
+ type="button"
300
+ className="flex items-center gap-2 kol-helper-12 text-fg-48 hover:text-fg-default transition-colors mx-2 px-4 border-x border-transparent pt-1"
301
+ onMouseDown={(e) => e.preventDefault()}
302
+ onClick={() => { onOpenResults(query); onClose?.() }}
303
+ >
294
304
  <Kbd icon="command"><Icon name="corner-down-left" size={12} /></Kbd>
295
305
  {resultsLabel}
296
- </p>
306
+ </button>
297
307
  )}
298
308
  </div>
299
309
  )}
@@ -2,7 +2,7 @@ import { useEffect } from 'react'
2
2
  import SettingsSections from './SettingsSections.jsx'
3
3
 
4
4
  /**
5
- * ShortcutsOverlay — the keyboard-shortcut sheet: blurred scrim, centred
5
+ * ShortcutsOverlay — The keyboard shortcut sheet. the keyboard-shortcut sheet: blurred scrim, centred
6
6
  * panel, a 2-col grid (label · keys), Esc / backdrop-click close.
7
7
  * Ported from the shared cut (mirror's, "copied from kol-monitor").
8
8
  *
@@ -41,7 +41,7 @@ const HUE_GRADIENT =
41
41
  'linear-gradient(to right, hsl(0,100%,50%), hsl(60,100%,50%), hsl(120,100%,50%), hsl(180,100%,50%), hsl(240,100%,50%), hsl(300,100%,50%), hsl(360,100%,50%))'
42
42
 
43
43
  /**
44
- * HueStrip — 1D hue slider: a rainbow bar with a draggable knob. Pointer
44
+ * HueStrip — A hue slider. 1D hue slider: a rainbow bar with a draggable knob. Pointer
45
45
  * drag anywhere on the strip; focus + Left/Right (or Down/Up) arrow keys
46
46
  * nudge hue by 1° (role="slider").
47
47
  *
@@ -116,7 +116,7 @@ export function HueStrip({ hue, onChange }) {
116
116
  }
117
117
 
118
118
  /**
119
- * SBSquare — 2D saturation/value picker: white→hue horizontal gradient with
119
+ * SBSquare — Pick saturation and value on a square. 2D saturation/value picker: white→hue horizontal gradient with
120
120
  * a black overlay fading upward, crosshair handle. Fills its container
121
121
  * (consumer owns the size — and the rounding: apply `rounded-[var(--kol-radius-xs)]
122
122
  * overflow-hidden` on the wrapper). Focus + arrow keys nudge: Left/Right =
@@ -233,7 +233,7 @@ function vertexAt(angleRad) {
233
233
  }
234
234
 
235
235
  /**
236
- * WheelTriangle — HSV color wheel: conic hue ring with an inscribed,
236
+ * WheelTriangle — A hue wheel with a value triangle. HSV color wheel: conic hue ring with an inscribed,
237
237
  * rotating HSV triangle for saturation/value. Ring press snaps hue to the
238
238
  * cursor angle and drags; triangle press grabs the SV handle with a
239
239
  * cursor↔handle offset so fine tuning never teleports it. Focus + arrow
@@ -478,7 +478,7 @@ function SvgHandle({ cx, cy, r = 2.4 }) {
478
478
  }
479
479
 
480
480
  /**
481
- * SpectrumControls — the composed classic square picker: HueStrip stacked
481
+ * SpectrumControls — A hue strip over a saturation square. The composed classic square picker: HueStrip stacked
482
482
  * over a fill-height SBSquare, per the source color panel's Hue mode layout
483
483
  * (SBSquare wrapped in `rounded-[var(--kol-radius-xs)] overflow-hidden`, see its comment).
484
484
  * Fills its container — the consumer owns the outer size. For the ring
@@ -4,7 +4,7 @@ import { resolveCssVar, resolveCssColor, isLight } from '../hooks/cssVar.js'
4
4
  import { Tooltip } from '../utilities/Popover.jsx'
5
5
 
6
6
  /**
7
- * SpectrumGrid — matrix view of the whole ramp system: rows = ramps, columns =
7
+ * SpectrumGrid — Every ramp by every stop. matrix view of the whole ramp system: rows = ramps, columns =
8
8
  * stops (50 → 900). Each cell is a ColorSwatch tile with the stop number and
9
9
  * hex printed over it (text color contrast-corrected via isLight), so the whole
10
10
  * palette is scannable in one grid.
@@ -33,7 +33,7 @@ const WIDTHS = {
33
33
  column: '',
34
34
  }
35
35
 
36
- const Table = ({ caption, columns, rows, variant = 'default', className = '', width = 'panel', rowClassName, compact = false }) => {
36
+ const Table = ({ caption, columns, rows, variant = 'default', className = '', width = 'panel', rowClassName, compact = false, lastRule = false }) => {
37
37
  const [sort, setSort] = useState({ key: null, dir: null })
38
38
 
39
39
  const cycle = (key) =>
@@ -58,7 +58,9 @@ const Table = ({ caption, columns, rows, variant = 'default', className = '', wi
58
58
  const variantClass = variant === 'simple' ? 'kol-table--simple' : ''
59
59
  /* compact — record-surface density (RecordManager, 2026-08-09): the default
60
60
  * 12/16 cell box read as bloated rows against the reference table. */
61
- const wrapperClass = ['kol-table-wrapper', variantClass, compact && 'kol-table--compact', WIDTHS[width] ?? WIDTHS.panel, className].filter(Boolean).join(' ')
61
+ /* lastRule — `simple` only: the rule under the LAST row. Off by default (2026-10-01): the
62
+ * table is usually followed by a divider of its own, and the two read as a double line. */
63
+ const wrapperClass = ['kol-table-wrapper', variantClass, lastRule && 'kol-table--last-rule', compact && 'kol-table--compact', WIDTHS[width] ?? WIDTHS.panel, className].filter(Boolean).join(' ')
62
64
  return (
63
65
  <div className={wrapperClass}>
64
66
  <table className="kol-table">
@@ -5,7 +5,7 @@ import SplitToolButton from '../molecules/SplitToolButton.jsx'
5
5
  import { Tooltip } from '../utilities/Popover.jsx'
6
6
 
7
7
  /**
8
- * ToolPalette — the editor's tool bar as one row (kol-fxr `shell/panels/ToolPalette.jsx`,
8
+ * ToolPalette — The editor's tool bar. the editor's tool bar as one row (kol-fxr `shell/panels/ToolPalette.jsx`,
9
9
  * editor-panels-the-held-specs A3, 2026-09-25). Four kinds of cell, all on one pinned-square rung:
10
10
  *
11
11
  * - `tool` — arms a mode; lit while `activeId` is its id
@@ -495,7 +495,7 @@ function AsciiCursorOverlay({ hideCursor }) {
495
495
  }
496
496
 
497
497
  /**
498
- * AsciiCursor — full-viewport decorative overlay that shadows the pointer
498
+ * AsciiCursor — An ASCII crosshair that follows the pointer. full-viewport decorative overlay that shadows the pointer
499
499
  * with an ASCII crosshair (diamond variant over interactive elements) and
500
500
  * layers ambient effects on top of the page: drifting cursor stars,
501
501
  * click-triggered ASCII fireworks, and a right-click Space Invader that
@@ -1,5 +1,5 @@
1
1
  /**
2
- * AssetGrid — thin responsive N-column grid for tiling asset figures
2
+ * AssetGrid — A responsive grid for asset figures. thin responsive N-column grid for tiling asset figures
3
3
  * (swatches, placeholders, spec cards). Fixed 2/3/4-column layout that
4
4
  * collapses to 2 columns under the md breakpoint and to 1 column under
5
5
  * 480px, all via Tailwind responsive utilities — no CSS of its own.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * ButtonGroup — responsive layout wrapper for a group of Buttons: stacked
2
+ * ButtonGroup — Lay out a group of buttons. responsive layout wrapper for a group of Buttons: stacked
3
3
  * full-width on mobile, horizontal row from `sm` up, aligned left / center /
4
4
  * right. Pure layout — children compose at the call site and render as-is
5
5
  * (nothing is cloned, no props injected); all button behavior lives on each
@@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from 'react'
2
2
  import { CanvasZoomContext } from '../hooks/canvasZoom.js'
3
3
 
4
4
  /**
5
- * CropOverlay — crop-mode chrome for a photo layer with an explicit crop
5
+ * CropOverlay — Crop handles over a photo layer. crop-mode chrome for a photo layer with an explicit crop
6
6
  * window ({imgX,imgY,imgW,imgH} — the image's draw rect in frame-local px).
7
7
  *
8
8
  * • drag inside the frame → pan the image within the frame (clamped)
@@ -81,7 +81,7 @@ function Handle({ cx, cy, role }) {
81
81
  }
82
82
 
83
83
  /**
84
- * CurveOverlay — SVG easing/curve visualizer laid absolutely over a frame:
84
+ * CurveOverlay — An easing curve drawn over a frame. SVG easing/curve visualizer laid absolutely over a frame:
85
85
  * a dashed accent curve with endpoint dots, and — in `curve="custom"`
86
86
  * mode — a two-handle cubic-bezier editor (Figma/After-Effects style)
87
87
  * with tangent lines back to the anchored endpoints.
@@ -2,7 +2,7 @@ import { Component } from 'react'
2
2
  import Button from '../atoms/Button.jsx'
3
3
 
4
4
  /**
5
- * ErrorBoundary — class error boundary (boundaries can't be hooks). Catches
5
+ * ErrorBoundary — Catches a crash and shows a fallback. class error boundary (boundaries can't be hooks). Catches
6
6
  * render errors in its subtree and swaps in a centered full-screen fallback
7
7
  * ("Something went wrong") with two recovery actions: retry in place and go
8
8
  * home. A dev-only error/stack panel renders on Vite dev builds
@@ -1,5 +1,5 @@
1
1
  /**
2
- * ExitPreview — the escape hatch out of a preview surface, worn as a fixed
2
+ * ExitPreview — A pill to leave a preview. the escape hatch out of a preview surface, worn as a fixed
3
3
  * pill. Router-AGNOSTIC by the same seam kol-shell uses for navigation: it
4
4
  * renders a plain `<a>` unless the consumer hands it its router's link.
5
5
  *
@@ -3,7 +3,7 @@ import { pushLayer, popLayer, isTopLayer } from './layerStack.js'
3
3
  import CloseButton from '../atoms/CloseButton.jsx'
4
4
 
5
5
  /**
6
- * FullscreenOverlay — the scrim + centred sheet every overlay in the repo
6
+ * FullscreenOverlay — The scrim and sheet every overlay wears. the scrim + centred sheet every overlay in the repo
7
7
  * wears. Owns dismissal (Escape, backdrop, close button), scroll lock and
8
8
  * stacking; the consumer supplies the panel.
9
9
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverlayGlassPanel — the KOL frosted-glass content card that floats over
2
+ * OverlayGlassPanel — A frosted panel over media. the KOL frosted-glass content card that floats over
3
3
  * hero/carousel media: translucent surface-primary (color-mix) + a 1px
4
4
  * backdrop blur, children stacked vertically. Extracted from 4 identical
5
5
  * inline copies in the monorepo (StudioHero, StudioAboutCard,
@@ -240,7 +240,7 @@ function TooltipOn({
240
240
  }
241
241
 
242
242
  /**
243
- * PopoverPanel — renders the floater into a portal with default panel chrome.
243
+ * PopoverPanel — A floating panel in a portal. renders the floater into a portal with default panel chrome.
244
244
  *
245
245
  * Props:
246
246
  * popover — the value returned from `usePopover`
@@ -1,5 +1,5 @@
1
1
  /**
2
- * ProsePreview — a full rich-text specimen: one `.kol-prose` block exercising
2
+ * ProsePreview — Every long-form prose element in one view. a full rich-text specimen: one `.kol-prose` block exercising
3
3
  * every long-form element — H1–H4 ladder, section lede, body paragraph,
4
4
  * blockquote, indented passage, code block, pullout, and unordered/ordered
5
5
  * lists — so the KOL prose stylesheet can be reviewed end-to-end in one view.
@@ -4,7 +4,7 @@ import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
4
4
  import useCoarsePointer from '../hooks/useCoarsePointer.js'
5
5
 
6
6
  /**
7
- * TiltCard — self-contained image card with a spring-based 3D tilt that
7
+ * TiltCard — An image card that tilts toward the pointer. self-contained image card with a spring-based 3D tilt that
8
8
  * follows the pointer (via the shared useTilt hook). On coarse-pointer
9
9
  * devices or when the user prefers reduced motion it renders a plain,
10
10
  * tilt-free card — no springs, no listeners.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TransparentX — diagonal stroke indicator for transparent / disabled / unused
2
+ * TransparentX — A slash marking an empty slot. diagonal stroke indicator for transparent / disabled / unused
3
3
  * slots. Universal "no value" affordance.
4
4
  *
5
5
  * Renders absolute-positioned to fill its parent. Parent must be `position: