Skip to content
MUSICLINKD

The design system, generated from itself. Tokens come from tokens.json; components are parsed out of ml-core.css and ml-widgets.css. This page is styled with those same files — if a component breaks, this page breaks.

111 tokens 137 sections 573 selectors 423 icons Light only

Brand · 9

Every mark in frontend/guide/brand/assets/, each shown on the ground it was drawn for — detected from the file's own fills, so dropping a new variant into the folder documents it. The wordmark set in Unica One (.ml-wordmark) is the type treatment; these are the artwork.

favicon mark
favicon-mark.svgon ink · 2KB
logo badge inverse
logo-badge-inverse.svgon ink · 22KB
logo dark pill
logo-dark-pill.svgon ink · 11KB
logo lockup black
logo-lockup-black.svgon ink · 8KB
logo lockup grey
logo-lockup-grey.svgon ink · 8KB
logo lockup white
logo-lockup-white.svgon ink · 9KB
logo lockup wide caps
logo-lockup-wide-caps.svgon ink · 7KB
logo watermark stacked
logo-watermark-stacked.svgon ink · 12KB
mark grey
mark-grey.svgon paper · 2KB

Positioning

Where talent meets opportunity.

Logo usage

Voice

Clear, confident, creative, and professional. Avoid hype and generic marketplace language.

Colour roles

Which colour means what. A value alone does not say whether it is allowed on a primary button — this does, and it is the rule the old catalogue carried that the rebuild had not.

RoleTokenUse
Brand --color-pinkThe brand signal. Intent, selection-in-progress, the one accent on a screen.
Primary --color-inkEvery primary action and committed state. Black is the primary button, not pink.
Ground --color-paperPage ground. Chrome stays monochrome so media carries all saturation.

The v4 rule also read “Purple = badges only.” There is no purple in the palette and no component uses one, so that rule named a colour the system does not have; badges use the status colours or --color-ink. Recorded rather than dropped silently — a rule that vanishes with no reason is how two colour books happened.

Typeface & weights

--font-display · Inter Tight · Screen titles, hero headlines, numbers that matter
600 --weight-3 — MusicLinkd, the professional network for music
800 --weight-4 — MusicLinkd, the professional network for music
--font-body · Inter · Everything else
400 --weight-1 — MusicLinkd, the professional network for music
500 --weight-2 — MusicLinkd, the professional network for music
600 --weight-3 — MusicLinkd, the professional network for music

Colour moved into one book on 2026-08-30 — see Foundations → Colour below. The brand-* tokens there are marketing-only, never a screen colour; everything else is UI. Merged 2026-08-30: previously these lived in a separate section up here, which is exactly the "two colour books" problem the merge fixes.

Imagery

Recovered from the old catalogue's Imagery section on 2026-08-31. Everything here is bound to a token or a component; nothing below introduces an asset the system does not already use. Media is the only element permitted to carry saturation — chrome stays monochrome, which is why these rules matter more than they look.

Aspect ratios

Three tokens. The old catalogue listed a fourth — 3:2 · Studio Photo — and for studio photography it is folded into --media-aspect-wide, whose description names studio photos explicitly. A ratio differing from another by 0.28 is not a decision anyone makes consistently at a glance.

One component still writes 3/2 literally: .ml-dimension, the Discover entry grid, where the ratio is load-bearing — six tiles in two columns only resolve to a whole number of rows at 3:2. It is recorded here rather than tokenised because the token budget is at its ceiling and a fourth aspect used once would be a name for a single call site, which is the sprawl the ceiling exists to stop. Found 2026-08-31 while measuring contrast; this page had claimed the consolidation was total, and it was not.

--media-aspect-square
1/1
Album art, avatars, track thumbs
--media-aspect-wide
16/9
Studio photos, video, hero imagery
--media-aspect-card
4/3
Media card artwork

The scrim

One treatment, not four. Any text laid over artwork sits on --media-scrim — never on raw imagery, because a photograph's luminance is not something the type can negotiate with.

Yash Raj Sound Studios
Andheri West · Dolby Atmos

Same photograph without the scrim would put white type over a blown highlight.

The old catalogue offered four overlay treatments. Only the dark gradient survived, and the three that did not are recorded here rather than dropped in silence. Pink Tint and Duotone both put chrome colour ON the media, which inverts the one palette rule this system has — media carries the saturation, chrome does not add any. Left Fade was a layout need, not a treatment: a component wanting type beside artwork uses .ml-split-editorial, which does not tint the photograph at all.

Motion & object media

The old catalogue called these “Branded Media Assets” and listed them as a library to browse. They are not a library — each pool is already bound to a component, and that binding is the only reason a file here is part of the system. A pool with no component is not documented on this page.

PoolFolderFilesBound to
objectimg/5 — 3D object renders on transparent ground 2 c-bento
motionimg/6 — Short looping animations 1 c-bento
videoimg/4 — Real motion, muted and looping 3 c-video c-split-editorial
object
motion
video

Counts are read from disk at build time, so adding a file to a folder makes it available with no edit here — and build-hosting derives its ship-list from the markup this produces, so a pool and what actually deploys cannot drift.

Avatars

Four steps, and the profile header is --avatar-4. The old catalogue specified 96dp for a profile and 64dp for a card; 96 is not a step and adding one would break the four-step rule, so the profile header renders at 64 — the value --avatar-4's own description already assigns to it.

--avatar-1
24px
--avatar-2
32px
--avatar-3
48px
--avatar-4
64px

Foundations

Black, grey and white build every surface and control.

Colour

One book. brand-* entries are marketing only, not the UI palette — a screen never reaches for a brand* colour and a poster never reaches for the UI palette; the separation is carried by the name, not by a second group.

--color-ink#0D0D0DPrimary action AND primary text
--color-paper#FCFCFDApp canvas / page background
--color-white#FFFFFFCard and sheet fill
--color-surface#F8F8FBSubtle raised/sunken fill — search bars, inactive segments, skeletons
--color-line#D5D5DEHairline borders, dividers, list separators
--color-muted#66666FSecondary text, metadata, placeholder
--color-pink#EA4C89Brand accent — focus ring, selection, active tab, brand mark, waveform progress
--color-pink-pressed#C7295FTwo jobs, one token
--color-pink-container#FCE7F3The one permitted tinted surface — accent chips, progress tracks
--color-ink-pressed#2B2B2BPressed state of a primary (black) control — lifts off pure black so the press is visible
--color-success#22C55E
--color-warning#F59E0B
--color-error#DC2626
--color-brand-warm-pink#FF005CBrand pink
--color-brand-black#141621Brand black, faintly blue
--color-brand-white#FFFFFFThe supplied swatch labelled White carried HEX #000000 against RGB 255 255 255 — contradictory
--color-brand-dark-gray#4F5059EXPRESSION ONLY — never on a product screen
--color-brand-light-gray#C4C5C8EXPRESSION ONLY — never on a product screen
--color-info#2563EBInformational badge — 'On Tour', 'Remote available'
--color-disabled#9CA3AFInactive control borders and text
--color-scrimrgba(13,13,13,0.32)Backdrop behind drawers, sheets and modals
--color-purple#8B5CF6BADGES ONLY

Scales

Four steps each, exponential — every scale except type, which moved to seven on 2026-09-11 when the brand owner lifted the cap. Every step is visibly different from its neighbour; that is still the point.

1234
space4px8px16px32px
radius8px16px32px9999px
size32px40px48px56px
icon16px20px24px32px
avatar24px32px48px64px
elevation1.dp3.dp8.dp12.dp
opacity0.080.160.320.64
motion · web125ms200ms320ms500ms
motion · androidspring 1/1500spring 0.9/700spring 0.85/400spring 0.75/300

Type — 7 steps

Grown from four on 2026-09-11: 14px and 28px fill the two gaps the old 12/16/22/32 ramp left, and 40px is the hero step used once, on the pre-auth landing.

1234567
type · web12px–13px14px–15px16px–18px22px–28px28px–36px32px–44px40px–56px
type · android12sp14sp16sp22sp28sp32sp40sp
type · iOScaption1subheadlinebodytitle3titlelargeTitlelargeTitle

Type and motion are dual-authored: clamp() does not exist on native and native motion is spring physics, so a single web value could never be handed to a Compose engineer. Web clamp minimums equal the Android sp values, so this preview shows what the app will render.

Type specimens

Hero — the pre-auth landing headline, once per product
Display — hero headlines, now-playing track title, the one big number on a screen
Large title — a detail screen's headline, a figure inside a card
Title — section and card headings
Body — default UI copy and list items
Secondary body — supporting lines, list-item metadata, form help
Caption — metadata, labels and badges

Scale audit

Measured, not asserted. A step passes if each neighbour differs by at least 1.5× — roughly where a difference stops being arguable at a glance.

ScaleStepsRatiosVerdict
space4/8/16/322.0x, 2.0x, 2.0x. 8x spread.Pass
radius8/16/322.0x, 2.0x. Step 4 (9999) is functional, not a scale step.Pass
opacity0.08/0.16/0.32/0.642.0x, 2.0x, 2.0x. 8x spread.Pass
motion125/200/320/500ms1.6x, 1.6x, 1.56x. 4x spread.Pass
zIndex100/200/400/8002.0x, 2.0x, 2.0x.Pass
elevationblur 3/12/24/32clearly separable at every step.Pass
size32/40/48/561.25x, 1.2x, 1.17x. Constant set, not a scale — Material's 48dp / iOS's 44pt touch-target floor rules out an exponential ramp here.
type12/14/16/22/28/32/401.17x, 1.14x, 1.38x, 1.27x, 1.14x, 1.25x. Seven steps since 2026-09-11: 14 and 28 fill the two gaps the original 12/16/22/32 perfect-fourth ramp left, and 40 is the hero. Chosen for text, not a strict exponential scale.

Typography spec

Every axis of every step, and the Compose TextStyle it becomes. Generated from the same source the CSS is, so the app and this page cannot disagree.

TokenFluid value (web)WeightCompose TextStyleUsage
--type-1 12px → 13px 600 TextStyle(fontFamily = Inter, fontSize = 12sp, lineHeight = 16sp, fontWeight = FontWeight.W600) Micro labels, captions, badges, metadata, timestamps
--type-2 14px → 15px 400 TextStyle(fontFamily = Inter, fontSize = 14sp, lineHeight = 20sp, fontWeight = FontWeight.W400) Secondary body — supporting lines under a title, list-item metadata, form help. Added 2026-09-11: nothing sat within 2px of 14, so screens carried 14–15px as arbitrary sizes
--type-3 16px → 18px 400 TextStyle(fontFamily = Inter, fontSize = 16sp, lineHeight = 24sp, fontWeight = FontWeight.W400) Body copy, default UI text, list item titles
--type-4 22px → 28px 600 TextStyle(fontFamily = InterTight, fontSize = 22sp, lineHeight = 28sp, fontWeight = FontWeight.W600) Section headings, card titles, screen titles
--type-5 28px → 36px 600 TextStyle(fontFamily = InterTight, fontSize = 28sp, lineHeight = 36sp, fontWeight = FontWeight.W600) Large titles — a detail screen's headline, a figure inside a card. Added 2026-09-11 to fill the 22→32 gap, the widest in the old ramp
--type-6 32px → 44px 800 TextStyle(fontFamily = InterTight, fontSize = 32sp, lineHeight = 40sp, fontWeight = FontWeight.W800) Display — now-playing track title, the one big number on a screen
--type-7 40px → 56px 800 TextStyle(fontFamily = InterTight, fontSize = 40sp, lineHeight = 48sp, fontWeight = FontWeight.W800) Hero — the pre-auth landing headline only, one per product. Added 2026-09-11; the Lovable app shipped it first as its own --type-5. On iOS it maps to largeTitle, the largest Dynamic Type style
PropertyValueUsage
Paragraph spacingvar(--space-3) · 16pxBetween paragraphs
Max line widthvar(--layout-measure) · 64chReadable prose width — .ml-measure
Font fallback-apple-system, BlinkMacSystemFont, sans-serifDeclared inside each --font-* value
Number styleTabularStats, tables, timers — .ml-tabular

Sizing map

Component dimensions from the spec. Where a value already lands on a scale it is mapped, not duplicated — emitting it again would be a second name for the same number, which is how the previous system reached 248 tokens.

ComponentResolves toValue
--comp-btn-h-sm / -md / -lg--size-1 / --size-2 / --size-3 (32 / 40 / 48)
--comp-input-h--size-2 (40)
--comp-chip-h--size-1 (32)
FAB small / regular--size-2 / --size-4 (40 / 56)
Touch target min / comfortable--size-3 / --size-4 (48 / 56)
Nav height--size-3 (48)
Switch track height--size-1 (32); width is --component-switch-track (52)
--comp-card-padding / -radius--space-3 / --radius-3 (16 / 32)
--layout-gutter-mobile / -tablet / -desktop--space-3 / --space-4 / --space-4 (16 / 32 / 32)
--layout-gap-sm / -md / -lg--space-2 / --space-3 / --space-4 (8 / 16 / 32)
--layout-aspect-card / -hero / -avatar4/3 has no token (see meta.knownGaps); --media-aspect-wide 16/9; --media-aspect-square 1/1
--state-disabled-opacity--opacity-3 (0.32)
--state-hover-bg--color-ink at --opacity-1
--state-pressed-bg--color-ink at --opacity-2
--state-selected-bg--color-pink-container
--state-focus-ring2px --color-pink at 2px offset — one definition, in ml-core.css :focus-visible
--int-app-touch-target-min / -comfortable--size-3 / --size-4
--int-web-hover-transition--duration-2 (200ms), aliased as --gesture-hover-transition because the spec names it
--sp-xs / -sm / -md / -lg / -xl / -2xl--space-1 / -2 / -3 / -4; 24 and 48 have NO token by design — they are the midpoints an exponential scale deliberately omits
--r-card / -media / -pill / -avatar--radius-3 (32, spec said 24 — changed to match the scale) / --radius-2 / --radius-4 / --radius-4
Paragraph spacing--space-3 (16)
Font fallbackdeclared inside each --font-* value, not a separate token
Tabular numbersa utility class .ml-tabular, not a token — it is a font-feature-settings switch, not a value

Elevation & borders

TokenShadowUsage
--elevation-1 0 1px 3px rgba(13,11,38,0.08) Cards, chips, resting surfaces. Prefer a --color-line border before reaching for this.
--elevation-2 0 4px 12px rgba(13,11,38,0.05) Hover cards, dropdowns, popovers
--elevation-3 0 8px 24px rgba(13,11,38,0.08) FAB, side sheet, bottom sheet, mini-player
--elevation-4 0 12px 32px rgba(13,11,38,0.12) Modals, dialogs, full-screen overlays
--border-11px solid var(--color-line)Divider, card border, input rest
--border-22px solid var(--color-pink)Focus ring, selected card or chip
disabled border1px solid var(--color-disabled)Inactive controls

