Components
Assembled, reusable units — the pieces a screen is actually built from. Every component here is a composition of elements and objects. Each section shows the component as it ships — live, working markup, never a screenshot — alongside the named pieces it's made of.
Elements vs. components
Elements are the indivisible atoms (a chip, a star, a quote, a button); objects are small clusters of those (a field row, a byline, a dropdown). This page holds components: the larger assemblies they snap into. The review card is the canonical example — a card shell wrapping six elements, so changing an element changes every component that uses it. Reach for an existing component first; compose a new one only when none bends to fit.
Header & navigation
The black header that anchors every screen: brand lockup, the primary module tabs, and a standalone Request Intake action held to the right. Locations is the default tab; Request Intake is present everywhere but never a peer of the sections.
Header ink-900 bg at --size-header · tabs brand underline on aria-current="page" · Request intake = a real .km-btn--ondark, right-aligned, persistent — never a styled tab.
Built from these elements. A fixed shell: brand mark, a row of tab links, and one on-dark action — the only chrome shared by every page. The whole strip speaks the on-dark token family (foundations); the mark is the system Krown K on a brand tile.
Review card
The Reviews-tab work unit: one Google review with a single reply action. Pure composition — a .km-card.km-card--accent with the --m-reviews spine, wrapping six elements. The profile link is icon-only so words never compete with the review; Draft reply is the one black primary per card.
.km-review — composition over .km-card.
The card shell + --m-reviews spine are the only component-level
parts; everything inside is an element.
Built from these elements — six, top to bottom. Edit any one in the element kit and it updates here.
- Shop description — shop name (UI title) +
#id · citydotline, in the shop-name font, not mono. - Stars — monochrome
.km-stars; the score reads from the count of filled stars, never gold. - Reviewer byline — author · date · time dotline.
- Quote — someone else's words,
.km-quote, opening with the filled quote glyph as a quiet ornament. - Icon link — platform glyph + external ↗, no label, so the action recedes behind the review text.
- Button — primary — the one real action per card.
Location card
The browsable unit for a single location: name as the only title, address + ID as metadata, one status chip, the K·G·A·B coverage row, and a footer. Public platform links live here; admin links live on the detail page only.
.km-loc — name is the single title; address + ID are metadata; one
status chip top-right; coverage row reads K·G·A·B at a glance.
Built from these elements. A bordered card shell wrapping the location's identity, status, coverage, and footer — shop description, status pill, platform indicators, and an inline link.
Panel & card
The workhorse container every other component extends. Surface, hairline border, radius-md, optional 4px module spine. A header holds a title and at most one trailing control or count.
.km-card · .km-card--accent with --accent for module context. Border only — never a resting shadow.
Built from these elements. The base container — almost everything else on this page is a card with something inside it: border & surface, a module accent, a plain chip as the count.
Detail / field-row card
A card filled with field rows — the atom of every detail page. A 160px mono-caps label pairs with a value that can hold text, a chip, or links, divided by hairlines.
.km-field — mono caps label + value, hairline divider between.
Values hold chips, links, or text.
Built from these elements. Stacks of field rows inside a card make up every detail surface.
Confirmation card
The “here's what I understood” receipt the system shows before doing anything. Brand left-border, mono-caps keys, a primary proceed and a quiet edit. Honest about manual work up front.
.km-confirm — brand left-border, mono caps keys, primary “proceed”
+ quiet “edit”. Nothing publishes until confirm.
Built from these elements. A brand-accented card of key/value rows, capped with the safety actions — status pill, primary + quiet buttons.
Intake conversation
The conversational front door — bubbles + a persistent composer with a mic. The rep speaks plainly; the system replies with a plain receipt. Voice produces an editable transcript, never an auto-submitted action.
.km-bubbles + .km-composer — user =
ink-900 right, system = brand tint left. The mic owns the composer's bottom-right corner.
Built from these elements. A bubble thread above a composer; the confirmation card (above) slots in as the system's structured reply.
Processing checklist
The live “what's happening now” after a request is confirmed. Marks pair color + glyph — done ✓, active ●, manual !, queued ○ — never color alone. Reads as operational history, never a developer log.
.km-check — done ✓ · active ● · manual ! · queued ○. Color + glyph,
never color alone.
Built from these elements. A card holding status-marked rows — each mark maps to a system status color from the token layer.
Activity feed
The durable “what happened” — one chronological stream across modules, every row attributed to a person. Module-tinted initial, plain-language line, who/how subtext, mono relative time.
.km-feed — module-tinted initial, plain-language line, who/how
subtext, mono relative time. Operational history, not logs.
Built from these elements. A card of feed rows, each carrying a module-tinted initial and its author.
Empty & warning states
Empty isn't broken — it's an invitation. Warnings are honest and specific; blocked states say what to do next, in plain language. Each leads with a word, never just a colour.
Empty dashed border, surface-2, title + one-line guidance + a recovery action. Banners manual (amber) · block (red, with next step) · info (neutral).
Built from these elements. An empty-state well plus three banner tones — each pairs an icon with a worded message and, where useful, a recovery action.
Dense table
Locations at scale — sticky mono headers, hover rows, and the platform tiles compacted so a hundred locations scan as one column of K·G·A·B.
.km-table — sticky surface-2 mono headers, hairline row dividers,
hover wash. Platform tiles compact to 20px inside the table so density never costs the K·G·A·B
read.
Segmented control
The sliding pill — one thumb glides between options on the same recipe as the tab marker (--dur-page / --ease-in-out), so every sliding-marker in the system moves as one gesture.
.km-seg — surface-3 well, surface thumb with shadow-sm. The --ink variant (black thumb, white selected label) is the
view-toggle voice: Table | Cards. Retired the harder-edged .km-toggle — every 2–4-option choice is a seg. Selection SLIDES,
press DIPS: choosing is never a press. Click an option: the thumb glides, it never blinks.
Shared surface morph
A card grows into its detail surface and visibly stays the SAME object — the boundary travels the whole way on --dur-grow, the slowest deliberate move in the system. Content only renders at its own scale; the just-viewed card carries the lift when you return.
growFrom / shrinkTo from $lib/motion/morph · rides --dur-grow / --ease-in-out · detail
content fades in after the surface is 55% there; on the way back, content fades over the first
third and the small display only appears once the surface lands. The phantom-hover guard mutes
stray hover until the pointer actually moves.
Reorderable widgets
Drag the handle: the row follows the pointer 1:1, neighbours give way on a quick decelerate, and release lands on the rare-overshoot settle. For dashboard widgets, kanban columns, priority lists.
createSnapDrag from $lib/motion/snap.svelte · direct index
targeting (fast multi-slot drags land in one move) · window-level listeners so release ALWAYS
lands · settle rides --dur-slow / --ease-settle.
Loading states
Calm and confident: layered skeletons with a soft sweep that stops when content lands, cards arriving on the stagger cascade, numbers rolling after. Never an endless pulse.
.km-skeleton + km-rise on --stagger steps (capped at 6) · figures roll in on the value-roll
behaviour once content lands.
AI generation
Generating never shows a plain spinner: a soft brand-tone border sweep, a streaming text shimmer, a pulsing caret, and the button label morphing Generate → Thinking → Regenerate. Brand tones only.
“Great service — they did every part, very nice to deal with.” ★★★★★
.km-ai--thinking border sweep · .km-ai-shimmer streaming text · .km-ai-caret pulse — for response drafting, insight cards,
translation suggestions across every AI-assisted surface.
Completion celebration
A tiny, contained reward on completion: the check draws itself, the badge settles in on the rare-overshoot curve, a soft tint halo breathes out once. Never confetti.
CheckDraw component · km-draw + km-badge-pop + km-halo on --dur-morph / --ease-settle.
Promotion log
How a component earns its way into this page. New work stages on a proposed-components surface, gets triaged against the locked system, and only then promotes into the core — nothing lands here unreviewed.
The governance pattern. Screenshots from the in-progress app are treated as a request, not a spec. Every one runs the same four-step loop on the staging surface: read the screen (separate what the rep needs from decorative chrome), rebuild from the kit (card, row, chip, tile, button — new parts only as a last resort), flag edge cases (when the system has no rule, name the gap and propose the rule), and promote to core (once agreed, the rule lands in the registry, the stylesheets and this documentation). The gate for anything new: “is this really not a card / row / chip / tile?” — extend an existing component with a modifier before inventing one, and no raw hex or px: a new value becomes a proposed token, never an inline number.
The Reviews module is the worked example. The Reviews tab was triaged on the
staging surface and promoted to core on June 11, 2026 with all ten edge cases
resolved — the reserved --m-reviews accent activated as the card spine, the
metric hero, the filter facets, the monochrome stars, the quote block, the review card
composition, and the custom dropdown. The page-local copies were then deleted: this
documentation consumes those primitives from core, so the docs can never drift from the
shipped system.
| Edge case | Resolution — promoted to core, Jun 11, 2026 |
|---|---|
Hero workload metric.km-metric-hero | One hero figure per view; prominence from scale, not colour. The number leads at title size with a .km-subtext label before it; a green meter fills with work done; the total recedes to a mono caption. |
Star rating + star glyphs.km-stars · star / star-fill | Literal stars, monochrome — filled (ink) = the score, hollow (border-grey) = the remainder. Keeps the “icons never carry their own colour” house rule; gold/amber was rejected. |
Filter facet.km-facet | The system’s first true filter pattern: a selectable chip borrowing the toggle’s selection language — active = ink fill, control height to line up with buttons and inputs, count doubling as a live tally. |
Review card + quote block.km-review · .km-quote | Assembled from card + shop description + stars + byline dotline + quote + platform tile. Mostly composition; .km-quote is the one genuinely new primitive, opening with the new quote glyph in muted ink. |
Reviews module accent--m-reviews | Already reserved in the token layer — the case simply activates it as the card left-spine. No new token needed; the foundation anticipated Reviews. |
Platform tile as profile linkicon-only link | Was “Open profile”. Now icon-only — the Google glyph (identity) plus the external ↗ glyph (leaves the app), no words, deep-linking to this exact review on the shop’s Google listing. |
Dropdown menu (custom).km-dropdown | Native select can’t style its list or stop the OS popup overlapping the field. Custom listbox opens below on the overlay recipe; hover = neutral, selection = brand — they never read alike. |
Select / dropdown caret.km-select | Existed but handed its arrow to the OS. Fixed in core: native appearance reset, the system caret-down-fill painted in ink-500; the Clear button moved from quiet to secondary. |
Subtext type role.km-subtext | The system had the size but no named secondary-text role, so captions were hand-styled each time. Added Small · regular · ink-500 as the one treatment for any quiet caption or metric label. |
Header action button.km-btn--ondark | “Request intake” was a fake button — a .km-tab with inline styles and a raw hex bolted on. Promoted to a real on-dark button variant with the --ondark-* token family; .km-tab hardened with nowrap. |
Ten edge cases · ten written rules · zero unreviewed landings. The staging surface is empty again — that is the steady state.
Component manifest
Every class in the system, registered. This table is generated from the component registry — the same data the audit reconciles against the stylesheets and real usage, so no class can exist invisibly.
| Selector | Title | Layer | File |
|---|---|---|---|
.km | Product base | element | components/base.css |
.km-subtext | Subtext | element | components/base.css |
.km-header | App header | component | components/header.css |
.km-tab | Top tab | component | components/header.css |
.km-sidenav | Side nav | component | components/sidenav.css |
.km-btn | Button | element | components/button.css |
.km-link | Link | element | components/button.css |
.km-card | Card / panel | component | components/card.css |
.km-loc | Location card | component | components/card.css |
.km-field | Detail field row | object | components/card.css |
.km-chip | Status chip | element | components/chip.css |
.km-plat | Platform tile | element | components/chip.css |
.km-assignee | Assignee pill | object | components/chip.css |
.km-label | Field label | element | components/form.css |
.km-input | Text input | element | components/form.css |
.km-textarea | Textarea | element | components/form.css |
.km-select | Select | element | components/form.css |
.km-hint | Field hint | element | components/form.css |
.km-seg | Segmented control | element | components/form.css |
.km-composer | Voice composer | component | components/form.css |
.km-bubble | Intake bubble | component | components/conversation.css |
.km-confirm | Confirmation card | component | components/conversation.css |
.km-check | Processing checklist | component | components/conversation.css |
.km-feed | Activity feed | component | components/conversation.css |
.km-empty | Empty state | component | components/feedback.css |
.km-banner | Banner | component | components/feedback.css |
.km-table | Dense table | component | components/table.css |
.km-metric-hero | Hero workload metric | object | components/reviews.css |
.km-facet | Filter facet | object | components/reviews.css |
.km-stars | Star rating | element | components/reviews.css |
.km-quote | Quote block | element | components/reviews.css |
.km-dotline | Dot-separated meta line | object | components/reviews.css |
.km-review | Review card | component | components/reviews.css |
.km-dropdown | Dropdown menu | overlay | components/dropdown.css |
.km-glass | Glass material | overlay | components/glass.css |
.km-lift | Card lift | effect | components/motion-effects.css |
.km-tilt | 3D tilt | effect | components/motion-effects.css |
.km-glow | Cursor-follow glow | effect | components/motion-effects.css |
.km-meter | Meter | effect | components/motion-effects.css |
.km-skeleton | Skeleton | effect | components/motion-effects.css |
.km-palette | Command palette | effect | components/motion-effects.css |
.km-drawer | Parallax drawer | effect | components/motion-effects.css |
.km-checkdraw | Status celebration | effect | components/motion-effects.css |
.km-ic-spin | Icon micro-motions | effect | components/motion-effects.css |
.km-empty--ambient | Ambient empty state | effect | components/motion-effects.css |
.km-ai | AI generation motion | effect | components/motion-effects.css |
.km-overlay | Overlay | overlay | components/dialog.css |
.km-dialog | Dialog | overlay | components/dialog.css |
Krown Design Manager · Components · Compositions assembled from the element kit. No live CMS/platform write behavior is implied by this document.