/* * Command palette recipe — ⌘K command bar. * * [data-command] → root container (input + list) * [data-command-input] → search input * [data-command-list] → scrolling listbox * [data-command-viewport] → optional inner scroller (if List wraps it) * [data-command-empty] → "no results" message * [data-command-loading] → progress bar slot * [data-command-group] → group container * [data-command-group-heading]→ group label * [data-command-group-items] → group items wrapper * [data-command-item] → row (highlighted via data-selected) * [data-command-link-item] → anchor-style row * [data-command-separator] → 1px divider * [data-command-item-icon] → leading glyph slot (eidos sub-part) * [data-command-item-shortcut]→ trailing kbd hint slot (eidos sub-part) * * Sizes — sm | md | lg via `data-size` on [data-command]. * Inside `` the panel chrome comes from dialog.css; this * recipe only paints the inner palette. */ [data-command] { --_command-input-px: var(--space-3); --_command-input-font-size: var(--font-size-md); --_command-item-px: var(--space-3); --_command-item-font-size: var(--font-size-md); /* Radius of the surface the palette lives in — the concentric reference for the input (which sits at the surface's top corners). Inline that surface is the command's own panel (radius-lg, matching the combobox popup). Inside it's overridden to the dialog panel's radius so the input corner stays parallel to the ACTUAL outer corner. */ --_command-radius: var(--radius-lg); /* Concentric items: expose the radius + inline inset to the shared `[data-shape-nest]` rule. Outer = the command's list radius (`lg`, FIXED) so items stay concentric with the list region in BOTH the inline palette and inside . The items aren't at the dialog's corner (the input + list padding sit above them), so they must NOT inflate to the dialog radius; only the input adapts to it via --_command-radius. gap = the list inline pad. */ --shape-outer-radius: var(--radius-lg); --shape-nest-gap: var(--space-1); display: flex; flex-direction: column; inline-size: 100%; min-inline-size: 0; /* Typography is anchored on the root so EVERY descendant (item, group heading, icon, shortcut) inherits the UI font + leading regardless of context. Inside the palette is portaled, which severs the ambient page-font inheritance — without this the rows fall back to the browser serif (Times New Roman). Self-contained typography keeps the portaled dialog identical to the inline palette. */ font-family: var(--font-ui); line-height: var(--leading-ui); color: var(--color-content-primary); /* Elevation — surface · border · shadow — from the `overlay` plane via `data-depth` (A1). Inside the dialog panel is the surface, so the `[data-dialog-content] [data-command]` override below (higher specificity) strips the plane. Radius / overflow stay the panel's own. */ border-radius: var(--_command-radius); overflow: hidden; outline: none; } /* Inside a Dialog (``) the dialog panel IS the surface — strip ONLY the command's own panel chrome (border / bg / shadow) so the two panels don't nest. Everything else (the boxed input, the list padding, the type scale, the item rows) is inherited unchanged, so the palette is identical to the inline , just hosted inside the dialog panel. */ [data-dialog-content] [data-command] { /* The visible surface is now the dialog panel — adopt ITS radius so the input stays concentric with the actual outer corner the user sees. */ --_command-radius: var(--dialog-content-radius); border: 0; border-radius: 0; background: transparent; box-shadow: none; } /* The command brings its own internal spacing (input margin + list padding), so the dialog content adds none of its own. */ [data-dialog-content]:has([data-command]) { padding: 0; } /* Clear the floating top-right close: the input BOX (not just its text) stops before the close — margin, not padding — so the two never overlap, with a comfortable gap. `--control-height-md` is the close's REAL footprint (an md IconButton); the old `--dialog-close-size` token under-measured it → 2px gap. */ [data-dialog-content] [data-command-input] { margin-inline-end: calc(var(--dialog-close-inset) + var(--control-height-md) + var(--space-1)); } /* Vertically center the floating close on the boxed input row — the dialog's default top inset (for a title row) sits it too low for the command input. */ [data-dialog-content]:has([data-command]) [data-dialog-close][data-position='top-right'] { top: var(--space-2); } [data-command][data-size='sm'] { --_command-input-px: var(--space-2); --_command-input-font-size: var(--font-size-sm); --_command-item-px: var(--space-2); --_command-item-font-size: var(--font-size-sm); } [data-command][data-size='lg'] { --_command-input-px: var(--space-4); --_command-input-font-size: var(--font-size-lg); --_command-item-px: var(--space-4); --_command-item-font-size: var(--font-size-lg); } /* ── Input ──────────────────────────────────────────────────────────── */ /* Boxed search field — same field treatment as the Select trigger (border + radius + surface bg + focus ring), inset from the panel edges, instead of the old flush borderless input with a bottom-rule separator. */ [data-command-input] { box-sizing: border-box; /* Same density-driven block padding as the options (archetype) so the input row and the option rows share one vertical rhythm. */ padding-block: var(--space-1-5); margin: var(--space-2); padding-inline: var(--_command-input-px); border: var(--border-width) solid var(--color-border-default); border-radius: var(--radius-md); background: var(--color-surface-default); color: var(--color-content-primary); font-family: var(--font-ui); font-size: var(--_command-input-font-size); line-height: var(--leading-ui); outline: 0; transition: border-color var(--duration-fast) var(--ease-default), box-shadow var(--duration-fast) var(--ease-default); } [data-command-input]:focus-visible { border-color: var(--color-primary-border); box-shadow: var(--focus-ring); } [data-command-input]::placeholder { color: var(--color-content-muted); } /* ── Loading progress (slim bar under Input) ───────────────────────── */ [data-command-loading] { display: block; block-size: 2px; background: linear-gradient( to right, var(--color-primary-solid) 0%, var(--color-primary-solid) var(--_command-loading-progress, 0%), transparent var(--_command-loading-progress, 0%) ); } /* ── List + Viewport ──────────────────────────────────────────────── */ /* The soma list is a transparent marker; the composed (command-list.svelte) owns the scroll + the design-system scrollbar, shared with select / combobox so the scroll chrome (incl. its colour) is common. */ [data-command-list] { display: contents; } [data-command-list] [data-scroll-area-viewport] { --scroll-area-auto-max-block: min(60vh, 24rem); display: flex; flex-direction: column; gap: var(--space-1); /* Inline inset matches the input's inline margin (space-2) so the option pills and the search box share ONE left/right edge. */ padding-inline: var(--space-2); padding-block-end: var(--space-1); overscroll-behavior: contain; } /* Reserve the scrollbar footprint + a matching inline gap when it shows. */ [data-command-list] [data-scroll-area]:has(> [data-scroll-area-scrollbar][data-orientation='vertical']) > [data-scroll-area-viewport] { padding-inline-end: calc(var(--space-2) + var(--space-3-5)); } [data-command-viewport] { display: flex; flex-direction: column; gap: var(--space-1); max-block-size: min(60vh, 24rem); padding: var(--space-1); overflow: auto; overscroll-behavior: contain; } /* ── Group / GroupHeading / GroupItems ────────────────────────────── */ [data-command-group] { display: grid; gap: var(--space-1); } [data-command-group-heading] { padding-block: var(--space-1); padding-inline: var(--_command-item-px); color: var(--color-content-muted); font-size: var(--font-size-xs); font-weight: 500; text-transform: uppercase; letter-spacing: var(--tracking-caps); } [data-command-group-items] { display: grid; gap: 1px; } /* ── Item / LinkItem ──────────────────────────────────────────────── */ [data-command-item], [data-command-link-item] { display: flex; align-items: center; gap: var(--space-2); padding-inline: var(--_command-item-px); /* Concentric radius from the shared `[data-shape-nest]` rule — the panel exposes --shape-outer-radius (its REAL radius, not radius-md) + --shape-nest-gap above. Height + block padding: the canonical archetype. */ color: var(--color-content-primary); font-size: var(--_command-item-font-size); line-height: var(--leading-ui); text-decoration: none; cursor: pointer; user-select: none; transition: background var(--duration-fast) var(--ease-default), color var(--duration-fast) var(--ease-default); } /* The active-row highlight comes from the canonical archetype layer (archetypes.css), shared with select / combobox / listbox / menus. */ [data-command-item][data-disabled], [data-command-link-item][data-disabled] { cursor: default; opacity: var(--opacity-disabled); } /* ── Item sub-parts (eidos-only) ──────────────────────────────────── */ [data-command-item-icon] { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; inline-size: 1.125em; block-size: 1.125em; color: var(--color-content-secondary); } [data-command-item-shortcut] { display: inline-flex; flex: 0 0 auto; align-items: center; gap: var(--space-1); margin-inline-start: auto; color: var(--color-content-muted); font-size: 0.875em; } /* When the row is highlighted, lift the muted sub-parts to primary. */ [data-command-item][data-selected] [data-command-item-icon], [data-command-item][data-selected] [data-command-item-shortcut], [data-command-link-item][data-selected] [data-command-item-icon], [data-command-link-item][data-selected] [data-command-item-shortcut] { color: var(--color-content-primary); } /* ── Empty state ──────────────────────────────────────────────────── */ [data-command-empty] { padding-block: var(--space-4); padding-inline: var(--_command-item-px); color: var(--color-content-muted); font-size: var(--_command-item-font-size); text-align: center; } /* ── Separator ────────────────────────────────────────────────────── */ [data-command-separator] { block-size: 1px; margin-block: var(--space-1); background: var(--color-border-subtle); }