Component states

StateTriggerVisual
DefaultRestBase style
HoverPointer enter--elevation-2, translateY(-2px). Pointer only — no hover on touch.
FocusedKeyboard / Tab2px var(--color-pink) outline at 2px offset
PressedPointer downscale(0.96–0.97), var(--duration-1)
SelectedTap / clickvar(--color-ink) fill for commitment; var(--color-pink-container) for intent
DisabledInactiveopacity var(--opacity-3) · 0.32, pointer-events none
LoadingAsync.ml-skeleton shimmer
ErrorValidation failvar(--color-error) border and message
EmptyNo data.ml-empty — icon, message, CTA

Semantic roles

Which foundation colour fills which role. These emit no CSS of their own — on web you use the foundation token directly, because a role alias would be a second name for the same value. The role names exist for the Compose and SwiftUI exports.

RoleTokenUsage
Primary--color-inkCTAs. Black, not pink — set by the brand owner.
Accent--color-pinkFocus, selection, active tab, brand mark. Never a CTA fill.
Primary container--color-pink-containerBadge and tag ground
Surface--color-whiteCard and sheet fill
Surface variant--color-surfaceSearch bars, inactive segments, skeletons
Background--color-paperApp canvas
Outline--color-lineHairlines and dividers
Success--color-successConfirmed, available, verified
Warning--color-warningPending, caution
Error--color-errorRejected, critical, destructive
Info--color-infoOn Tour, remote available
Disabled--color-disabledInactive elements
Scrim--color-scrimBackdrop behind drawers, sheets, modals

Icon sizes

The four real icon tokens. 16 and 24 are the two drawn grids; 20 and 32 are scaled, which is why every icon carries a viewBox — without one, resizing crops the path instead of scaling it. (Intermediate sizes like 14/18/22 showed here until 2026-08-30 — they weren't tokens, just components that hadn't been snapped to the scale yet.)

16
20
24
32

App icon set

The launcher mark at the sizes Android and iOS ask for, each on the ground it is drawn for. Picking the variant by ground rather than by taste is the whole rule.

32px · paper
48px · paper
48px · ink
64px · ink

Accessibility floors

Meet WCAG AA contrast, support screen readers and keyboard/focus navigation, preserve clear focus states, and never communicate critical meaning through colour alone.

Reconciled 2026-08-31. This file predates the v9 system and several of its values had gone stale. Corrections are marked below; the rules that survived are unchanged. It is now rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue again.

Measured floors

RuleValue
Touch target--size-3 (48dp) web + Compose, 44pt iOS
Contrast, normal text4.5:1
Contrast, large text3:1
Focus ring2px --color-pink at 2px offset, :focus-visible only

Was “keep targets at least 44px” without qualification. 44 is the Apple floor; web and Android are 48. Both now ship, per platform, from one token source.

Standing rules

Decisions not taken

Spec items that were considered and deliberately NOT adopted, or moved out of CSS entirely. Moved here from Gaps on 2026-08-31: none of these is outstanding work, and listing a settled decision under "Gaps" reads as a backlog item nobody has got to. A gap is something missing; this is something decided.

ItemWhy
breakpoints 767/1023/1440 — decision, not a gapThe spec's four breakpoints were considered and NOT adopted, not overlooked. platform.windowSize keeps Material's 600/840 WindowSizeClass values because those are what Compose actually branches on, and the app is Android-first. Shipping web breakpoints that disagree with the native ones is the exact drift v9 removed. --layout-max 1440 is kept as a max-width, which is what the spec's 1440 figure really was.
density modesNot implemented, as the spec itself notes.
Snackbar 4s/10sDurations are behaviour, not design tokens — they belong to the toast controller, not the stylesheet. Documented in the toast section's prose instead.

System bars & insets

The app draws edge to edge — content renders behind the status and navigation bars, and the bars themselves stay transparent. Nothing may rely on the OS reserving that space, so every fixed-position component pads itself by an inset token. Recovered from the old catalogue's Android Platform section on 2026-08-31; the tokens already existed but nothing on this page said what they were for, which is how three of them ended up referenced by no component at all.

TokenValueCompose insetWhat it is
--safe-topenv(safe-area-inset-top, 24px) WindowInsets.statusBarsStatus bar. The fallback is the 24dp Android status bar, used when env() is unsupported.
--safe-bottomenv(safe-area-inset-bottom, 16px) WindowInsets.navigationBarsGesture bar / navigation bar.
--chrome-status-bar24px WindowInsets.statusBarsStatus-bar height as a plain number, for layout maths that cannot use env().
--chrome-nav-bar48px WindowInsets.navigationBarsThree-button navigation bar height.
--chrome-scrollbar12px Desktop scrollbar width. Web-only; there is no native counterpart.

Applied by .ml-appbar (padding-top: calc(var(--space-2) + var(--safe-top))), .ml-tabbar and the floating action button, so a screen author never adds inset padding by hand. The old catalogue also listed WindowInsets.ime, systemGestures and displayCutout: IME is a component here (see native keyboard & IME), and the other two are behaviour Compose handles, not values a stylesheet can hold.

Core · 39

Approved components are shared primitives, controls, and composable blocks. Create an implementation and a usage specification together.

Reconciled 2026-08-31. This file predates the v9 system and several of its values had gone stale. Corrections are marked below; the rules that survived are unchanged. It is now rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue again.

Implementation rules

Canonical component list

The ten below were the original core. The system now documents 133 sections across ml-core.css and ml-widgets.css; /guide is the live list and this table is kept as the historical minimum, not the ceiling.

ComponentPurpose
Button (primary, secondary, ghost)CTAs, actions, passive triggers
Input FieldForm fields, onboarding, credentials, messaging
ChipGenre/role/filter selectors (pill, toggle)
Search BarDirectory search with category filters
Bottom NavigationMaster app tab switching
Audio Player / WaveformPlayable audio moments with animated waveform
Bottom SheetModal overlay for confirmations, filters, forms
Empty StateUniversal template for empty lists and no results
Verification BadgeTrust signal for verified artists and studios
Status BadgeAvailability, confirmation, urgency indicators

base

ml-core.css

[hidden] must win. The UA stylesheet's `[hidden] { display: none }` has the lowest possible specificity, so ANY author display rule beats it — and this system sets display on nearly every component (.ml-btn is inline-flex, .ml-otp is flex). Without this, app-shell.js's state switching sets the attribute correctly and…

Document defaults, the focus ring, the reduced-motion guard and the [hidden] override. Not a component — no demo.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-hit

button

ml-core.css Compose · Button / FilledTonalButton / OutlinedButton, MLSize.s3 minHeight
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 168 screens across 24 flows — auth/email_auth, auth/email_verification, auth/forgot_password, auth/google_signin, auth/mobile_auth, auth/otp_verification and 162 more.

8 selectors .ml-btn .ml-btn--primary .ml-btn--secondary .ml-btn--accent .ml-btn--ghost .ml-btn--block .ml-btn--lg .ml-btn--sm

icon button

ml-core.css Compose · IconButton — note the 48dp box around a 20dp glyph
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 190 screens across 24 flows — auth/email_auth, auth/email_verification, auth/forgot_password, auth/google_signin, auth/mobile_auth, auth/otp_verification and 184 more.

4 selectors .ml-icon-btn .ml-icon-btn--bare .ml-icon-btn--primary .ml-icon-btn--muted

field

ml-core.css Compose · OutlinedTextField
Helper text
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 53 screens across 18 flows — auth/email_auth, auth/forgot_password, auth/mobile_auth, auth/reset_password, band/band_create, band/band_settings and 47 more.

1 selector .ml-field

chip

ml-core.css Compose · FilterChip

A chip is a CONTROL (filter, selection). For a read-only state label use .ml-status below — conflating the two is why screens grew both a .chip and a .status-pill that looked alike but behaved differently.

Press one — pressed is pink (intent), selected is ink (commitment).

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 40 screens across 11 flows — booking/configure_session, booking/filters, discover/advanced_filters, discover/businesses, discover/communities, discover/discover_opportunities and 34 more.

3 selectors .ml-chip .ml-chip__icon .ml-chip__dismiss

status

ml-core.css Compose · AssistChip(enabled=false) / Badge

Read-only state label. The container and text colours are DERIVED from the three status tokens with color-mix, so adding "available / pending / live" costs zero new tokens — screens were hardcoding #DCFCE7/#166534 pairs (89 off-palette hex values across the app) purely because these did not exist.

Available SelectiveRejected Live bandDraft
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 72 screens across 22 flows — auth/registration_write, band/band_create, band/band_profile_layout, band/band_settings, band/ensemble_lineup, band/upcoming_shows and 66 more.

7 selectors .ml-status .ml-status--neutral .ml-status--success .ml-status--warning .ml-status--error .ml-status--accent .ml-status--info

badge

ml-core.css

CATEGORY, not state. Purple is scoped to this one modifier by the palette rule "Pink=Brand. Black=Primary. Purple=Badges only" — reinstated 2026-08-31. A category badge says what KIND of thing this is (genre, service, role); the status colours say how it is GOING. Those were being conflated, which is why genre labels…

★ 4.9Gold SufiMixing

Purple is category, never state — a genre or service kind, not how something is going. It is scoped to this one modifier and appears nowhere else in the system.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 3 screens across 3 flows — discover/studios_spaces, home/home_dashboard, portfolio/add_collaborators.

6 selectors .ml-badge .ml-badge--accent .ml-badge--category .ml-badge--overlay .ml-badge--removable .ml-badge__remove

card

ml-core.css Compose · Card(border = BorderStroke(1.dp, MLColor.line))

A hairline border is the default separator. Elevation is opt-in, because a flat monochrome system separates by contrast, not by stacked shadows — which is why the elevation scale is 2 levels rather than 4.

Card

Hairline border by default; elevation is opt-in.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 15 screens across 4 flows — discover/discover_opportunities, discover/discover_profile_detail, discover/project_detail, discover/projects, discover/service_detail, discover/studio_profile_discover and 9 more.

6 selectors .ml-card .ml-card--inset .ml-card--flat .ml-card--lg .ml-card--padded .ml-card--raised

media

ml-core.css Compose · AsyncImage + Brush.verticalGradient(MLColor.scrim)

The one element allowed to carry saturation. Any text laid over artwork MUST sit on the scrim, never on raw imagery.

Text on the scrim
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 4 screens across 2 flows — discover/projects, discover/studios_spaces, portfolio/media_preview, portfolio/portfolio_dashboard.

7 selectors .ml-media .ml-media--square .ml-media--wide .ml-media--scrim .ml-media__overlay .ml-media__tag .ml-media__act

avatar

ml-core.css

Replaces the 14 broken var(--r-avatar) references: an avatar is radius-4.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 30 screens across 13 flows — auth/google_signin, booking/studio_profile, business_profiles/business_reviews_gallery_tab, communication/chat_conversation, communication/networking_feed_artist_profile, discover/business_profile and 24 more.

4 selectors .ml-avatar .ml-avatar--sm .ml-avatar--lg .ml-avatar-btn

section header + rail

ml-core.css

"Featured talent … See all" + a horizontally scrolling row. The single most repeated layout in the app and in the reference build.

Featured

See all
OneTwoThree
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 102 screens across 23 flows — band/band_create, band/band_profile_layout, band/band_settings, band/ensemble_lineup, booking/configure_session, booking/equipment_screen and 96 more.

3 selectors .ml-section .ml-section__link .ml-rail

list row

ml-core.css Compose · ListItem
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 10 screens across 4 flows — discover/service_detail, onboarding/instrument_proficiency, onboarding/review_confirm, portfolio/credit_attribution, portfolio/profile_project_view, portfolio/publish_project and 4 more.

4 selectors .ml-row .ml-row__body .ml-row__title .ml-row__meta

divider

ml-core.css

or
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — auth/welcome.

2 selectors .ml-divider .ml-divider--labelled

loading

ml-core.css

Skeletons, not spinners, for content — a spinner tells the user nothing about what is arriving. tokens.json v8 recorded state.loading as "no dedicated token"; this is that gap closed.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 19 screens across 11 flows — home/home_dashboard, notifications/notifications_center, auth/email_auth, auth/email_verification, auth/otp_verification, auth/splash and 13 more.

2 selectors .ml-skeleton .ml-spinner

brand

ml-core.css

This section used to SET the brand in type — Inter Tight 800 with a pink "d" — which is not the logo. The logo is drawn artwork and lives in brand/assets as nine variants. A typographic stand-in beside a real mark guarantees the two drift, so the mark is now an <img> of the real file and the type is only the fallback…

Eight of the nine files are white artwork and only mark-grey is drawn dark, so paper gets the mark and ink gets the lockups. Putting a white lockup on paper is not a styling slip — the wordmark simply disappears, which is what this demo used to do.

Type fallback — never beside the real mark.

MUSICLINKD
Eyebrow label
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 9 screens across 7 flows — auth/splash, auth/welcome, home/home_dashboard, onboarding/dashboard_handoff, user_settings/app_version, cms_pages/content_article and 3 more.

9 selectors .ml-logo .ml-logo--sm .ml-logo--lg .ml-logo--clear .ml-wordmark .ml-wordmark--on-media .ml-eyebrow .ml-eyebrow--on-media .ml-eyebrow--accent

tabular numbers

ml-core.css Compose · TextStyle(fontFeatureSettings = "tnum")
Proportional
1,204
8,891
11,073
Tabular
1,204
8,891
11,073

Digits share one advance width, so columns align and a changing number does not shift the text beside it.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-tabular

readable measure

ml-core.css

The spec's "Max Line Width". Prose past ~75 characters loses the return sweep; --layout-measure is 64ch, which lands mid-range for Inter.

A line of prose past roughly seventy-five characters starts to lose its return sweep — the eye has to hunt for the start of the next line. This paragraph is capped at --layout-measure, which is 64ch, and the cap is expressed in ch so it tracks the font rather than the viewport.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-measure .ml-page

nav app bar

ml-core.css Compose · TopAppBar(navigationIcon = ...)

Back-arrow bar for anything inside a flow. Separate from .ml-appbar, which is the tab-root large-title bar.

Screen title

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 38 screens across 4 flows — auth/email_auth, auth/google_signin, auth/mobile_auth, auth/otp_verification, discover/advanced_filters, discover/businesses and 32 more.

3 selectors .ml-navbar .ml-navbar__title .ml-navbar__spacer

segmented control

ml-core.css Compose · SingleChoiceSegmentedButtonRow
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 2 flows — auth/email_auth, onboarding/instrument_proficiency.

2 selectors .ml-segmented .ml-segmented__btn

