Nithya Suri · Product designer

Sheet A-01 / 04

Design systems

Michelangelo

Picasso keeps the skeleton. Michelangelo provides the skin.

Tellius had a working React component library and a product that looked like eleven different products. Michelangelo is a token layer that re-skins the whole surface without asking engineering to rewrite a single component.

Client
Tellius
Product
AI analytics: Vizpads, Kaiya chat, Missions
Year
2026
Scope
47 component sets · 52 primitives · 54 icons · 30 chart types
Role
Sole designer, token system and skin
Team
With the Picasso engineering team

Impact at a glance

semantic tokens, replacing direct palette references
116
stroke colours consolidated
226 → 3
inline styles removed
338
chart types restyled
30
The Kaiya chat home screen in the Michelangelo skin, with a serif heading, an Ask Kaiya anything composer, four mode chips and a row of sample prompt cards.

The situation

Tellius ships an analytics platform: dashboards its users call Vizpads, a chat assistant called Kaiya, and scheduled jobs called Missions. The React library behind it, Picasso, was healthy. The surface was not.

Screens built in different quarters had drifted apart. Stroke colour alone had sprawled to 226 distinct values, none of them named. A refresh was wanted. A rewrite was not on any roadmap.

From the docs

Picasso keeps the skeleton. Michelangelo provides the skin.

That sentence is the constraint. Michelangelo may change how a component looks. Never what it is, what it is called, or the props an engineer writes.

Before and after

Before · Kaiya as it ships

After · the same screen on Michelangelo

  1. The type changes. The heading takes the display serif; everything else moves onto the named text styles.
  2. The colour changes. Blue accent and unrelated icon tints become one primary role and a tinted set bound to the visualisation tokens.
  3. The rail collapses to icons, which is the only structural move in the frame, and it was made by the product team, not by the skin.
  4. Nothing else moves. Card size, gutter, corner radius, control height, pager placement and the button on the right are all untouched.
The same screen before and after. Everything the skin controls is unmoved: the composer band, the three by two card grid, the pager row and the Show Popular Queries button. The wider crop on the left is the old expanded rail, which the product team collapsed separately. Click either side for full size.

Only fonts and colour move

Type and colour were in scope. Geometry was not.

  • The button is the same button: 32px, same padding, same radius, four levels, five states, three sizes. Only what the states resolve to changed.
  • Disabled became a flat token instead of an opacity, because opacity fades an icon and its label by different amounts and the control looks broken.
  • Every change stayed reviewable. A colour move reads in a minute; a padding move is a layout change and an argument.
Four levels, five states, three sizes. Same geometry as the component engineering already ships. Only the fills and the label colour are rebound.
The grid both presets are held to. These numbers are the ones already in the product; the skin adopted them rather than proposing new ones.

The span ladder in one line: 888 heading, 736 assistant body, 584 user bubble, 432 chart card, 280 prompt card, 204 filter. Prose stops at ten of the twelve columns, so answer text never runs the full width.

Two collections, one direction of travel

Values flow one way. Primitives are hidden from publishing, the semantic collection aliases them, and components bind semantic tokens only. Never a primitive, never a raw hex.

Two collections and a styles layer. 52 primitives nobody can bind by accident, 116 semantic tokens that are the only collection designers pick from, and 33 styles so a whole treatment lands in one click.

Hiding the primitives is what makes the rest enforceable. A visible palette gets bound directly, by someone, in a hurry, and breaks silently when retuned. The 116 semantic tokens each name a job, so the picker teaches the rule.

The Tellius Vizpad list view showing a sortable table with name, business view, viz count, creation date and created by columns, a search field, and Create New Vizpad and Import Vizpad buttons.
Vizpad list view, running on the workspace grid. Every rule, fill and label in this frame resolves through a named token; the grid view is the same components re-flowed.

Colour, role by role

The roles, with the primitive each one points at printed underneath. The note on the board says it plainly: the hex under each name is the primitive it resolves to, not a value to type.

The board reads as the thought process:

  • Text has six steps because an analytics screen has six levels of voice, from a metric value down to a disabled hint.
  • Surface separates hover from selected. Pointed at and chosen are different statements; before this file they were the same grey.
  • Border is four roles, because 226 stroke values collapsed into hairline, divider and ink, plus focus.
  • The violet accent means interactive: six states of one hue, not six hues.
Status is a pale tint paired with a deep ink, never a saturated fill behind text. The pairing is the token, so nobody composes an unreadable badge by hand.

Data visualisation is its own colour system

An analytics product lives or dies on its charts, so the visualisation palette is its own token family, built to answer three different questions.

Three kinds of colour question, three kinds of ramp. Categorical for which series is which, sequential for how much, diverging for which side of the midpoint. Measures are named for meaning, so revenue is the same colour on every chart in the product.

Twelve categorical series in a fixed order, and the order is the spec: series five is the same hue on every chart ever drawn. Measures bind meaning, not position. Revenue owns a colour, so two charts about revenue agree.

Twelve of the thirty chart types, rebuilt on the visualisation tokens. Each card also names the situation it is for, which is the half of a chart library that usually goes undocumented.

The icon layer