OTP

ml-core.css

One box per digit. The row is a single logical input for a screen reader.

48 2
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — auth/otp_verification.

2 selectors .ml-otp .ml-otp__box

phone entry

ml-core.css
🇮🇳 +91
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — auth/mobile_auth.

2 selectors .ml-phone .ml-phone__prefix

banner

ml-core.css

Inline, in-flow message. Not a toast — this one stays until resolved.

Informational
Saved
Something went wrong
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 55 screens across 21 flows — auth/email_auth, auth/email_verification, auth/forgot_password, auth/google_signin, auth/mobile_auth, auth/otp_verification and 49 more.

5 selectors .ml-banner .ml-banner--error .ml-banner--info .ml-banner--success .ml-banner--warning

confirmation mark

ml-core.css

The raw green on its own 14% tint is 2.02:1, under the 3:1 floor for a graphic (1.4.11). Same darkening the status pills already use.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 6 screens across 4 flows — auth/google_signin, auth/otp_verification, auth/registration_write, booking/booking_success, onboarding/submit_publish, portfolio/success.

1 selector .ml-check

step progress

ml-core.css

Onboarding is 13 screens; without a visible position people abandon it. .onb-progress / .onb-step / .step-dots were redefined in 12, 12 and 7 screens respectively before this existed.

3/9
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 23 screens across 2 flows — onboarding/genres, onboarding/instrument_proficiency, onboarding/instruments, onboarding/languages, onboarding/location, onboarding/networking_links and 17 more.

6 selectors .ml-steps .ml-steps__track .ml-steps__fill .ml-steps__label .ml-dots .ml-dots__dot

choice list

ml-core.css Compose · ListItem + RadioButton / Checkbox

Single- or multi-select rows. The whole row is the target, not the box.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 105 screens across 23 flows — auth/google_signin, band/band_settings, booking/payment_screen, business_profiles/create_business, communication/collaboration_files, onboarding/dashboard_handoff and 99 more.

6 selectors .ml-choice .ml-choice__body .ml-choice__title .ml-choice__meta .ml-choice__mark .ml-chip-wrap

emoji glyph

ml-core.css

Emoji appear as CONTENT on role/instrument/category choices — the same call the approved mobile reference makes on its category tiles. They are sized here rather than with an inline font-size so 21 screens stop hardcoding 22px. Not typography: this is an icon slot that happens to hold an emoji, so it does not use a…

🎤🎸🥁
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 5 screens across 1 flow — onboarding/dashboard_handoff, onboarding/instrument_proficiency, onboarding/instruments, onboarding/primary_role, onboarding/secondary_role.

1 selector .ml-emoji

visually hidden

ml-core.css

Available to assistive tech, absent from the visual layout. For the cases where a screen genuinely needs a heading for structure but showing one would duplicate what the UI already says — a search screen whose subject IS the focused search field, for instance. Not for hiding real content.

.ml-visually-hidden — present for assistive tech, absent visually. Nothing renders here by design.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 2 flows — discover/global_search, search/universal_search.

1 selector .ml-visually-hidden

verified mark

ml-core.css

The icon library's check-circle is a solid glyph: tinted pink at 14px it reads as a featureless blob. A disc with the check knocked out in white stays legible at the size this actually renders.

Ananya Sharma
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 9 screens across 1 flow — discover/business_profile, discover/businesses, discover/discover_feed, discover/nearby, discover/people_talent, discover/project_detail and 3 more.

1 selector .ml-verified

switch

ml-core.css Compose · Switch

The single most-needed missing control: user_settings is 13 screens of preferences with nothing to render them. The track is the target — 48dp tall even though it looks 28dp — and the state is carried by aria-checked so a screen reader gets it without a parallel class.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 18 screens across 10 flows — booking/configure_session, booking/provider_availability, business_profiles/create_business, home/home_dashboard, notifications/notification_categories, notifications/notification_preferences_onboarding and 12 more.

1 selector .ml-switch

checkbox / radio

ml-core.css Compose · Checkbox · RadioButton

Standalone controls. .ml-choice covers the whole-row pattern; these are for a control that sits beside other content — a filter list, a consent line.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 29 screens across 12 flows — booking/equipment_screen, profile_management/profile_completion, services_availability/session_configuration, services_availability/studio_services_amenities, verifications/verification_screen, booking/configure_session and 23 more.

3 selectors .ml-check-ctl .ml-check-ctl--radio .ml-check-row

select

ml-core.css Compose · ExposedDropdownMenuBox

A native <select> styled to match .ml-field. Deliberately native rather than a custom dropdown: the OS picker is better on a phone than anything we would draw, and it is accessible for free.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-select

slider

ml-core.css Compose · Slider · RangeSlider

Range input, restyled. Both vendor thumb pseudo-elements are needed — there is no shared selector, and omitting one leaves that browser unstyled.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 2 flows — booking/filters, search/search_filters.

1 selector .ml-slider

accordion

ml-core.css Compose · ExpandableCard

Built on <details>/<summary> so it works with no JavaScript and is keyboard-accessible for free. FAQ and settings screens need it.

How do payouts work?
Payouts settle to your registered account after the booking completes.
Can I cancel a booking?
Yes, up to 24 hours before the session starts.
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-accordion .ml-accordion__body

dialog

ml-core.css Compose · AlertDialog

Centre-screen decision. Distinct from .ml-sheet, which is for choosing among options; a dialog is for confirming or refusing one. Uses <dialog> so focus trapping and Esc are the platform's job, not ours.

Delete this listing?

It will be removed from Market immediately. Enquiries already received are kept.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-dialog .ml-dialog__title .ml-dialog__body .ml-dialog__actions .ml-dialog--danger

floating action button

ml-core.css Compose · FloatingActionButton
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-fab .ml-fab--accent

button group

ml-core.css

Two or three actions of equal weight on one row. Not a segmented control — these fire actions, they do not select a mode.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 47 screens across 13 flows — booking/equipment_screen, profile_management/profile_completion, services_availability/session_configuration, services_availability/studio_services_amenities, verifications/verification_screen, booking/configure_session and 41 more.

6 selectors .ml-btn-group .ml-help .ml-check-ctl .ml-chip .ml-crumbs__item .ml-segmented__btn

Widgets · 94

Cards drive discovery and conversion. Every card conforms to the unified base container specification.

Reconciled 2026-08-31. This file predates the v9 system and several of its values had gone stale. Corrections are marked below; the rules that survived are unchanged. It is now rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue again.

Container specification

shape        --radius-3   (32px)
border       --border-1   solid --color-line
background   --color-paper
padding      --space-3    (16px)
touch target --size-3     (48dp minimum)

Was “RoundedCornerShape(24dp) / 1dp #ECECF1 / #FFFFFF / 16–20dp”. The colour was right (#ECECF1 is --color-line); 24dp and the 16–20dp range are not steps on any scale, so no card could have been built from tokens and matched them.

Implementation rules

Canonical card types

CardPurpose
Artist CardPrimary discovery unit for talent
Studio CardRecording venue and rehearsal space
Marketplace CardGear, instruments, equipment
Project CardCollaboration sessions and gigs
Opportunity CardOpen auditions and freelance calls
Review CardClient testimonials
Booking CardStudio reservations
Notification CardPush notification items
Message CardChat list items

app shell

ml-widgets.css

The phone column. 430dp is the widest current phone (iPhone Pro Max); the app is designed at 360-430 and centred beyond that rather than stretched, because a stretched phone layout is the classic tell of a web app.

.ml-app bounds the viewport at 430dp and .ml-app__body is the only thing that scrolls. Every screen in the preview uses it — see any screen under /preview rather than a demo here.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 205 screens across 24 flows — auth/email_auth, auth/email_verification, auth/forgot_password, auth/google_signin, auth/mobile_auth, auth/otp_verification and 199 more.

2 selectors .ml-app .ml-app__body

top app bar

ml-widgets.css Compose · TopAppBar / LargeTopAppBar
MusicLinkd

Discover

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 155 screens across 24 flows — auth/email_verification, auth/forgot_password, auth/reset_password, band/band_create, band/band_profile_layout, band/band_settings and 149 more.

4 selectors .ml-appbar .ml-appbar__titles .ml-appbar__title .ml-appbar__actions

bottom tab bar

ml-widgets.css Compose · NavigationBar + NavigationBarItem
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 14 screens across 2 flows — discover/businesses, discover/communities, discover/discover_feed, discover/discover_opportunities, discover/music_audio, discover/nearby and 8 more.

3 selectors .ml-tabbar .ml-tabbar__item .ml-tabbar__icon

category tile

ml-widgets.css Compose · FilterChip in a LazyRow, or a custom CategoryTile
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — marketplace/marketplace_browse.

3 selectors .ml-cat-tile .ml-cat-tile__icon .ml-cat-tile__label

artist card

ml-widgets.css

Widget_Directory: ArtistCard · Compose: UnifiedArtistCard

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — home/home_dashboard.

8 selectors .ml-artist-card .ml-artist-card__media .ml-artist-card__body .ml-artist-card__name .ml-artist-card__role .ml-artist-card__meta .ml-artist-card__rating .ml-artist-card__count

studio card

ml-widgets.css

Widget_Directory: StudioCard · Compose: UnifiedStudioCard

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 5 screens across 3 flows — booking/studio_discovery, booking/studio_profile, discover/business_profile, discover/discover_feed, home/home_dashboard.

7 selectors .ml-studio-card .ml-studio-card__media .ml-studio-card__body .ml-studio-card__name .ml-studio-card__loc .ml-studio-card__meta .ml-studio-card__price

media card

ml-widgets.css

Full-bleed artwork with the title ON the scrim — the Trending pattern. This is the palette rule at its purest: the card has no colour of its own.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 10 screens across 5 flows — band/band_profile_layout, business_profiles/business_overview, discover/community_detail, discover/discover_feed, discover/discover_profile_detail, discover/trending_recommended_sections and 4 more.

5 selectors .ml-media-card .ml-media-card__tag .ml-media-card__body .ml-media-card__title .ml-media-card__sub

marketplace card

ml-widgets.css

Widget_Directory: MarketplaceCard

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 5 screens across 2 flows — marketplace/marketplace_browse, marketplace/marketplace_saved_bookmarks, marketplace/marketplace_seller_profile, saved_favorites/saved_favorites_hub, marketplace/marketplace_item_detail.

8 selectors .ml-market-card .ml-market-card__media .ml-market-card__save .ml-market-card__body .ml-market-card__price .ml-market-card__title .ml-market-card__meta .ml-market-grid

booking / review / notification rows

ml-widgets.css

Widget_Directory: BookingCard, ReviewCard, NotificationCard

Andheri Live Room
16 Aug · 3 hrs · ₹9,600
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 24 screens across 10 flows — band/upcoming_shows, booking/my_bookings, booking/provider_requests, home/home_dashboard, booking/studio_profile, business_profiles/business_reviews_gallery_tab and 18 more.

11 selectors .ml-booking-card .ml-booking-card__thumb .ml-booking-card__body .ml-booking-card__title .ml-booking-card__meta .ml-review-card .ml-review-card__head .ml-review-card__stars .ml-review-card__body .ml-notification .ml-notification--unread

stat grid

ml-widgets.css

Widget_Directory: PublicReputationWidget

4,200Views
610Likes
88Shares
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 11 screens across 9 flows — booking/provider_dashboard, business_profiles/business_dashboard, business_profiles/business_owner_insights, discover/service_detail, home/home_dashboard, marketplace/marketplace_seller_profile and 5 more.

5 selectors .ml-stat-grid .ml-stat .ml-stat__num .ml-stat__label .ml-stat__delta

profile hero

ml-widgets.css

Widget_Directory: ProfilePreviewSheet header

Available

Rahul Iyer

Producer · Mumbai
8.1k followers★ 4.8
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 51 screens across 20 flows — discover/business_profile, discover/community_detail, discover/discover_profile_detail, discover/project_detail, discover/studio_profile_discover, portfolio/profile_project_view and 45 more.

6 selectors .ml-hero .ml-hero__body .ml-hero__name .ml-hero__sub .ml-hero__stats .ml-action-row

progress card

ml-widgets.css

Widget_Directory: ProfileCompletionMeter (proposed, PRODUCT-SPEC §3)

Profile 80% complete
Add streaming links to finish
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 7 screens across 6 flows — business_profiles/business_owner_insights, communication/collaboration_files, communication/collaboration_project, discover/trending_recommended_sections, profile_management/profile_completion, public_profile/profile_analytics and 1 more.

5 selectors .ml-progress .ml-progress__title .ml-progress__meta .ml-progress__track .ml-progress__fill

media upload grid

ml-widgets.css

PRODUCT-SPEC Part E flags this as the highest-priority missing widget —

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 8 screens across 5 flows — business_profiles/create_business, communication/collaboration_files, marketplace/marketplace_create_listing, profile_management/band_profile_editor, profile_management/business_profile_editor, profile_management/talent_profile_editor and 2 more.

4 selectors .ml-upload-grid .ml-upload-grid__item .ml-upload-grid__remove .ml-upload-grid__add

audio player

ml-widgets.css

Widget_Directory: AudioPlayerWidget · Compose: WaveformAudioPlayer

1:12
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 7 screens across 3 flows — communication/collaboration_files, communication/collaboration_project, discover/discover_profile_detail, discover/project_detail, discover/service_detail, portfolio/profile_project_view and 1 more.

10 selectors .ml-player .ml-player__btn .ml-player__wave .ml-player__bar .ml-player__time .ml-miniplayer .ml-miniplayer__art .ml-miniplayer__body .ml-miniplayer__title .ml-miniplayer__sub

bottom sheet

ml-widgets.css

Widget_Directory: AdvancedFiltersBottomSheet · Compose: ModalBottomSheet

Filters

Drag handle, scrim, detents.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 1 flow — saved_favorites/collection_detail, saved_favorites/saved_favorites_hub.

4 selectors .ml-sheet-scrim .ml-sheet .ml-sheet__handle .ml-sheet__body

toast

ml-widgets.css
Listing published
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-toast

empty state

ml-widgets.css

Nothing saved yet

Tap the bookmark on any profile to keep it here.

Start discovering
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 86 screens across 23 flows — auth/email_verification, auth/forgot_password, auth/reset_password, band/band_create, band/band_profile_layout, band/ensemble_lineup and 80 more.

3 selectors .ml-empty .ml-empty__title .ml-empty__body

scrollable category tabs

ml-widgets.css Compose · ScrollableTabRow

The dimension switcher: People / Businesses / Music / Services / Spaces / Communities. Too many to fit a segmented control, so it scrolls.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 38 screens across 12 flows — band/upcoming_shows, booking/availability_calendar, booking/my_bookings, booking/provider_availability, booking/provider_requests, business_profiles/business_equipment_tab and 32 more.

3 selectors .ml-tabs .ml-tabs__tab .ml-tabs--fill

result row

ml-widgets.css

The single densest unit in Discover: avatar/thumb, name, qualifier, a trailing signal (match, distance, rating) and one connect affordance.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 37 screens across 12 flows — booking/search_results, booking/studio_discovery, business_profiles/business_book_now, business_profiles/create_business, communication/collaborations, discover/business_profile and 31 more.

7 selectors .ml-result .ml-result__thumb .ml-result__thumb--square .ml-result__body .ml-result__name .ml-result__meta .ml-result__trail

match score

ml-widgets.css

AI recommendation strength. A number plus a bar, never colour alone.

88% match
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 6 screens across 3 flows — communication/ai_matchmaker_tab, discover/discover_feed, discover/people_talent, discover/search_results, discover/trending_recommended_sections, recommendation_engine/for_you.

5 selectors .ml-match .ml-match__pct .ml-match__label .ml-match__track .ml-match__fill

community card

ml-widgets.css

stacked member avatars

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 5 screens across 4 flows — discover/communities, band/band_profile_layout, communication/collaboration_project, discover/projects, notifications/notifications_center.

6 selectors .ml-community .ml-community__media .ml-community__body .ml-community__name .ml-community__meta .ml-facepile

service card

ml-widgets.css

A service is offered BY someone — the provider is the subject, the rate is a qualifier. Inverting that would make it a Market listing.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 6 screens across 4 flows — business_profiles/business_services_tab, discover/business_profile, discover/discover_profile_detail, discover/services, public_profile/talent_services_view, services_availability/my_services.

6 selectors .ml-service .ml-service__head .ml-service__title .ml-service__by .ml-service__foot .ml-service__rate

"what are you looking for?" grid

ml-widgets.css

The Discover Home entry point. Six dimensions, two columns, media-led.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — discover/discover_feed.

4 selectors .ml-dimension-grid .ml-dimension .ml-dimension__label .ml-dimension__count

recent / suggested search rows

ml-widgets.css
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 2 flows — discover/global_search, search/universal_search.

3 selectors .ml-suggest .ml-suggest__body .ml-suggest__kind

tab-bar beta marker

ml-widgets.css

Market is Beta. Labelling it in the nav is the honest thing to do and it stops the tab reading as a finished surface.

Shown on the Market tab in the bottom-tab-bar demo above.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 14 screens across 2 flows — discover/businesses, discover/communities, discover/discover_feed, discover/discover_opportunities, discover/music_audio, discover/nearby and 8 more.

1 selector .ml-tabbar__beta

inset card

ml-widgets.css

From the supplied visual references. The pattern across all of them: · the card is PADDED and the media sits INSET with its own radius, so the card reads as an object holding a picture rather than a picture with text stuck underneath · a pill overlays the media top-left, a circular control top-right · bold title, then…

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 5 screens across 4 flows — qr_share/digital_business_card, qr_share/qr_scanner, reviews/review_list, cms_pages/about_pricing_careers, subscription/plans.

18 selectors .ml-inset .ml-inset--raised .ml-inset--dark .ml-inset__media .ml-inset__media--square .ml-inset__tag .ml-inset__act .ml-chip--on-media .ml-icon-btn--on-media .ml-dots--on-media .ml-inset__body .ml-inset__title .ml-inset__sub .ml-inset__foot .ml-value .ml-btn--arrow .ml-btn__arrow .ml-btn--accent

lede

ml-widgets.css

Mixed weight inside one sentence, as in the reference: grey carries the sentence, ink carries the words that matter. Cheaper than colour and it works on a monochrome page.

Grey carries the sentence, ink carries the words that matter — cheaper than colour, and it works on a monochrome page.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — cms_pages/content_article.

1 selector .ml-lede

calendar

ml-widgets.css Compose · a DatePicker / DateRangePicker built on this grid

One month grid, four cell states. Needed twice over — booking's studio slots and Market's rental availability — which is why it lives in the system rather than in either flow. Bound to MarketplaceItemDoc.blockedDates for rentals; to the studio's own slots for booking.

March 2026
MTWTFSS
Selected In range Unavailable
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 3 screens across 2 flows — booking/availability_calendar, booking/provider_availability, marketplace/marketplace_availability.

10 selectors .ml-calendar .ml-calendar__head .ml-calendar__month .ml-calendar__dow .ml-calendar__grid .ml-calendar__day .ml-calendar__legend .ml-calendar__key .ml-calendar__key--sel .ml-calendar__key--blocked

chat

ml-widgets.css Compose · MessageBubble

The communication flow is 7 screens with no message component. Outgoing is ink, incoming is surface — never colour alone: the two also differ in alignment and corner shape, which survives a greyscale screenshot.

Today
Is the SM7B still available?11:04
It is — shockmount and cable included.11:06 · Read
Would you take ₹26,000?11:07
Sending my card for the Monsoon Sessions gig Not delivered · Tap to retry
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — communication/chat_conversation.

10 selectors .ml-chat .ml-bubble .ml-bubble--in .ml-bubble--out .ml-bubble__meta .ml-bubble--typing .ml-bubble--failed .ml-bubble__error .ml-chat__day .ml-composer

attachment

ml-widgets.css
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — communication/collaboration_files.

5 selectors .ml-attachment .ml-attachment__icon .ml-attachment__body .ml-attachment__name .ml-attachment__meta

timeline

ml-widgets.css

Ordered events with state: a booking's progress, a transaction's stages. The rail is drawn with a border on the item so it cannot desync from the dots.

  1. Offer accepted
    16 Aug · ₹38,000
  2. Awaiting handover
    Arrange a time with the seller
  3. Completed
    Review unlocks after handover

A stage can also fail — added 2026-08-30, the first two states couldn't represent a cancelled or failed step.

  1. Offer accepted
    16 Aug · ₹38,000
  2. Payment failed
    Card declined — buyer notified
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 6 screens across 5 flows — booking/availability_calendar, cms_pages/content_article, communication/collaboration_files, communication/collaboration_project, marketplace/marketplace_order_status, verifications/verification_status.

4 selectors .ml-timeline .ml-timeline__item .ml-timeline__title .ml-timeline__meta

metrics

ml-widgets.css

Deliberately not a charting library. Insights screens need a trend and a comparison, and both are cheaper as CSS than as a 90KB dependency. Bars are labelled and the sparkline carries its values in the markup, so neither communicates by shape alone.

4,210+18%
Listing views · last 7 days
MTWTFSS
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 8 screens across 7 flows — booking/provider_dashboard, business_profiles/business_dashboard, business_profiles/business_owner_insights, home/home_dashboard, marketplace/marketplace_seller_profile, public_profile/profile_analytics and 2 more.

10 selectors .ml-kpi .ml-kpi__num .ml-kpi__delta .ml-kpi__delta--up .ml-kpi__delta--down .ml-bars .ml-bars__bar .ml-bars__labels .ml-spark .ml-spark__bar

equalizer

ml-widgets.css

A playing indicator, not a control — it says "audio is running here" on a track row. Animated, and stopped entirely under reduced motion by the global guard in ml-core.css.

Tum Hi Toh (Unplugged) Now playing
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-eq

feed post

ml-widgets.css Compose · FeedPostCard

The one component the audit found genuinely missing after the 16-component pass: communication's networking feed defines .post-card / .post-head / .post-body / .post-actions locally and nothing in the system expresses it. Everything else those screens define maps onto .ml-row, .ml-rail, .ml-card or .ml-status…

Mehek Kapoor

Finished tracking the Monsoon Sessions EP today. Still looking for a bassist for two of the five tracks.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — communication/networking_feed.

9 selectors .ml-post .ml-post__head .ml-post__who .ml-post__name .ml-post__meta .ml-post__body .ml-post__media .ml-post__actions .ml-post__action

opportunity card

ml-widgets.css

Widget_Directory: OpportunityCard · opportunities flow + Discover

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — opportunities/opportunities_home.

8 selectors .ml-opportunity-card .ml-opportunity-card__head .ml-opportunity-card__title .ml-opportunity-card__by .ml-opportunity-card__body .ml-opportunity-card__foot .ml-opportunity-card__budget .ml-opportunity-card__closes

application card

ml-widgets.css

The applicant's side of an opportunity: what you sent and where it stands.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 1 flow — opportunities/my_applications, opportunities/my_opportunities.

5 selectors .ml-application-card .ml-application-card__body .ml-application-card__title .ml-application-card__meta .ml-application-card__foot

band card

ml-widgets.css

A band is a group, so the facepile is the identity — not one avatar.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-band-card .ml-band-card__media .ml-band-card__body .ml-band-card__name .ml-band-card__meta

rating

ml-widgets.css

Used on nearly every card. A number first, stars second: the number is what people compare, and it survives greyscale and a screen reader.

4.9 ★★★★★(128) 4.4 ★★★★☆(52)
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 24 screens across 7 flows — band/band_profile_layout, booking/studio_profile, business_profiles/business_equipment_tab, business_profiles/business_overview, business_profiles/business_reviews_gallery_tab, business_profiles/business_services_tab and 18 more.

4 selectors .ml-rating .ml-rating__score .ml-rating__stars .ml-rating__count

credit row

ml-widgets.css

A verified credit: who did what on a release, and whether it is confirmed. The confirmation state is the whole point of the Credits Trust Engine.

Rahul Iyer Mix Engineer Verified
Mehek Kapoor Composer Pending
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

4 selectors .ml-credit .ml-credit__body .ml-credit__who .ml-credit__role

order summary

ml-widgets.css

Line items with a total. Promised in the Flow 7 plan and never built; the booking flow needs it too. The total is separated by a rule and set in the display face, because it is the number people actually read.

Studio A · 3 hrs₹9,600
Engineer₹3,000
Platform fee₹640
Total₹13,240

Estimate — payment is not collected in this preview.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 49 screens across 18 flows — auth/reset_password, band/band_profile_layout, band/band_settings, band/ensemble_lineup, band/upcoming_shows, booking/booking_success and 43 more.

4 selectors .ml-summary .ml-summary__row .ml-summary__row--total .ml-summary__note

swipe deck

ml-widgets.css Compose · a Box with draggable + animateTo

Tinder-style discovery. Stacked cards with the next two peeking, so the deck reads as a deck rather than a single card. Drag distance is bound to --gesture-swipe-threshold rather than a literal, which is what the old SwipeDeckBlock hardcoded in App.tsx.

Ananya Sharma
Playback Vocalist · Mumbai
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

8 selectors .ml-deck .ml-deck__card .ml-deck__body .ml-deck__name .ml-deck__meta .ml-deck__actions .ml-deck__btn .ml-deck__btn--yes

time picker

ml-widgets.css

Booking picks a slot, not an arbitrary clock time — so this is a list of real availability, not a dial. A dial would imply any time is bookable.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — booking/availability_calendar.

2 selectors .ml-slots .ml-slot

drawer

ml-widgets.css

Side panel. Distinct from .ml-sheet: a sheet is a decision about the current screen, a drawer is navigation away from it.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-drawer .ml-drawer__body

video

ml-widgets.css

With controls — the default. 3 clips in the pool.

0:08

Muted autoplay loop — decorative only, never for content that carries meaning.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

3 selectors .ml-video .ml-video__play .ml-video__time

stem mixer

ml-widgets.css

Per-track level and mute for a multi-stem preview. Genuinely music-specific and the reason a generic component library cannot cover this product.

Vocals
Guitar
Bass
Drums
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-mixer .ml-mixer__track .ml-mixer__name .ml-mixer__level .ml-mixer__mute

editorial layouts

ml-widgets.css

Masonry, bento and split. Named because the styleguide had all three and they are genuinely different shapes, not one grid with options.

bento
Featured
Trending
Nearby
masonry
A note
Another
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

0 selectors

masonry

ml-widgets.css Compose · LazyVerticalStaggeredGrid
Saved to Moodboard
Saved to Moodboard
Saved to Moodboard

Nine tiles of unequal height, 790 in the pool. Columns: 2 / 3 at 600dp / 4 at 840dp.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 3 screens across 2 flows — business_profiles/business_gallery, business_profiles/business_reviews_gallery_tab, public_profile/media_gallery.

5 selectors .ml-masonry .ml-masonry--roomy .ml-mosaic-tile .ml-mosaic-tile__cap .ml-mosaic-tile__pin

bento

ml-widgets.css Compose · custom Grid with spans
Live sessions

The wide tile leads. Everything after it is a beat in the same bar.

Gear
Studios
Tall tile

Spans two rows at 600dp and up.

Collaborators
Dark bento

Tiles are translucent white, not a second black — so the same markup works over ink or over media.

Live rooms

5% white fill

Motion

12% white border

Both variants carry media in every tile — a bento with empty cells reads as a broken grid, not a considered one.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

6 selectors .ml-bento .ml-bento__card .ml-bento__img .ml-bento__title .ml-bento__body .ml-bento--dark

split editorial

ml-widgets.css Compose · Row with weight(1f) each
Find the room, not just the engineer.
Ananya Sharma · Playback vocalist, Mumbai
The flipped band puts the media second.
Alternating sides is what stops a run of these reading as a slideshow
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

4 selectors .ml-split .ml-split__media .ml-quote .ml-quote__cite

article grid

ml-widgets.css Compose · LazyVerticalGrid(Adaptive(300.dp))
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 1 flow — cms_pages/blog_changelog, cms_pages/content_home.

6 selectors .ml-articles .ml-article .ml-article__media .ml-article__tag .ml-article__title .ml-article__meta

surface effects

ml-widgets.css

Restrained on purpose. The palette rule says the chrome is monochrome and the media carries the colour, so these adjust SURFACE, never hue: a frosted panel over media, a soft lift, and a paper grain. No coloured glows.

.ml-glass — frosted panel over media
.ml-grain + .ml-lift

Surface only — no coloured glows, because the chrome stays monochrome.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 6 screens across 2 flows — communication/networking_feed_artist_profile, public_profile/public_profile_view, public_profile/public_profile_view_band, public_profile/public_profile_view_business, public_profile/public_profile_view_talent, public_profile/public_profile_view_venue.

4 selectors .ml-glass .ml-glass--dark .ml-lift .ml-grain

tooltip

ml-widgets.css Compose · PlainTooltip (Material3)

Desktop only — a touch screen has no hover. On a phone use Help or a sheet.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-tip .ml-tip--below

popover

ml-widgets.css Compose · DropdownMenu / ExposedDropdownMenu
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

8 selectors .ml-pop-anchor .ml-pop .ml-pop--left .ml-pop__item .ml-pop__item--danger .ml-pop__sep .ml-pop__msg .ml-pop__msg-title

help button