Icons are where a system falls apart, because nobody audits them. The audit found 338 inline vector copies pasted across the file.

The production set: twenty nine glyphs that already existed as assets, pulled onto one grid and one stroke.
The gaps: twenty five glyphs that existed only as pasted vectors, redrawn as components. The note under the grid is the receipt: 338 inline copies replaced, 90 in the library and 248 on screens.

Stroke weight resolves to stroke/icon, the canvas to the size/icon scale. Colour may be overridden per instance. Weight may not. That is the entire policy.

The rules sheet: where icons come from, what they bind to, and which surfaces may use which glyphs.

Typography is two voices, not one font

Fraunces speaks, Geist operates, Geist Mono records. The board's own closing rule: apply a style, never type a size.

Who is allowed to talk like what:

  • Fraunces, the serif, is the product’s voice: greetings, insight questions, the sentences Kaiya writes.
  • Geist runs the working interface. Geist Mono carries data and identifiers.
  • Headings sit at Medium, and body reads through text/body rather than text/primary, because near-black at heavy weight is how dashboards shout.

A user can tell, before reading a word, whether the product is speaking, offering a control, or citing a value.

Designing the surface where the product reasons

Tellius is an analytics product whose main interface is a conversation, and a conversation with a model is a trust problem before it is a layout problem. Three decisions carry most of the weight.

The plan is shown before the answer. Kaiya posts its working plan as numbered steps that check off as they run. A reader who can see step three running trusts step five’s conclusion differently.

A Kaiya conversation where the question about prescription probability calibration has produced a five step plan: two SQL query steps, two Python analysis steps and a summary step, each with a completion tick, under a heading reading finalizing the response.
The plan, posted before the answer and checked off as it runs. The language rule on this surface: the status reads reasoning, never thinking, never loading.

The answer is typeset, not dumped. Headed sections, bold figures, every claim carrying its number, and the dashboards’ own charts rendered inline on the same tokens.

A finished Kaiya answer laid out with headed sections for overall calibration, geographic segments and specialty segments, bold figures for every statistic, and an inline bar chart of conversion rates by region arriving below the text.
The answer as a typeset page with its evidence inline. Every figure in the prose is bold, and the chart underneath is drawn on the same series tokens as every dashboard.

The voice is specified like a component. You and your, never we. Status reads reasoning, never thinking, never loading. A banned list keeps the marketing register out of an analyst’s tool. That restraint is a large part of why people trust the numbers.

The Kaiya home in Mission mode, asking what is your mission today, with the composer carrying a mission chip, mode chips for deep insight, mission, app and architect, sample prompts, and the day's briefings row below.
Mission mode, where a question becomes a standing job. The mode chips, the composer and the briefing cards are all library components, so an agent surface could ship on the normal release cadence.

What changed

52 primitives hidden from publishing. 116 semantic tokens in the one collection a designer sees, named for jobs. The foundations page keeps a live light and dark pair of the same card, so the mode override is proven on the sheet rather than promised.

The same card, both modes, one set of bindings. The pair lives on the foundations page as a standing proof, not as a promise in the documentation.

Stroke was the clearest win: 226 values collapsed to hairline, divider and ink, and all 338 inline styles were replaced with bound variables. Without that, the mode switch would not have been possible.

Two grids govern layout: a workspace preset for dense surfaces at 40px margins, and a conversation preset for Kaiya at an 888 measure.

A Kaiya home screen showing a Today's briefings row with three briefing summary cards, each with a coloured top rule, a title, body text, and an Investigate link.
Briefing cards in the running product. Status reads through the top rule and the label, not through a tinted card body.

The calls that could have gone another way

A system is decided in a handful of moments where more than one path was defensible. Three mattered here, with the options that lost kept on the sheet.

What I would do next

In order:

  • Measure adoption: library insertions and detach rates per component. A detach is feedback with coordinates.
  • Retire the 25 reconstructed icons as production assets land, so the gap ledger closes.
  • Open a contribution path, so a missing component becomes a proposal rather than a local copy.

How it stays alive with engineering

A token layer that only lives in Figma is a mood board. The contract has three parts:

  • The variable collection is the source. Every component set binds to it. A role changes in one place; nothing is corrected screen by screen.
  • Storybook is where we agree. A token change lands as a pull request and is reviewed against the stories, not a screenshot in a ticket.
  • A standing half hour, every week. Engineering brings what had no token, I bring what drifted. Most weeks it is a component using the wrong role.

One rule: I do not file a design bug without proposing the token that fixes it. A proposal is a thing an engineer can merge.

Where it stands

Foundations and Components are rebuilt, Vizpads run on the workspace grid, Kaiya on the conversation grid. Component sets expose variant properties only, which keeps the contract with engineering narrow.

One number is deliberately missing. The skin shipped in 2026 and the detach-rate baseline is still accruing, so there is no adoption figure yet. Quoting one this early would be decoration.

Revisions

Δ1
Foundations page rebuilt on a single variable collection.
Δ2
Component sets rebound from raw hex to semantic tokens.
Δ3
Stroke palette collapsed from 226 values to three roles.
Δ4
Chart styling moved onto viz tokens, six categorical and four measure roles.
Δ5
Kaiya chat surfaces added on the conversation grid.