ml-widgets.css Compose · IconButton + DropdownMenu
Industry verified
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-help

combobox

ml-widgets.css Compose · ExposedDropdownMenuBox
3 results
Tabla
Tabor
Guitar (tabbed)
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-combo .ml-combo__list .ml-combo__opt .ml-combo__empty .ml-combo__clear

breadcrumb

ml-widgets.css Compose · BreadcrumbRow (custom)
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-crumbs .ml-crumbs__item

pricing tiers

ml-widgets.css Compose · PlanCard (custom)
Free
₹0 /month
  • Profile and portfolio
  • 3 applications a month
  • Verified badge
Studio
₹1,999 /month
  • Everything in Pro
  • Team seats and booking

The recommended tier is marked by border and label, not by colour alone.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 2 flows — cms_pages/about_pricing_careers, subscription/plans.

10 selectors .ml-tiers .ml-tier .ml-tier--featured .ml-tier__flag .ml-tier__name .ml-tier__price .ml-tier__unit .ml-tier__feats .ml-tier__feat .ml-tier__feat--off

collage

ml-widgets.css Compose · CollageGrid (custom)
+7
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

3 selectors .ml-collage .ml-collage__hero .ml-collage__more

social sign-in button

ml-widgets.css Compose · SocialSignInButton (custom)

Provider marks are the one documented palette exception — their brand terms fix the colours.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-btn--social

native keyboard & IME

ml-widgets.css Compose · WindowInsets.ime + KeyboardOptions
enterkeyhint="send"
System keyboard — 45% of the screen
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

3 selectors .ml-ime-pad .ml-ime-bar .ml-ime-bar__done

feature grid

ml-widgets.css Compose · LazyVerticalGrid(Adaptive(280.dp))

Matched, not searched

Briefs go to the twelve people who actually fit, not the twelve hundred who might.

Credits that hold up

Every credit is confirmed by a second party before it counts.

Paid on delivery

Escrow releases when the stems land, not when someone remembers.

Unverified credits

Anyone can claim a session. Nothing proves it.

Cold outreach

The same fifty DMs to the same fifty inboxes.

Accent disc for capability, neutral disc for problem — a pain point is not an accent.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — cms_pages/marketing_homepage.

6 selectors .ml-features .ml-feature .ml-feature__icon .ml-feature__title .ml-feature__body .ml-feature--problem

testimonial

ml-widgets.css Compose · TestimonialCard (custom)
Three confirmed credits in a fortnight, and every one of them from someone who found me rather than the other way round.
Ananya Sharma
Playback vocalist · Mumbai
3Credits
14Days
4.9Rating
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — public_profile/public_profile_view_talent.

7 selectors .ml-testimonial .ml-testimonial__quote .ml-testimonial__user .ml-testimonial__name .ml-testimonial__role .ml-testimonial__stats .ml-testimonial__stat

ambient album card

ml-widgets.css Compose · AlbumCard (custom)
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-album .ml-album__frame .ml-album__play .ml-album__title .ml-album__meta

trust & verification

ml-widgets.css Compose · TrustRow (custom)
Identity
Verified by Aadhaar eKYC · Mar 2026
Credit · Dil Ki Raah
Confirmed by Yash Raj Sound Studios
Payout account
Verified by penny-drop · Feb 2026
98%Response
6 yrsOn MusicLinkd

Every tick names its source. A tick with no source is decoration.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — public_profile/public_profile_view_talent.

6 selectors .ml-trust .ml-trust__row .ml-trust__mark .ml-trust__what .ml-trust__who .ml-trust__stats

sticker

ml-widgets.css Compose · overlay Text with rotation
Now booking
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-sticker

ambient mosaic panel

ml-widgets.css Compose · Box with a blurred image wall behind
MUSICLINKD

72,000 verified music professionals.

The wall is decorative and aria-hidden; the card carries the meaning. Drift respects prefers-reduced-motion.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-wall .ml-wall__bg .ml-wall__col .ml-wall__col--drift .ml-wall__card

permission dialog

ml-widgets.css Compose · rememberPermissionState + AlertDialog

Allow microphone access?

Needed to record scratch takes for a brief. Nothing is recorded until you tap Record.

Earns the OS prompt before firing it — Android remembers "don't ask again" after two refusals.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-permission .ml-permission__icon .ml-permission__title .ml-permission__why .ml-permission__acts

camera picker

ml-widgets.css Compose · ActivityResultContracts.TakePicture / PickVisualMedia
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-capture .ml-capture__opt

audio recorder

ml-widgets.css Compose · MediaRecorder + AudioAmplitude
Recording 00:14
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

7 selectors .ml-rec .ml-rec__head .ml-rec__dot .ml-rec__time .ml-rec__meter .ml-rec__bar .ml-rec__acts

stem dropzone

ml-widgets.css Compose · dragAndDropTarget
Drop stems here WAV, AIFF up to 200MB
Release to upload
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 3 screens across 3 flows — communication/collaboration_files, qr_share/qr_scanner, verifications/verification_screen.

3 selectors .ml-dropzone .ml-dropzone__hint .ml-dropzone__formats

inline editor

ml-widgets.css Compose · editable Text with a focus affordance
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

3 selectors .ml-inline .ml-inline__pencil .ml-inline__acts

error boundary

ml-widgets.css Compose · ErrorScreen

Something broke on our end

The page didn't load. Your data is safe — try again in a moment.

Ref · 8F2C-91A
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — home/home_dashboard.

5 selectors .ml-error .ml-error__mark .ml-error__title .ml-error__body .ml-error__ref

offline & adaptive banners

ml-widgets.css Compose · ConnectivityBanner / InstallPromptBanner
You're offline — changes will sync when you're back.
Install MusicLinkd for faster access and offline briefs.
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 1 screen across 1 flow — home/home_dashboard.

3 selectors .ml-banner--offline .ml-banner--promo .ml-banner__dismiss

QR share

ml-widgets.css Compose · QrBitmap + ShareSheet
@arijitsen
Scan to view profile
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 2 screens across 1 flow — qr_share/digital_business_card, qr_share/qr_share_flow.

4 selectors .ml-qr .ml-qr__code .ml-qr__handle .ml-qr__hint

animated success

ml-widgets.css Compose · AnimatedVisibility + scaleIn

Booking confirmed

Yash Raj Sound Studios · Sat, 4 PM

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

4 selectors .ml-success .ml-success__mark .ml-success__ring .ml-success__tick

what's new

ml-widgets.css Compose · ReleaseNotesSheet
Version 4.2 · Aug 2026
New
Rental marketplace
Rent gear and studio time from verified owners.
Fixed
Booking calendar
Blocked dates now sync correctly across time zones.
Improved
Credit verification
Second-party confirmation now takes under 48 hours.
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

6 selectors .ml-whatsnew .ml-whatsnew__ver .ml-whatsnew__item .ml-whatsnew__kind .ml-whatsnew__what .ml-whatsnew__why

android app grid

ml-widgets.css Compose · adaptive-icon layers
Circle mask
Squircle mask
Rounded square

Dashed line marks the 66.6% safe zone — OEM masks vary and only the centre is guaranteed visible.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

8 selectors .ml-appgrid .ml-appgrid__cell .ml-appgrid__canvas .ml-appgrid__canvas--circle .ml-appgrid__canvas--squircle .ml-appgrid__canvas--rounded .ml-appgrid__safe .ml-appgrid__label

person row

ml-widgets.css Compose · ListItem with leadingContent = Avatar
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 24 screens across 12 flows — band/band_create, band/ensemble_lineup, business_profiles/business_overview, business_profiles/business_owner_insights, business_profiles/business_team_tab, communication/ai_matchmaker_tab and 18 more.

1 selector .ml-person-row

collaborator match rail

ml-widgets.css Compose · RecommendedCollaboratorsSection

Widget_Directory: CollaboratorMatchWidget · a rail OF the card above

Layout only — it does not restyle the cards it holds, so the two cannot drift.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-collab-rail

discovery search result card

ml-widgets.css Compose · DiscoverySearchResultCard

Widget_Directory: DiscoverySearchResultCard · global search result item

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-search-result .ml-search-result__body .ml-search-result__name .ml-search-result__meta .ml-search-result__tags

networking feed

ml-widgets.css Compose · NetworkingFeed

Widget_Directory: NetworkingFeed · social activity feed

Karan SaxenaGuitarist · 2h

Tracked three takes of the bridge today. The room finally sounds right.

Priya SharmaProducer · 5h

Looking for a tabla player for a session in Bandra next week.

You're all caught up

The post is .ml-post. This is the feed around it — it owns the two states a post has no concept of, loading-more and empty.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-feed .ml-feed__end

band members

ml-widgets.css Compose · BandMembersWidget

Widget_Directory: BandMembersWidget · roster with instrument roles

Raman Negi
Vocals, rhythm guitar
Paras Thakur
Lead guitar
Sahil Sarin
Drums
Ramit Mehra
Bass
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-roster .ml-roster__member .ml-roster__id .ml-roster__name .ml-roster__instrument

studio venue list item

ml-widgets.css Compose · StudioVenueListItem

Widget_Directory: StudioVenueListItem · compact StudioCard

Andheri Live Room
Andheri East · 1.4 km
★ 4.4
Yash Raj Sound Studios
Andheri West · 3.2 km
★ 4.9

A modifier on .ml-studio-card, not a second block — same data, one-line layout.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-studio-card--compact

studio spec

ml-widgets.css Compose · StudioSpecWidget

Widget_Directory: StudioSpecWidget · console, monitors, mic inventory

Console
SSL 9000J, 72 channels
Monitors
PMC IB2S · Yamaha NS-10M
Microphones
Neumann U87 Ai · AKG C414 · Shure SM7B
Outboard
Neve 1073 ×2 · Urei 1176 · Lexicon 480L
Room
Live room 620 sq ft · booth 90 sq ft
StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

4 selectors .ml-spec .ml-spec__row .ml-spec__key .ml-spec__val

project card

ml-widgets.css Compose · UnifiedProjectCard

Widget_Directory: ProjectCard · portfolio release presentation

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-project-card .ml-project-card__body .ml-project-card__title .ml-project-card__meta .ml-project-card__credits

recent project card

ml-widgets.css Compose · RecentProjectCard

Widget_Directory: RecentProjectCard · compact dashboard ProjectCard

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

1 selector .ml-project-card--compact

track card

ml-widgets.css Compose · UnifiedTrackCard

Widget_Directory: TrackCard · track release discovery item

Dil Ki Raah
3:42 SpotifyYouTube
128k
Neon Horizon
4:05 SpotifyYouTube
86k
Tu Hi Bata
3:18 SpotifyYouTube
54k

Platforms are named in the existing badge — the system ships no third-party logo artwork.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

6 selectors .ml-track .ml-track__body .ml-track__title .ml-track__meta .ml-track__platforms .ml-track__plays

audio podcast demo

ml-widgets.css Compose · AudioPodcastDemoWidget

Widget_Directory: AudioPodcastDemoWidget · inline demo player

Demo — session reel
1:24

A modifier on .ml-player, not a second player — the transport and waveform are the same component.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

2 selectors .ml-player--inline .ml-player__title

hire contact modal

ml-widgets.css Compose · HireContactModal

Widget_Directory: HireContactModal · hiring inquiry

Scope
Proposed date
Budget
per day

Form body only. The shell is .ml-sheet or .ml-dialog, so this cannot fork their open/close behaviour.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Not used by any screen yet. Built and documented here; no flow has recycled it.

5 selectors .ml-hire .ml-hire__scope .ml-hire__row .ml-hire__label .ml-hire__budget

share sheet

ml-widgets.css Compose · WhatsAppShareSheet

Widget_Directory: WhatsAppShareSheet · external share with preview

Named for the job, not the destination — a .ml-whatsapp-sheet guarantees a near-identical .ml-telegram-sheet later.

StatesHoverFocusedPressedSelectedDisabledLoadingErrorEmptyOpen

Recycled on 9 screens across 5 flows — business_profiles/create_business, marketplace/marketplace_create_listing, profile_management/band_profile_editor, profile_management/business_profile_editor, profile_management/talent_profile_editor, profile_management/venue_profile_editor and 3 more.

10 selectors .ml-share .ml-share__preview .ml-share__msg .ml-share__channels .ml-mosaic-tile__pin .ml-mixer__mute .ml-banner__dismiss .ml-upload-grid__remove .ml-upload-grid__add .ml-market-card__save

Motion

Use purposeful motion only: pressed state, gentle card lift, sheet/modal fade and scale, swipeable discovery, audio waveform feedback, and skeleton loading. Respect reduced-motion preferences.

Reconciled 2026-08-31. This file predates the v9 system and several of its values had gone stale. Corrections are marked below; the rules that survived are unchanged. It is now rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue again.

Timing

Web durations are the four --duration-* tokens. Native does not take a duration — it takes a spring, and MLMotion.spring1..4 are emitted to both Compose and SwiftUI from the same source.

TokenWebUsage
--duration-1125msButton press, chip toggle, ripple
--duration-2200msHover, icon change, colour change, dismissal
--duration-3320msSheet reveal, card lift, shared-element transform
--duration-4500msModal fade+scale, splash

Was 150/200/300/500. Three of the four disagreed with the shipped tokens.

Rules

Known gap

The system has feedback motion but no choreography: 0 entry animations, 0 view transitions, 0 scroll-driven motion, and state switching is a hard cut across 518 states. See docs/09-Roadmap/motion-plan.md.

Four steps, dual-authored. Web gets a duration and a cubic-bezier; native gets spring physics, because a duration is not translatable to a spring and pretending otherwise was the web-shaped assumption in the old system. Press Play to run each one.

1 · Press, ripple, toggle, chip select — must feel instant
web 125ms cubic-bezier(0.4, 0, 0.2, 1) · android spring(1, 1500) · iOS response 0.15
2 · Icon change, colour change, hover lift, dismissal
web 200ms cubic-bezier(0.4, 0, 0.2, 1) · android spring(0.9, 700) · iOS response 0.25
3 · Sheet reveal, card lift, shared-element / container transform
web 320ms cubic-bezier(0.05, 0.7, 0.1, 1) · android spring(0.85, 400) · iOS response 0.35
4 · Entrance, modal, splash, expressive moments (the Shazam result reveal)
web 500ms cubic-bezier(0, 0.35, 0, 1.25) · android spring(0.75, 300) · iOS response 0.5

Every animation in the system is disabled under prefers-reduced-motion, which Android reads as ANIMATOR_DURATION_SCALE.

Patterns · 205

Canonical layout families. A new page should start from one of these templates.

Reconciled 2026-08-31. Rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue. Its interactive reference used to be styleguide.html, which now 301-redirects to /guide.

The nine families below predate the flow model. /guide → Patterns is the live list — 24 flows generated from webapp/flows/. These remain the layout archetypes those flows are built from.

Template families

TemplatePurposeKey sections
SplashApp launchCentered logo on dark background, fade-in
LoginAuthenticationEmail/password, social auth, brand mark
OnboardingProfile setupProgress indicator, role selection, photo upload, genre/skills, availability
HomePersonalized dashboardGreeting, quick stats, activity feed, recommendations, upcoming bookings
DiscoverCard-driven discoverySearch bar, filter chips, card grid, skeleton loading, empty state
Artist ProfileTalent showcaseHero, About, Audio, Projects, Credits, Reviews, Gallery, Services, sticky Hire CTA
Studio ProfileBusiness showcaseIdentity header, equipment, rooms, calendar, reviews, Booking CTA
MarketplaceGear & instrument listingsCategory tabs, search, filter bar, listing grid, sorting
SettingsAccount managementProfile, Account, Notifications, Privacy, Payments, Help, Log out

Rules

Use shared modules — identity, hero, audio, projects, credits, gallery, services, equipment, availability, reviews, contact, and business information — to compose profiles. Do not create a wholly separate layout for every role.

Reconciled 2026-08-31. Rendered into /guide by scripts/build-guide.mjs, so this file is the source and cannot drift from the catalogue. Its interactive reference used to be styleguide.html, which now 301-redirects to /guide.

Still unbuilt in the design layer. role_profiles is a live Firestore collection with an admin route, and none of the four families or their module lists appear in /guide. This file is currently the only place the composition rules exist — see the Gaps ledger, "Live data the design layer cannot see".

Primary template families

FamilyRolesKey modules
TalentSinger, Instrumentalist, Producer/Engineer, DJ/Performer, Composer, LyricistHero + photo capture, verification badge, nav tabs (About, Projects, Credits, Reviews), audio waveform, Connect/Hire CTA
BandEnsembles, groups, duosBanner + logo, lineup carousel (member cards), technical rider & stage plot, media reel, Booking CTA
BusinessRecording Studio, Record Label, Music School, Equipment DealerIdentity header, equipment checklist, room photos, availability calendar, reviews, Booking CTA (studio) / Course catalog (school) / Artist grid (label) / Product catalog (dealer)
VenueConcert hall, club, amphitheater, festivalHero imagery + address, capacity & features ledger, event calendar, Booking CTA for tour managers

Category-specific modules (Talent)

Role variantModules
Singer / VocalistVocal register, performance languages, microphone specs
InstrumentalistCore instrument registry, touring setup, session availability
Producer / EngineerDAW stack, outboard gear ledger, A/B mixing deck
DJ / PerformerDeck setup, residency timeline, festival logs
ComposerFilmography, original scores carousel
LyricistSignature lyric cards, IPRS verification, writing languages

Rules

Composed patterns are real screens, not mockups — every one below is live under /preview and built from the components above. Listed straight from the repo, so this cannot drift the way the old block list did (it claimed 84 against an actual 94).

Home

flow 0 · 1 on the system

User Auth

flow 1 · 10 on the system

User Onboarding

flow 2 · 16 on the system

Add Portfolio

flow 3 · 12 on the system

Discover

flow 4 · 21 on the system

Opportunities

flow 5 · 7 on the system

Communication & Collaboration

flow 6 · 11 on the system

Marketplace — Buy/Sell/Rent

flow 7 · 12 on the system

Booking

flow 8 · 14 on the system

Profile Management

flow 10 · 10 on the system

Services, Availability

flow 11 · 6 on the system

Business Profiles (Studios, Labels)

flow 12 · 10 on the system

Notifications

flow 13 · 6 on the system

Public Profile

flow 14 · 9 on the system

Band

flow 15 · 5 on the system

Verifications

flow 16 · 2 on the system

Reviews

flow 17 · 11 on the system

Subscription

flow 18 · 4 on the system

Search

flow 19 · 2 on the system

Recommendation Engine

flow 20 · 2 on the system

Settings & Support

flow 21 · 19 on the system

CMS Pages

flow 22 · 7 on the system

QR Code & Profile Sharing

flow 23 · 4 on the system

Saved & Favorites

flow 24 · 4 on the system

Icons · 423

From pinterest/gestalt (Apache-2.0), extracted to SVG. Gestalt is reference only — no Gestalt code ships. Screens inline these at build time via icon(), which fails the run on an unknown name rather than rendering an empty box.

Two optical grids. 25 "compact" icons are drawn on a 16-unit box and 398 standard icons on 24. Rendering a 16-unit glyph at 22px inflates its strokes about 1.4x against a 24-unit one beside it — which is what made the set look unstable. Each is now shown at its own native size.

Gestalt · 423 — the product set

360
3d
3d-move
accessibility
ad
ad-group
add
add-circle
add-layout
add-pin
add-section
ads-overview
ads-stats
alert
align-bottom
align-bottom-center
align-bottom-left
align-bottom-right
align-middle
align-top
align-top-center
align-top-left
align-top-right
alphabetical
amazon
android-share
angled-pin
animate
api
apple
apps
ar-try-on
arrow-back
arrow-circle-back
arrow-circle-down
arrow-circle-forward
arrow-circle-up
arrow-counter-clockwise
arrow-double-back
arrow-double-forward
arrow-down
arrow-end
arrow-forward
arrow-left-curved
arrow-nested
arrow-start
arrow-up
arrow-up-left
arrow-up-right
arrows-vertical
aspect-ratio
audio-bars
audio-mix
audio-playing
bell
bell-fill
birthday-cake
blur
board
board-sticker-large
board-sticker-small
bold
border
border-shadow
briefcase
building-business
business-hierarchy
calendar
calendar-check
camera
camera-flip
camera-roll
cancel
canonical-pin
captions
captions-outline
card-stack
card-stack-refresh
check
check-circle
check-circle-fill
chevron-down-circle
chevron-left-circle
chevron-right-circle
chevron-up-circle
circle
circle-ellipsis
circle-information-fill
circle-initializing
clear
clipboard
clips
clock
clock-checked
cloud-server
code
code-check
cog
cog-fill
collage
collapse
color
color-palette
color-picker
color-solid
color-split
compact-add-compact
compact-angled-pin-compact
compact-arrow-up-right-compact
compact-cancel-compact
compact-check-circle-fill-compact
compact-check-compact
compact-chevron-down-compact
compact-chevron-left-compact
compact-chevron-right-compact
compact-chevron-up-compact
compact-dash-compact
compact-ellipsis-compact
compact-info-circle-fill-compact
compact-lock-compact
compact-maximize-compact
compact-mute-compact
compact-sound-compact
compact-sound-slash-compact
compact-sparkle-compact
compact-workflow-status-canceled-compact
compact-workflow-status-halted-compact
compact-workflow-status-in-progress-compact
compact-workflow-status-problem-compact
compact-workflow-status-unstarted-compact
compact-workflow-status-warning-compact
compass
compass-fill
compose
contrast
conversion-tag
copy-to-clipboard
credit-card
credit-card-plus
crop
crystal-ball
cutout
dash
data-source
deselect
design
desktop
diagnostics
directional-arrow-left
directional-arrow-right
download
drag-drop
draw
dropbox
duplicate
edit
ellipsis
envelope
erase
erase-auto
etsy
expand
eye
eye-hide
face-happy
face-neutral
face-sad
face-smiley
face-smiley-outline
face-smiley-plus
face-tryon
facebook
fade
ferris-wheel
file-box
file-unknown
fill-opaque
fill-transparent
filter
flag
flame
flash
flash-automatic
flash-slash
flashlight
flip-horizontal
flip-vertical
folder
folder-fill
forward
gauge
ghost
ghost-fill
gif
gif-visual
gift
globe
globe-checked
gmail
graph-bar
graph-pie
hand
hand-pointing
handle
heart
heart-broken
heart-health
heart-outline
highlights
history
home
home-fill
idea-pin
image-portrait
imessage
impressum
indent
info-circle
information
insights-audience
insights-conversion
instagram
instagram-stories
invoice
italics
kakao-talk
key
knoop
lab-flask
lasso-magic
layers-stack
layout
lightbulb
lightning-bolt-circle
link
link-broken
lips
list-bullets
list-numbered
list-numbered-rtl
location
lock
logo-large
logo-small
logout
magic-pen
magic-wand
magnifying-glass-sparkle
manage-access
margins-large
margins-medium
margins-small
maximize
megaphone
menu
messenger
microphone
minimize
mobile
moon
move-pin
music-off
music-on
mute
mute-fill
orientation-landscape
orientation-portrait
outdent
outlook
overlay-text
overlay-text-outline
overview
paper-clip
paper-lines-plus
pause
pen
pen-auto
people
performance-plus
person
person-add
person-fill
person-magnifying-glass
phone
pin
pin-hide
pincode
pinterest
play
protect
qr-code
question-mark
quote
record-limit
record-limit-10
record-limit-15
record-limit-30
record-limit-5
record-limit-60
redo
refresh
remove
reorder-images
replace
report
rewind
ribbon
rocketship
rotate
saturation
save-outline
saved
scale
scissors
search
search-by-image
search-fill
security
select
send
shadows
shapes
share
shopping-bag
shopping-bag-fill
shrink
shuffles
skintone
slide
smiley
snapchat
sort-ascending
sort-descending
sound
sound-fill
sound-slash
sound-slash-fill
sparkle
speech
speech-ellipsis
speech-ellipsis-fill
speech-exclamation-point
speech-heart
speech-outline
speed
speed-.3x
speed-.5x
speed-1x
speed-2x
speed-3x
spread
square-plus
square-plus-fill
star
star-half
star-outline
sticker
sticker-image
sun
swap
switch-account
table
tag
tag-star
target
telegram
template
terms
text
text-align-center
text-align-left
text-align-right
text-all-caps
text-extra-small
text-invert
text-large
text-line-height
text-medium
text-sentence-case
text-size
text-small
text-spacing
text-sticker
threads
thumbs-down
thumbs-up
timer
timer-10
timer-3
tint
trash-can
trending
underline
undo
unlock
upload-feed
viber
vibrance
video-advance-10-seconds
video-camera
video-rewind-10-seconds
view-type-default
view-type-default-fill
view-type-dense
view-type-list
view-type-sparse
visit
warmth
wave
whatsapp
wifi-no
workflow-status-all
workflow-status-canceled
workflow-status-halted
workflow-status-in-progress
workflow-status-ok
workflow-status-problem
workflow-status-queued
workflow-status-unstarted
workflow-status-warning
x-social
yahoo
youtube

Lucide · 2006 — the breadth set

Restored 2026-08-31 on the brand owner's instruction. styleguide.html had specified “Lucide icons, 1.75px stroke” and the v9 rebuild replaced it wholesale with Gestalt; both now ship. Vendored from lucide-react@1.28.0 (ISC) — the package was already an admin dependency, so this is extracted from the installed copy rather than fetched, and the build fails if any icon does not parse.

Never mix the two inside one control or one toolbar. Gestalt is filled, Lucide is a 2px stroked outline; at the same size a filled glyph beside a stroked one reads as two different weights — the same instability the 16-vs-24 grid fix removed. Choose a set per surface. Gestalt stays the product set because screens inline it at build time; reach for Lucide when the product set has no glyph for something. These render via CSS mask rather than inline SVG, so the grid costs ~4KB of markup instead of 680KB and each glyph still takes its colour from currentColor.

a-arrow-down
a-arrow-up
a-large-small
accessibility
activity
activity-square
ad
air-vent
airplay
alarm-check
alarm-clock
alarm-clock-check
alarm-clock-minus
alarm-clock-off
alarm-clock-plus
alarm-minus
alarm-plus
alarm-smoke
album
alert-circle
alert-octagon
alert-triangle
align-center
align-center-horizontal
align-center-vertical
align-end-horizontal
align-end-vertical
align-horizontal-distribute-center
align-horizontal-distribute-end
align-horizontal-distribute-start
align-horizontal-justify-center
align-horizontal-justify-end
align-horizontal-justify-start
align-horizontal-space-around
align-horizontal-space-between
align-justify
align-left
align-right
align-start-horizontal
align-start-vertical
align-vertical-distribute-center
align-vertical-distribute-end
align-vertical-distribute-start
align-vertical-justify-center
align-vertical-justify-end
align-vertical-justify-start
align-vertical-space-around
align-vertical-space-between
ambulance
ampersand
ampersands
amphora
anchor
angry
annoyed
antenna
anvil
aperture
app-window
app-window-mac
apple
archive
archive-restore
archive-x
area-chart
armchair
arrow-big-down
arrow-big-down-dash
arrow-big-left
arrow-big-left-dash
arrow-big-right
arrow-big-right-dash
arrow-big-up
arrow-big-up-dash
arrow-down
arrow-down-0-1
arrow-down-01
arrow-down-1-0
arrow-down-10
arrow-down-a-z
arrow-down-az
arrow-down-circle
arrow-down-from-line
arrow-down-left
arrow-down-left-from-circle
arrow-down-left-from-square
arrow-down-left-square
arrow-down-narrow-wide
arrow-down-right
arrow-down-right-from-circle
arrow-down-right-from-square
arrow-down-right-square
arrow-down-square
arrow-down-to-dot
arrow-down-to-line
arrow-down-up
arrow-down-wide-narrow
arrow-down-z-a
arrow-down-za
arrow-left
arrow-left-circle
arrow-left-from-line
arrow-left-right
arrow-left-square
arrow-left-to-line
arrow-right
arrow-right-circle
arrow-right-from-line
arrow-right-left
arrow-right-square
arrow-right-to-line
arrow-up
arrow-up-0-1
arrow-up-01
arrow-up-1-0
arrow-up-10
arrow-up-a-z
arrow-up-az
arrow-up-circle
arrow-up-down
arrow-up-from-dot
arrow-up-from-line
arrow-up-left
arrow-up-left-from-circle
arrow-up-left-from-square
arrow-up-left-square
arrow-up-narrow-wide
arrow-up-right
arrow-up-right-from-circle
arrow-up-right-from-square
arrow-up-right-square
arrow-up-square
arrow-up-to-line
arrow-up-wide-narrow
arrow-up-z-a
arrow-up-za
arrows-up-from-line
asterisk
asterisk-square
astroid
at-sign
atom
audio-lines
audio-waveform
award
axe
axis-3-d
axis-3d
baby
backpack
badge
badge-alert
badge-cent
badge-check
badge-dollar-sign
badge-euro
badge-help
badge-indian-rupee
badge-info
badge-japanese-yen
badge-minus
badge-percent
badge-plus
badge-pound-sterling
badge-question-mark
badge-russian-ruble
badge-swiss-franc
badge-turkish-lira
badge-x
baggage-claim
balloon
ban
banana
bandage
banknote
banknote-arrow-down
banknote-arrow-up
banknote-check
banknote-x
bar-chart
bar-chart-2
bar-chart-3
bar-chart-4
bar-chart-big
bar-chart-horizontal
bar-chart-horizontal-big
barcode
barrel
baseline
bath
battery
battery-charging
battery-full
battery-low
battery-medium
battery-plus
battery-warning
beaker
bean
bean-off
bed
bed-double
bed-single
beef
beef-off
beer
beer-off
bell
bell-check
bell-dot
bell-electric
bell-minus
bell-off
bell-plus
bell-ring
between-horizonal-end
between-horizonal-start
between-horizontal-end
between-horizontal-start
between-vertical-end
between-vertical-start
biceps-flexed
bike
binary
binoculars
biohazard
bird
birdhouse
bitcoin
blend
blender
blinds
blocks
bluetooth
bluetooth-connected
bluetooth-off
bluetooth-searching
bold
bolt
bomb
bone
bone-fracture
book
book-a
book-alert
book-audio
book-check
book-copy
book-dashed
book-down
book-headphones
book-heart
book-image
book-key
book-lock
book-marked
book-minus
book-open
book-open-check
book-open-text
book-plus
book-search
book-template
book-text
book-type
book-up
book-up-2
book-user
book-x
bookmark
bookmark-check
bookmark-minus
bookmark-off
bookmark-plus
bookmark-x
boom-box
bot
bot-message-square
bot-off
bottle-wine
bow-arrow
box
box-select
boxes
braces
brackets
brain
brain-circuit
brain-cog
brick-wall
brick-wall-fire
brick-wall-shield
briefcase
briefcase-business
briefcase-conveyor-belt
briefcase-medical
bring-to-front
broccoli
brush
brush-cleaning
bubbles
bug
bug-off
bug-play
building
building-2
bus
bus-front
cable
cable-car
cake
cake-slice
calculator
calendar
calendar-1
calendar-arrow-down
calendar-arrow-up
calendar-check
calendar-check-2
calendar-clock
calendar-cog
calendar-days
calendar-fold
calendar-heart
calendar-minus
calendar-minus-2
calendar-off
calendar-plus
calendar-plus-2
calendar-range
calendar-search
calendar-sync
calendar-x
calendar-x-2
calendars
camera
camera-off
candlestick-chart
candy
candy-cane
candy-off
cannabis
cannabis-off
captions
captions-off
car
car-front
car-taxi-front
caravan
card-sim
carrot
case-lower
case-sensitive
case-upper
cassette-tape
cast
castle
cat
cctv
cctv-off
chart-area
chart-bar
chart-bar-big
chart-bar-decreasing
chart-bar-increasing
chart-bar-stacked
chart-candlestick
chart-column
chart-column-big
chart-column-decreasing
chart-column-increasing
chart-column-stacked
chart-gantt
chart-line
chart-network
chart-no-axes-column
chart-no-axes-column-decreasing
chart-no-axes-column-increasing
chart-no-axes-combined
chart-no-axes-gantt
chart-pie
chart-scatter
chart-spline
check
check-check
check-circle
check-circle-2
check-line
check-square
check-square-2
chef-hat
cherry
chess-bishop
chess-king
chess-knight
chess-pawn
chess-queen
chess-rook
chevron-down
chevron-down-circle
chevron-down-square
chevron-first
chevron-last
chevron-left
chevron-left-circle
chevron-left-square
chevron-right
chevron-right-circle
chevron-right-square
chevron-up
chevron-up-circle
chevron-up-square
chevrons-down
chevrons-down-up
chevrons-left
chevrons-left-right
chevrons-left-right-ellipsis
chevrons-right
chevrons-right-left
chevrons-up
chevrons-up-down
church
cigarette
cigarette-off
circle
circle-alert
circle-arrow-down
circle-arrow-left
circle-arrow-out-down-left
circle-arrow-out-down-right
circle-arrow-out-up-left
circle-arrow-out-up-right
circle-arrow-right
circle-arrow-up
circle-check
circle-check-big
circle-chevron-down
circle-chevron-left
circle-chevron-right
circle-chevron-up
circle-dashed
circle-divide
circle-dollar-sign
circle-dot
circle-dot-dashed
circle-ellipsis
circle-equal
circle-euro
circle-fading-arrow-up
circle-fading-plus
circle-gauge
circle-help
circle-minus
circle-off
circle-parking
circle-parking-off
circle-pause
circle-percent
circle-pile
circle-play
circle-plus
circle-pound-sterling
circle-power
circle-question-mark
circle-slash
circle-slash-2
circle-slashed
circle-small
circle-star
circle-stop
circle-user
circle-user-round
circle-x
circuit-board
citrus
clapperboard
clipboard
clipboard-check
clipboard-clock
clipboard-copy
clipboard-edit
clipboard-list
clipboard-minus
clipboard-paste
clipboard-pen
clipboard-pen-line
clipboard-plus
clipboard-signature
clipboard-type
clipboard-x
clock
clock-1
clock-10
clock-11
clock-12
clock-2
clock-3
clock-4
clock-5
clock-6
clock-7
clock-8
clock-9
clock-alert
clock-arrow-down
clock-arrow-left
clock-arrow-right
clock-arrow-up
clock-check
clock-fading
clock-plus
closed-caption
cloud
cloud-alert
cloud-backup
cloud-check
cloud-cog
cloud-download
cloud-drizzle
cloud-fog
cloud-hail
cloud-lightning
cloud-moon
cloud-moon-rain
cloud-off
cloud-rain
cloud-rain-wind
cloud-snow
cloud-sun
cloud-sun-rain
cloud-sync
cloud-upload
cloudy
clover
club
code
code-2
code-square
code-xml
coffee
cog
coins
columns
columns-2
columns-3
columns-3-cog
columns-4
columns-settings
combine
command
compass
component
computer
concierge-bell
cone
construction
contact
contact-2
contact-round
container
contrast
cookie
cooking-pot
copy
copy-check
copy-minus
copy-plus
copy-slash
copy-x
copyleft
copyright
corner-down-left
corner-down-right
corner-left-down
corner-left-up
corner-right-down
corner-right-up
corner-up-left
corner-up-right
cpu
creative-commons
credit-card
croissant
crop
cross
crosshair
crown
cuboid
cup-soda
curly-braces
currency
cylinder
dam
database
database-arrow-down
database-arrow-up
database-backup
database-check
database-minus
database-plus
database-search
database-x
database-zap
decimals-arrow-left
decimals-arrow-right
delete
dessert
diameter
diamond
diamond-minus
diamond-percent
diamond-plus
dice-1
dice-2
dice-3
dice-4
dice-5
dice-6
dices
diff
disc
disc-2
disc-3
disc-album
divide
divide-circle
divide-square
dna
dna-off
dock
dog
dollar-sign
donut
door-closed
door-closed-locked
door-open
dot
dot-square
download
download-cloud
drafting-compass
drama
drill
drone
droplet
droplet-off
droplets
drum
drumstick
dumbbell
ear
ear-off
earth
earth-lock
eclipse
edit
edit-2
edit-3
egg
egg-fried
egg-off
ellipse
ellipsis
ellipsis-vertical
equal
equal-approximately
equal-not
equal-square
eraser
ethernet-port
euro
ev-charger
expand
external-link
eye
eye-closed
eye-dashed
eye-off
factory
fan
fast-forward
feather
fence
ferris-wheel
file
file-archive
file-audio
file-audio-2
file-axis-3-d
file-axis-3d
file-badge
file-badge-2
file-bar-chart
file-bar-chart-2
file-box
file-braces
file-braces-corner
file-chart-column
file-chart-column-increasing
file-chart-line
file-chart-pie
file-check
file-check-2
file-check-corner
file-clock
file-code
file-code-2
file-code-corner
file-cog
file-cog-2
file-diff
file-digit
file-down
file-edit
file-exclamation-point
file-headphone
file-heart
file-image
file-input
file-json
file-json-2
file-key
file-key-2
file-line-chart
file-lock
file-lock-2
file-minus
file-minus-2
file-minus-corner
file-music
file-output
file-pen
file-pen-line
file-pie-chart
file-play
file-plus
file-plus-2
file-plus-corner
file-question
file-question-mark
file-scan
file-search
file-search-2
file-search-corner
file-signal
file-signature
file-sliders
file-spreadsheet
file-stack
file-symlink
file-terminal
file-text
file-type
file-type-2
file-type-corner
file-up
file-user
file-video
file-video-2
file-video-camera
file-volume
file-volume-2
file-warning
file-x
file-x-2
file-x-corner
files
film
filter
filter-x
fingerprint-pattern
fire-extinguisher
fish
fish-off
fish-symbol
fishing-hook
fishing-rod
flag
flag-off
flag-triangle-left
flag-triangle-right
flame
flame-kindling
flashlight
flashlight-off
flask-conical
flask-conical-off
flask-round
flip-horizontal
flip-horizontal-2
flip-vertical
flip-vertical-2
flower
flower-2
focus
fold-horizontal
fold-vertical
folder
folder-archive
folder-bookmark
folder-check
folder-clock
folder-closed
folder-code
folder-cog
folder-cog-2
folder-dot
folder-down
folder-edit
folder-git
folder-git-2
folder-heart
folder-input
folder-kanban
folder-key
folder-lock
folder-minus
folder-open
folder-open-dot
folder-output
folder-pen
folder-plus
folder-root
folder-search
folder-search-2
folder-symlink
folder-sync
folder-tree
folder-up
folder-x
folders
footprints
fork-knife
fork-knife-crossed
forklift
form
form-input
forward
frame
frown
fuel
fullscreen
function-square
funnel
funnel-plus
funnel-x
gallery-horizontal
gallery-horizontal-end
gallery-thumbnails
gallery-vertical
gallery-vertical-end
gamepad
gamepad-2
gamepad-directional
gantt-chart
gantt-chart-square
gauge
gauge-circle
gavel
gem
georgian-lari
ghost
gift
git-branch
git-branch-minus
git-branch-plus
git-commit
git-commit-horizontal
git-commit-vertical
git-compare
git-compare-arrows
git-fork
git-graph
git-merge
git-merge-conflict
git-pull-request
git-pull-request-arrow
git-pull-request-closed
git-pull-request-create
git-pull-request-create-arrow
git-pull-request-draft
glass-water
glasses
globe
globe-2
globe-check
globe-lock
globe-off
globe-x
goal
gpu
grab
graduation-cap
grape
grid
grid-2-x-2
grid-2-x-2-check
grid-2-x-2-plus
grid-2-x-2-x
grid-2x2
grid-2x2-check
grid-2x2-plus
grid-2x2-x
grid-3-x-3
grid-3x2
grid-3x3
grip
grip-horizontal
grip-vertical
group
guitar
ham
hamburger
hammer
hand
hand-coins
hand-fist
hand-grab
hand-heart
hand-helping
hand-metal
hand-platter
handbag
handshake
hard-drive
hard-drive-download
hard-drive-upload
hard-hat
hash
hat-glasses
haze
hd
hdmi-port
heading
heading-1
heading-2
heading-3
heading-4
heading-5
heading-6
headphone-off
headphones
headset
heart
heart-crack
heart-handshake
heart-minus
heart-off
heart-plus
heart-pulse
heart-x
heater
helicopter
help-circle
helping-hand
hexagon
highlighter
history
home
hop
hop-off
hospital
hotel
hourglass
house
house-heart
house-plug
house-plus
house-wifi
ice-cream
ice-cream-2
ice-cream-bowl
ice-cream-cone
id-card
id-card-lanyard
image
image-down
image-minus
image-off
image-play
image-plus
image-up
image-upscale
images
import
inbox
indent
indent-decrease
indent-increase
indian-rupee
infinity
info
inspect
inspection-panel
italic
iteration-ccw
iteration-cw
japanese-yen
joystick
kanban
kanban-square
kanban-square-dashed
kayak
key
key-round
key-square
keyboard
keyboard-music
keyboard-off
lamp
lamp-ceiling
lamp-desk
lamp-floor
lamp-wall-down
lamp-wall-up
land-plot
landmark
languages
laptop
laptop-2
laptop-minimal
laptop-minimal-check
lasso
lasso-select
laugh
layers
layers-2
layers-3
layers-minus
layers-plus
layout
layout-dashboard
layout-freeform
layout-grid
layout-list
layout-panel-left
layout-panel-top
layout-template
leaf
leafy-green
lectern
lens-concave
lens-convex
letter-text
library
library-big
library-square
life-buoy
ligature
lightbulb
lightbulb-off
line-chart
line-dot-right-horizontal
line-squiggle
line-style
link
link-2
link-2-off
list
list-check
list-checks
list-chevrons-down-up
list-chevrons-up-down
list-collapse
list-end
list-filter
list-filter-plus
list-indent-decrease
list-indent-increase
list-minus
list-music
list-ordered
list-plus
list-restart
list-sort-ascending
list-sort-descending
list-start
list-todo
list-tree
list-video
list-x
loader
loader-2
loader-circle
loader-pinwheel
locate
locate-fixed
locate-off
location-edit
lock
lock-keyhole
lock-keyhole-open
lock-open
log-in
log-out
logs
lollipop
luggage
m-square
magnet
mail
mail-check
mail-minus
mail-open
mail-plus
mail-question
mail-question-mark
mail-search
mail-warning
mail-x
mailbox
mails
map
map-minus
map-pin
map-pin-check
map-pin-check-inside
map-pin-house
map-pin-minus
map-pin-minus-inside
map-pin-off
map-pin-pen
map-pin-plus
map-pin-plus-inside
map-pin-search
map-pin-x
map-pin-x-inside
map-pinned
map-plus
mars
mars-stroke
martini
maximize
maximize-2
medal
megaphone
megaphone-off
meh
memory-stick
menu
menu-square
merge
message-circle
message-circle-check
message-circle-code
message-circle-dashed
message-circle-heart
message-circle-more
message-circle-off
message-circle-plus
message-circle-question
message-circle-question-mark
message-circle-reply
message-circle-warning
message-circle-x
message-square
message-square-check
message-square-code
message-square-dashed
message-square-diff
message-square-dot
message-square-heart
message-square-lock
message-square-more
message-square-off
message-square-plus
message-square-quote
message-square-reply
message-square-share
message-square-text
message-square-warning
message-square-x
messages-square
metronome
mic
mic-2
mic-audio-lines
mic-off
mic-signal
mic-vocal
microchip
microscope
microwave
milestone
milk
milk-off
minimize
minimize-2
minus
minus-circle
minus-square
mirror-rectangular
mirror-round
monitor
monitor-check
monitor-cloud
monitor-cog
monitor-dot
monitor-down
monitor-off
monitor-pause
monitor-play
monitor-smartphone
monitor-speaker
monitor-stop
monitor-up
monitor-x
moon
moon-star
more-horizontal
more-vertical
mosque
motorbike
mountain
mountain-snow
mouse
mouse-left
mouse-off
mouse-pointer
mouse-pointer-2
mouse-pointer-2-off
mouse-pointer-ban
mouse-pointer-click
mouse-pointer-square-dashed
mouse-right
move
move-3-d
move-3d
move-diagonal
move-diagonal-2
move-down
move-down-left
move-down-right
move-horizontal
move-left
move-right
move-up
move-up-left
move-up-right
move-vertical
music
music-2
music-3
music-4
navigation
navigation-2
navigation-2-off
navigation-off
network
newspaper
nfc
non-binary
notebook
notebook-pen
notebook-tabs
notebook-text
notepad-text
notepad-text-dashed
nut
nut-off
octagon
octagon-alert
octagon-minus
octagon-pause
octagon-x
omega
option
orbit
origami
outdent
package
package-2
package-check
package-minus
package-open
package-plus
package-search
package-x
paint-bucket
paint-roller
paintbrush
paintbrush-2
paintbrush-vertical
palette
palmtree
panda
panel-bottom
panel-bottom-close
panel-bottom-dashed
panel-bottom-inactive
panel-bottom-open
panel-left
panel-left-close
panel-left-dashed
panel-left-inactive
panel-left-open
panel-left-right-dashed
panel-right
panel-right-close
panel-right-dashed
panel-right-inactive
panel-right-open
panel-top
panel-top-bottom-dashed
panel-top-close
panel-top-dashed
panel-top-inactive
panel-top-open
panels-left-bottom
panels-left-right
panels-right-bottom
panels-top-bottom
panels-top-left
paper-bag
paperclip
parasol
parentheses
parking-circle
parking-circle-off
parking-meter
parking-square
parking-square-off
party-popper
pause
pause-circle
pause-octagon
paw-print
pc-case
pen
pen-box
pen-line
pen-off
pen-square
pen-tool
pencil
pencil-line
pencil-off
pencil-ruler
pencil-sparkles
pentagon
percent
percent-circle
percent-diamond
percent-square
person-standing
phi
philippine-peso
phone
phone-call
phone-forwarded
phone-incoming
phone-missed
phone-off
phone-outgoing
pi
pi-square
piano
pickaxe
picture-in-picture
picture-in-picture-2
pie-chart
piggy-bank
pilcrow
pilcrow-left
pilcrow-right
pilcrow-square
pill
pill-bottle
pin
pin-off
pipette
pizza
plane
plane-landing
plane-takeoff
play
play-circle
play-off
play-square
plug
plug-2
plug-zap
plug-zap-2
plus
plus-circle
plus-square
pocket-knife
podcast
podium
pointer
pointer-off
popcorn
popsicle
pound-sterling
power
power-circle
power-off
power-square
presentation
printer
printer-check
printer-x
projector
proportions
puzzle
pyramid
qr-code
quote
rabbit
radar
radiation
radical
radio
radio-off
radio-receiver
radio-tower
radius
rainbow
rat
ratio
receipt
receipt-cent
receipt-euro
receipt-indian-rupee
receipt-japanese-yen
receipt-pound-sterling
receipt-russian-ruble
receipt-swiss-franc
receipt-text
receipt-turkish-lira
rectangle-circle
rectangle-ellipsis
rectangle-goggles
rectangle-horizontal
rectangle-vertical
recycle
redo
redo-2
redo-dot
refresh-ccw
refresh-ccw-dot
refresh-cw
refresh-cw-off
refrigerator
regex
remove-formatting
repeat
repeat-1
repeat-2
repeat-off
replace
replace-all
reply
reply-all
rewind
ribbon
road
rocket
rocking-chair
roller-coaster
rose
rotate-3-d
rotate-3d
rotate-ccw
rotate-ccw-clock
rotate-ccw-key
rotate-ccw-square
rotate-cw
rotate-cw-fading-clock
rotate-cw-square
route
route-off
router
rows
rows-2
rows-3
rows-4
rss
ruler
ruler-dimension-line
russian-ruble
sailboat
salad
sandwich
satellite
satellite-dish
saudi-riyal
save
save-all
save-check
save-off
save-pen
save-plus
scale
scale-3-d
scale-3d
scaling
scan
scan-barcode
scan-box
scan-eye
scan-face
scan-heart
scan-line
scan-qr-code
scan-search
scan-square
scan-text
scatter-chart
school
school-2
scissors
scissors-line-dashed
scissors-square
scissors-square-dashed-bottom
scooter
screen-share
screen-share-off
scroll
scroll-text
search
search-alert
search-check
search-code
search-slash
search-x
section
send
send-horizonal
send-horizontal
send-to-back
separator-horizontal
separator-vertical
server
server-cog
server-crash
server-off
server-plus
settings
settings-2
shapes
share
share-2
sheet
shell
shelving-unit
shield
shield-alert
shield-ban
shield-check
shield-close
shield-cog
shield-cog-corner
shield-ellipsis
shield-half
shield-keyhole
shield-minus
shield-off
shield-plus
shield-question
shield-question-mark
shield-user
shield-x
ship
ship-wheel
shirt
shopping-bag
shopping-basket
shopping-cart
shovel
shower-head
shredder
shrimp
shrink
shrub
shuffle
sidebar
sidebar-close
sidebar-open
sigma
sigma-square
signal
signal-high
signal-low
signal-medium
signal-zero
signature
signpost
signpost-big
siren
skip-back
skip-forward
skull
slash
slash-square
slice
sliders
sliders-horizontal
sliders-vertical
smartphone
smartphone-charging
smartphone-nfc
smile
smile-plus
snail
snowflake
soap-dispenser-droplet
sofa
solar-panel
sort-asc
sort-desc
soup
space
spade
sparkle
sparkles
speaker
speech
spell-check
spell-check-2
spline
spline-pointer
split
split-square-horizontal
split-square-vertical
spool
sport-shoe
spotlight
spray-can
sprout
square
square-activity
square-arrow-down
square-arrow-down-left
square-arrow-down-right
square-arrow-left
square-arrow-out-down-left
square-arrow-out-down-right
square-arrow-out-up-left
square-arrow-out-up-right
square-arrow-right
square-arrow-right-enter
square-arrow-right-exit
square-arrow-up
square-arrow-up-left
square-arrow-up-right
square-asterisk
square-bottom-dashed-scissors
square-centerline-dashed-horizontal
square-centerline-dashed-vertical
square-chart-gantt
square-check
square-check-big
square-chevron-down
square-chevron-left
square-chevron-right
square-chevron-up
square-code
square-dashed
square-dashed-bottom
square-dashed-bottom-code
square-dashed-kanban
square-dashed-mouse-pointer
square-dashed-text
square-dashed-top-solid
square-divide
square-dot
square-equal
square-function
square-gantt-chart
square-kanban
square-library
square-m
square-menu
square-minus
square-mouse-pointer
square-off
square-parking
square-parking-off
square-pause
square-pen
square-percent
square-pi
square-pilcrow
square-play
square-plus
square-power
square-radical
square-round-corner
square-scissors
square-sigma
square-slash
square-split-horizontal
square-split-vertical
square-square
square-stack
square-star
square-stop
square-terminal
square-user
square-user-round
square-x
squares-exclude
squares-intersect
squares-subtract
squares-unite
squircle
squircle-dashed
squirrel
stamp
star
star-check
star-half
star-minus
star-off
star-plus
star-x
stars
step-back
step-forward
stethoscope
sticker
sticky-note
sticky-note-check
sticky-note-minus
sticky-note-off
sticky-note-plus
sticky-note-x
sticky-notes
stone
stop-circle
store
stretch-horizontal
stretch-vertical
strikethrough
subscript
subtitles
summary
sun
sun-dim
sun-medium
sun-moon
sun-snow
sunrise
sunset
superscript
swatch-book
swiss-franc
switch-camera
sword
swords
syringe
table
table-2
table-cells-merge
table-cells-split
table-columns-split
table-config
table-of-contents
table-properties
table-rows-split
tablet
tablet-smartphone
tablets
tag
tag-plus
tag-x
tags
tally-1
tally-2
tally-3
tally-4
tally-5
tangent
target
telescope
tent
tent-tree
terminal
terminal-square
test-tube
test-tube-2
test-tube-diagonal
test-tubes
text
text-align-center
text-align-end
text-align-justify
text-align-start
text-cursor
text-cursor-input
text-initial
text-quote
text-search
text-select
text-selection
text-wrap
theater
thermometer
thermometer-snowflake
thermometer-sun
thumbs-down
thumbs-up
ticket
ticket-check
ticket-minus
ticket-percent
ticket-plus
ticket-slash
ticket-x
tickets
tickets-plane
timeline
timer
timer-off
timer-reset
toggle-left
toggle-right
toilet
tool-case
toolbox
tornado
torus
touchpad
touchpad-off
towel-rack
tower-control
toy-brick
tractor
traffic-cone
train
train-front
train-front-tunnel
train-track
tram-front
transgender
trash
trash-2
tree-deciduous
tree-palm
tree-pine
trees
trending-down
trending-up
trending-up-down
triangle
triangle-alert
triangle-dashed
triangle-right
trophy
truck
truck-electric
turkish-lira
turntable
turtle
tv
tv-2
tv-minimal
tv-minimal-play
type
type-outline
umbrella
umbrella-off
underline
undo
undo-2
undo-dot
unfold-horizontal
unfold-vertical
ungroup
university
unlink
unlink-2
unlock
unlock-keyhole
unplug
upload
upload-cloud
usb
user
user-2
user-check
user-check-2
user-circle
user-circle-2
user-cog
user-cog-2
user-key
user-lock
user-minus
user-minus-2
user-pen
user-plus
user-plus-2
user-round
user-round-arrow-left
user-round-check
user-round-cog
user-round-key
user-round-minus
user-round-pen
user-round-plus
user-round-search
user-round-x
user-search
user-shield
user-square
user-square-2
user-star
user-x
user-x-2
users
users-2
users-round
utensils
utensils-crossed
utility-pole
van
variable
vault
vector-square
vegan
venetian-mask
venus
venus-and-mars
verified
vibrate
vibrate-off
video
video-off
videotape
view
voicemail
volleyball
volume
volume-1
volume-2
volume-off
volume-x
vote
wallet
wallet-2
wallet-cards
wallet-minimal
wallpaper
wand
wand-2
wand-sparkles
warehouse
washing-machine
watch
waves
waves-arrow-down
waves-arrow-up
waves-horizontal
waves-ladder
waves-vertical
waypoints
webcam
webcam-off
webhook
webhook-off
weight
weight-tilde
wheat
wheat-off
whole-word
wifi
wifi-cog
wifi-high
wifi-low
wifi-off
wifi-pen
wifi-sync
wifi-zero
wind
wind-arrow-down
wine
wine-off
workflow
worm
wrap-text
wrench
wrench-off
x
x-circle
x-line-top
x-octagon
x-square
zap
zap-off
zodiac-aquarius
zodiac-aries
zodiac-cancer
zodiac-capricorn
zodiac-gemini
zodiac-leo
zodiac-libra
zodiac-ophiuchus
zodiac-pisces
zodiac-sagittarius
zodiac-scorpio
zodiac-taurus
zodiac-virgo
zoom-in
zoom-out

Taxonomy · 18

The product vocabulary — 89 values across 18 categories, generated from Master_Data_Seed_Values.md, which is canonical and Firestore-backed. These are the words the UI is allowed to use.

vocal_range

Singer module (Talent profile)
SopranoMezzo-SopranoAltoTenorBaritoneBass

daw_tools

Engineer module (Talent profile)
Logic ProPro ToolsAbleton LiveFL StudioCubaseStudio OneReaper

session_types

Studio Booking "Configure Session" screen
RecordingMixingMasteringPodcastJam Session

session_duration_tiers

Studio Booking "Configure Session" screen
HourlyHalf DayFull Day

studio_services

Studio Discovery filter chips
RecordingMixingMastering

singing_styles

Singer role profile
PlaybackClassicalGhazalSufiIndiePopRockRapBhajan

lyricist_specializations

Lyricist role profile
RomanticCommercialDevotionalRapFilm SongsIndependent Music

director_specializations

Music Director role profile
Film MusicOTTAdvertisingIndependent

composition_styles

Composer role profile
OrchestralElectronicBackground ScoreCommercial JinglesFilm Score

engineer_specialties

Sound Engineer role profile
RecordingMixingMasteringLive Sound

dj_types

DJ role profile
ClubWeddingRadioFestivalBollywood

verification_id_type

Verification Queue
Government ID (Aadhaar)PassportDriving LicenseCompany PAN / GSTIN

availability_status

Talent availability
Available NowOpen for GigsBooked SoonOn TourUnavailable

podcast_categories

Podcaster role profile
MusicInterviewComedyCultureBusinessEducation

marketplace_categories

Gear SaleGear RentalBeats LicensingStemsMixing & MasteringCreative Services

equipment_categories

MicrophonesAudio InterfacesStudio MonitorsMixersPreampsHeadphonesControllers

budget_type

₹ (Budget)₹₹ (Mid-range)₹₹₹ (Premium)

opportunity_types

₹₹₹ (Premium)

Gaps

Computed from the repo, not listed by hand. The old registry was hand-maintained and went stale; this one cannot.

Widgets named but not built · 0 of 27

Named in Widget_Directory.md with no matching component in the system.

Screens not yet on the system · 0

Still carrying local <style> blocks or pre-system markup. 205 of 205 screens are rebuilt.

Built but never recycled · 54 of 137

Documented here, used by no screen. Not a rendering fault — this is the recycling backlog, and it is the number that should fall as flows are rebuilt. Each component page states its own count.

States declared but not rendered · 0

Loading is declared by 4 screens and rendered by 26. A screen that promises a loading state and shows nothing is worse than one that never claimed it — the component state map above already predicts this by listing Loading as composed rather than owned, and almost nothing composes it.

Live data the design layer cannot see · 3

Firestore collections with full admin CRUD and no counterpart in this catalogue. A screen author cannot tell which persona a screen serves or which module it belongs to, because neither is expressed anywhere in the design layer.

Missing hereExists as
Personas / rolesadmin route /role-profiles + Firestore collection
Platform modulesadmin route /modules + Firestore collection
Analyticsadmin route /analytics + Firestore collection

Coverage

4 sections exist in the CSS with no demo on this page. Listed rather than hidden:

Replaces /guide/styleguide (213 tokens) and /guide/musiclinkd-system (524 Gestalt tokens). Both 301-redirect here via firebase.json, verified live 2026-08-31. Generated by scripts/build-guide.mjs — do not hand-edit.