Quiet Sky · foundations + application · v2.0

One system, every surface.

Tokens, type, space, elevation and motion — the layer every ai.com surface consumes. Marketing, product, docs, desktop and mobile, in light and dark, from one source.

1accent colour
2themes
4pxspace rhythm
1motion curve

The ai.com design system, extracted from the brand's two canonical artifacts — landing.html (v4 "quiet sky") and strategy-deck.html (identity slides) — and extended to cover the whole platform: product UI, marketing, docs, desktop and mobile, in light and dark.

This page is its own proof. Everything on it is built from the semantic tokens defined below — flip the theme toggle in the sidebar and the entire system re-renders. Components marked Canonical come directly from the source files; components marked Extended are new, derived strictly from the system's rules to cover product needs the marketing pages never had (forms, toasts, navigation shells, mobile).

Three small source discrepancies were resolved while extracting: night-muted standardized to #9DA1B2 (landing used #A7A9BC), danger on dark standardized to #FF7A87 (landing used #FF8A96), and glass opacity standardized to 0.72 (landing hero 0.55, deck 0.75). The mint "verified" green existed only as raw rgba values in landing.html — it is now a first-class token.
Foundations

Principles.

Quiet Sky in five rules. Everything else in this document is these rules applied at smaller scales.

#PrincipleWhat it means in practice
1One color carries the brandA single cyan accent with three readings — #0FA8CE as the color, #0B86A6 for small text and pressed states on light, #5FD4F2 lifted for the night. No gradients, anywhere. No second hue.
2The accent means somethingCyan appears only where it carries meaning: live dots, the agent's word, active states, checkpoints. Never in body text, never as decoration. Danger red appears only on Deny and Stop.
3Near-black night, soft glowDark surfaces are near-black (#0A0D12) with a faint cyan horizon and at most one slow aurora band. Texture you feel, not atmosphere that shouts. No violet, no neon-on-black.
4The dot is the materialThe dot in ai·com is the brand's particle: live pips, agent avatars, status dots, the page-scale dot lattice. Its glow (0 0 10px accent) marks anything alive right now.
5Trust is visible, not badgedEvery safety claim is a component you can watch: the checkpoint card, the verified-done strip, the Stop pill. No seals, no badge walls, no trust theater.

Always

  • Ink pills for primary actions on light; white pills on dark.
  • Soft geometry: pills at 99px, cards at 16–20px. No sharp corners.
  • Onest for everything — including numbers. Nothing is ever monospaced in product or marketing UI.
  • Layered, soft shadows; glass panels with gentle backdrop blur on dark.

Never

  • No gradients — anywhere. One color carries the brand.
  • No violet, no purple skies. Dusk-toned darks read entertainment, not work.
  • No neon-on-black. Dark zones glow softly; they never buzz.
  • No badge walls, seals, or trust theater. No accent color in body text.

Both lists verbatim from strategy-deck.html slide 11. Canonical

Color

A near-black night, one cyan accent.

Two palettes — day and night — that were born as the landing page's light and dark zones, formalized here as the platform's light and dark themes. Components never touch primitives; they consume the semantic layer, which is what makes theming a variable swap.

Primitives Canonical

The raw brand values. The first eight are the deck's own swatch row; the rest appear throughout landing.html and are codified here.

Canvas#FBFBFD
Surface#FFFFFF
Ink#0E0E14
Muted#5B5B66
Faint#8A8A94
Accent#0FA8CE
Accent deep#0B86A6
Accent night#5FD4F2
Night#0A0D12
Night 2#0D1117
Night 3#12161F
Night ink#EDEEF4
Night muted#9DA1B2
Night faint#7E8095
Danger#C24558
Danger night#FF7A87
Mint#2BD9A9
Mint deep#14795C
Mint night#8FE0C4

Mint is the "verified / live" green — it appears only on evidence of completed, verified work (done strips, live chips). It is never a general success color for UI chrome. Night 2 and Night 3 are the product dark-mode surface steps, derived from the landing's glass base rgb(13,17,23). Extended

Semantic tokens Extended

What components actually use. One name, two values — the theme decides which. This table is the heart of the system; the full copy-paste CSS lives in Tokens & implementation.

TokenLightDarkUse for
--bgCanvas #FBFBFDNight #0A0D12The page. Nothing else sits below it.
--surface-1#FFFFFF#0D1117Cards, frames, panels — anything raised off the page
--surface-2#F7F7FA#12161FNested wells inside cards: mocks, code wells, input strips
--surface-3#FDFDFE#0F131BBarely-raised rows, table headers
--text-1Ink #0E0E14Night ink #EDEEF4Headings, primary copy, values
--text-2Muted #5B5B66Night muted #9DA1B2Body copy, descriptions
--text-3Faint #8A8A94Night faint #7E8095Metadata, timestamps, decorative labels only
--borderink @ 8%night-ink @ 9%Hairlines, dividers, card edges
--border-strongink @ 14%night-ink @ 18%Ghost buttons, inputs, interactive edges
--fillink @ 4.5%night-ink @ 5%Chips, hovers, quiet fills
--accent#0FA8CE#5FD4F2Live dots, active states, meters, focus rings
--accent-text#0B86A6#5FD4F2Small/bold accent text — eyebrows, checkmarks, working labels
--accent-tint / --accent-borderaccent @ 8% / 30%accent-night @ 10% / 30%Checkpoint cards, agent-tinted fills, selected states
--danger#C24558#FF7A87Deny and Stop. Nothing else.
--ok / --ok-text#2BD9A9 / #14795C#2BD9A9 / #8FE0C4Verified done, live-now chips
--btn-primary-bg / -fgInk / whiteNight ink / nightThe primary pill — ink on light, white on dark, by brand rule
--bubble-agent#F4F4F8night-ink @ 7%Agent message bubbles
--glasswhite @ 78%rgb(13,17,23) @ 72%Floating nav, overlay panels — always with backdrop blur 8–14px

Rules of light Canonical

How color behaves

  • One accent, three readings — the theme picks the reading; components just say --accent.
  • Primary buttons are ink pills in light, white pills on dark. The accent is never a button fill.
  • Text never renders in raw accent on light — small accent text uses --accent-text (#0B86A6), which exists precisely for contrast.
  • Tints (8–10%) carry meaning-fills: checkpoints, agent bubbles, selection. Fills (--fill) are meaning-free.

Color anti-patterns

  • Accent as decoration, in body text, or as a background for large areas.
  • Danger anywhere except Deny / Stop / destructive confirmation.
  • Mint as a general success color — it marks verified outcomes only.
  • New hues. If a state needs a color, it maps to accent, danger, mint, or neutrals.
Typography

One family, soft geometry.

Onest is the only typeface, everywhere — display to caption, marketing to product, including every number. Nothing in the brand is ever monospaced (code samples in internal docs are the sole exception).

Aa
Onest — 400 / 500 / 600 / 700 / 800
RegularMediumSemiboldBoldExtrabold
DisplayEveryone gets an agent.
Title 1Trust is a visible mechanism.
Title 2Command Center, live
Title 3Approvals waiting on you
Body lgYour agent runs your inbox, your meetings, your morning brief.
Body / UISix drafts ready. I read 132 issues across the 6 projects.
SmallRoutine · invoice chaser · run 7 · waiting 12 min
CaptionUpdated 7:45 · checked independently by the verifier
EyebrowNeeds you
Micro labelAwaiting reply
StyleSizeWeightTrackingLine heightNotes
Display64px · clamp(46, 7vw, 80) hero700–800−0.035 to −0.04em1.02Marketing heroes, deck titles. Never inside product chrome.
Title 136–44px · clamp(30, 3.8vw, 40)600–700−0.025em1.08–1.12Section / page titles
Title 218–22px700−0.02em1.2Card and feature headings
Title 314.5–16px600–700−0.015em1.3Row titles, list headings
Body lg16–17px400–50001.6–1.65Marketing body, ledes
Body / UI13.5–14px400–50001.5–1.55Product default: bubbles, descriptions
Small12.5–13px400–60001.45–1.5Secondary rows, steps, provenance
Caption12px400–50001.4Timestamps, footnotes — --text-3
Eyebrow12px700+0.1em, uppercase1Section markers — --accent-text or --text-3
Micro label10–11px700–800+0.06–0.09em, uppercase1Chips, tags, panel titles. Decorative — never the only carrier of meaning.

Numbers and stats are set in Onest 600. Emphasis inside body copy is weight 600 in --text-1 — not italic, not accent color. On mobile, body/UI never drops below 13px and captions never below 11px.

Spacing & shape

A 4px rhythm and soft geometry.

Spacing steps on a 4px base. Radii come in six named stops — pills for anything interactive and small, soft rectangles for containers.

Spacing scale Extended

4
8
12
16
20
24
28
32
44
64
96

Usage anchors from the sources: gaps between cards 12–18 · card padding 24–28 · frame padding 18–20 · section padding 96 desktop / 80 tablet / 64 mobile · marketing container padding-inline 28.

Radius Canonical

--r-pill 99
--r-frame 20
--r-card 16
--r-inner 14
--r-ctrl 12
--r-tight 8

Pills for buttons, chips, and floating nav. Frames (chat windows, hero scenes) at 20–24. Cards at 16. Nested cards and callouts at 12–14. Controls (inputs) at 12. Tiny nested elements at 8. Message bubbles: 14 with a 4px "speaker corner" pointing at the sender. No sharp corners, anywhere.

Layout & breakpoints Extended

ContextSpecSource
Marketing containermax-width 1160 · padding-inline 28landing.html
Deck / doc contentmax-width 1000–1060strategy-deck, product-spec
App shell (desktop)rail 250–260 · main flexible (content max 980) · right panel 320 collapsibleproduct-spec app map
Breakpoints1024 tablet (rail collapses, grids halve) · 640 mobile (single column, bottom nav)standardized — deck's 1000/560 folds into these
Grid gaps18 between cards on desktop, 12–14 on mobilelanding bento / team grids
Touch targets≥ 44 × 44 px on mobile; inputs grow to 44px heightextended
Elevation & surfaces

Soft light, glass, and the night sky.

Depth comes from layered shadows and surface steps, not borders alone. Dark zones add glass and — in marketing only — the aurora.

LevelToken / recipeUse
Flat--bg, no shadowThe page itself
Raised--surface-1 + --shadow-soft + --borderCards, panels, rows
Floating--surface-1 + --shadow-cardFrames, modals, popovers, hero scenes
Glass--glass + backdrop-blur 8–14px + --border-strongFloating nav, overlay chrome, dark-zone cards
Hover lifttranslateY(-4px) + shadow-soft → shadow-card, 250msInteractive cards only — never rows or list items

The dusk treatment Canonical

Marketing dark zones (hero, finale, deck title slides) sit on the night with a faint cyan horizon rising from the bottom edge and one aurora band drifting on a 22–30s loop, blurred 70px. Optional film grain at 4% opacity. Product dark mode uses none of this — it is flat night surfaces; the glow belongs to the brand's front door, not to work.

The dusk recipe: radial cyan horizon at 14% from the bottom · linear cyan wash at 4.5% from the top · one aurora band, blur 70px, drifting 22s alternate. This band is the entire permitted atmosphere.

Motion

Calm, physical, brief.

One easing curve everywhere. Transform and opacity only — nothing animates layout. Ambient motion exists solely in marketing dark zones.

TokenValueUse
--easecubic-bezier(0.22, 1, 0.36, 1)Every transition and entrance. The only curve.
--t-fast · 200msbuttons, toggles, links, color shiftsMicro-interactions
--t-base · 250mscard hover lift, chipsComponent state
--t-slow · 300msnav, theme flip, panel slideChrome
--t-reveal · 500msfade + translateY(14–16px), stagger 90msScroll-in reveals, first paint

The named motions Canonical

pip-pulse · 2.4s working spin · 1s

pip-pulse marks anything live. bar-run (1.8s) is the agent working. spin is a short determinate wait. Ambient loops — orbit float 7s, aurora 22–30s, marquee 36s — are marketing-only. Every animation dies under prefers-reduced-motion; reveals render visible, spinners become static.

Components

The library.

Every component in both themes — the global toggle flips this whole page; the paired panels below pin one theme each so you can compare side by side. All of it consumes semantic tokens only.

Buttons Canonical

Primary is an ink pill on light and a white pill on dark — by rule, not preference. Ghost carries secondary actions; quiet is for tertiary; deny is text-only danger. Sizes: lg 15/13×26 (marketing CTAs), md 13/8×15 (product default), sm 12/6×12 (dense rows).

Light
Dark

Chips, labels & badges Canonical

Chips are quiet fills for neutral facts. Labels are micro-type pills that classify — solid for the highest rank, accent-tinted for meaningful states, outlined neutral for the rest. The glass badge carries a live pip in heroes and headers.

Light
13 Connectors4 of 5 seats
P0Needs youVerifiedAwaiting replyLiveStopped
Your agent is workingApprovals 3
Dark
13 Connectors4 of 5 seats
P0Needs youVerifiedAwaiting replyLiveStopped
Your agent is workingApprovals 3

The dot & avatars Canonical

People are photographs; agents are the dot. The agent avatar is a solid accent circle with a pulsing halo ring — one glance separates human from agent in any thread. Pips come in 6 / 7 / 8px; a glowing pip means live right now.

M J

Sizes: 40 (headers, member rows) · 26 (threads) · 20 (dense mocks). The pulse ring animates at 2.6s. In shared Rooms every agent message carries both the dot avatar and its owner's name — "mika · Maya's agent" — attribution is structural, not stylistic.

Messages & threads Canonical

The fused human + agent timeline. User bubbles are primary-colored pills with the speaker corner bottom-right; agent bubbles are quiet fills, corner top-left. Steps render inside agent bubbles with cyan checks. A working line always carries Stop.

agent #client-ops · Tue 8:42
Draft status updates for our 6 client projects from last week's Jira activity.
Agent
Six drafts ready. I read 132 issues and summarized what changed for each client.
Pulled last week's Jira activitySummarized per clientDrafted 6 updates in Gmail
working
agent #client-ops · Tue 8:42
Draft status updates for our 6 client projects from last week's Jira activity.
Agent
Six drafts ready. I read 132 issues and summarized what changed for each client.
Pulled last week's Jira activitySummarized per clientDrafted 6 updates in Gmail
working

The checkpoint card Canonical

The product's core interaction, identical anatomy everywhere: state line ("Needs you…"), the concrete action, provenance, and the three verbs. Accent tint + accent border — the only card that ships with meaning built into its fill. Deny is always text-only, always last.

Needs you — nothing sends until you approve
6 drafts ready to send via Gmail. From Routine · invoice chaser · run 7.
Needs you — nothing sends until you approve
6 drafts ready to send via Gmail. From Routine · invoice chaser · run 7.

Verified done Canonical

The only place mint appears: work confirmed by the independent verifier, with evidence. The check circle is mint, the claim is text-1, evidence is expandable.

Run 142 complete — 6 sent, verified
6 emails in Sent match approved drafts · recipients match contact list · no bounces after 15 min
Verified

Panels, rows & toggles Canonical

The panel is the product's list container: micro-label title, hairline-divided rows, metadata right-aligned in text-3. The toggle is 38×21 with the accent as its on-state.

Light
#client-updates · Permissions
Send external emailAlways pauses at a checkpoint first
External messagesOff in this Room
Meridian renewal — due todayDraft reply ready for review
7:45
Dark
#client-updates · Permissions
Send external emailAlways pauses at a checkpoint first
External messagesOff in this Room
Meridian renewal — due todayDraft reply ready for review
7:45

Forms Extended

The marketing pages have no inputs, so these are derived: surface-1 fields, 12px radius, strong border idle, accent border + 3px tint ring on focus. Labels 12.5/600; errors in danger with a plain sentence. 42px tall on desktop, 44px on mobile.

Light
Shown on invites and billing.
That doesn't look like a complete address.
Dark
Shown on invites and billing.
That doesn't look like a complete address.

Tables Canonical

Micro-label headers on surface-3, hairline rows, key column bold in text-1, everything else text-2. Wide tables scroll inside their container — the page never scrolls horizontally.

WhenAgentActionAuthorized by
Mon 8:24mika (Maya)Sent 6 emails · Gmail · run 142Maya · checkpoint 8:19
Mon 9:02juno (Jon)Logged 9 calls · SalesforceJon · always-allow #sales

Progress & meters Canonical

Meters are 7px pills — accent fill for budgets and usage, switching to danger only past a warning threshold. The indeterminate working bar belongs to the agent alone.

Usage this cycle62%
Goal budget91%

Toasts & empty states Extended

Toasts are floating frames with an intent pip — accent for information, mint only for verified outcomes, danger for failures. They enter with the reveal motion, bottom-right on desktop, above the tab bar on mobile. Empty states are one sentence plus one action — designed, never defaulted.

Brief readyYour morning brief is up to date as of 7:45.
6 sent, verifiedEvery send confirmed with evidence.
Run stoppedJon stopped juno in #shipping-week. State preserved.
Your brief starts with one connection.
Connect Gmail or Slack and the agent triages your morning by tomorrow.
Mobile

The same system at thumb scale.

Below 640px the rail becomes a five-slot tab bar, checkpoints become bottom sheets, and everything interactive grows to a 44px target. Nothing changes visual language.

Main surface
single column · cards full-width
section padding 64 → 20 inline
Brief Rooms Agent Approvals More
Thread behind the sheet dims to 40%
Needs you
6 drafts ready to send via Gmail. Nothing sends until you approve.
RuleSpec
Tab bar5 slots max · 56px + safe-area inset · labels 10px/600 · active = accent-text + tint. Approvals keeps its count badge.
Checkpoint sheetBottom sheet, radius 20 20 0 0, grabber 36×4. Verbs stack full-width if they don't fit in a row. Deny never collapses into a menu.
Touch≥44×44 targets · inputs 44px tall · row tap-areas full-bleed
TypeBody/UI floors at 13px, captions at 11px. Display scales via the clamp() ramps — no separate mobile scale.
ThreadsBubbles widen to 88% max-width · avatars drop to 20px · working line + Stop always visible, never behind a swipe
Grids4-col → 2-col at 1024 → 1-col at 640 (landing's own collapse pattern). Card gaps 18 → 12.
MotionAmbient marketing loops (orbit float, marquee) switch off below 1024 — the landing already does this; keep it platform law.
Accessibility

Contrast, focus, motion.

The palette's roles encode its contrast math. Approximate ratios below — re-verify when any value changes.

Pair≈ RatioVerdict
Ink on Canvas18 : 1AAA everywhere
Muted on Canvas6.5 : 1AA all sizes — the body-copy pair
Faint on Canvas3.3 : 1Fails AA for small text — decorative metadata only, never the sole carrier of meaning
Accent deep on white4.2 : 1700-weight labels and eyebrows only; body copy never renders in accent (brand rule)
Night ink on Night17 : 1AAA everywhere
Night muted on Night7 : 1AA all sizes
Accent night on Night11 : 1AA — why raw #0FA8CE (6.8:1, thin strokes) is lifted on dark

Non-negotiables

  • Focus is always visible: 2px --focus-ring outline, offset 2 — on every interactive element, both themes.
  • The three checkpoint verbs are keyboard-operable in DOM order: approve, review, deny. Pending checkpoints announce to assistive tech.
  • Live pips and working bars pair with text ("working…") — color and motion never carry state alone.
  • prefers-reduced-motion collapses every animation to ≤0.01ms; reveals render visible; ambient loops stop.
  • Both themes declare color-scheme so native controls, scrollbars, and form widgets match.

Practices

  • Icon-free design means labels do the work — keep them; never reduce a verb to a glyph.
  • Agent avatars carry aria-label naming the owner ("Maya's agent").
  • Hit areas ≥44px on touch; row taps cover the full row, not just the title.
  • Skip-link pattern from landing.html (sr-only, surfaces on focus) ships in every shell.
Implementation

Tokens, ready to ship.

Drop this in as tokens.css. Theming API: set data-theme="light|dark" on <html>; omit it and honor prefers-color-scheme with the tiny bootstrap below. Scoped theming (a pinned-dark hero inside a light page) is the same variables on a .theme-dark wrapper.

/* tokens.css — ai.com Quiet Sky v2.0 */ :root { /* primitives */ --white:#FFFFFF; --canvas-l:#FBFBFD; --ink:#0E0E14; --gray-muted:#5B5B66; --gray-faint:#8A8A94; --night:#0A0D12; --night-2:#0D1117; --night-3:#12161F; --night-ink:#EDEEF4; --night-muted:#9DA1B2; --night-faint:#7E8095; --cyan:#0FA8CE; --cyan-deep:#0B86A6; --cyan-night:#5FD4F2; --red:#C24558; --red-night:#FF7A87; --mint:#2BD9A9; --mint-deep:#14795C; --mint-night:#8FE0C4; /* shape */ --r-pill:99px; --r-frame:20px; --r-card:16px; --r-inner:14px; --r-ctrl:12px; --r-tight:8px; /* motion */ --ease:cubic-bezier(0.22,1,0.36,1); --t-fast:200ms; --t-base:250ms; --t-slow:300ms; --t-reveal:500ms; /* type */ --font:"Onest","Inter",system-ui,sans-serif; } :root[data-theme="light"], .theme-light { --bg:var(--canvas-l); --surface-1:var(--white); --surface-2:#F7F7FA; --surface-3:#FDFDFE; --text-1:var(--ink); --text-2:var(--gray-muted); --text-3:var(--gray-faint); --border:rgba(14,14,20,.08); --border-strong:rgba(14,14,20,.14); --fill:rgba(14,14,20,.045); --accent:var(--cyan); --accent-text:var(--cyan-deep); --accent-tint:rgba(15,168,206,.08); --accent-border:rgba(15,168,206,.30); --danger:var(--red); --ok:var(--mint); --ok-text:var(--mint-deep); --ok-tint:rgba(43,217,169,.10); --ok-border:rgba(43,217,169,.35); --btn-primary-bg:var(--ink); --btn-primary-fg:var(--white); --bubble-agent:#F4F4F8; --bubble-user-bg:var(--ink); --bubble-user-fg:var(--white); --glass:rgba(255,255,255,.78); --shadow-card:0 1px 2px rgba(14,14,20,.04), 0 24px 64px rgba(14,14,20,.12); --shadow-soft:0 1px 2px rgba(14,14,20,.04), 0 12px 32px rgba(14,14,20,.07); --focus-ring:var(--cyan); color-scheme: light; } :root[data-theme="dark"], .theme-dark { --bg:var(--night); --surface-1:var(--night-2); --surface-2:var(--night-3); --surface-3:#0F131B; --text-1:var(--night-ink); --text-2:var(--night-muted); --text-3:var(--night-faint); --border:rgba(237,238,244,.09); --border-strong:rgba(237,238,244,.18); --fill:rgba(237,238,244,.05); --accent:var(--cyan-night); --accent-text:var(--cyan-night); --accent-tint:rgba(95,212,242,.10); --accent-border:rgba(95,212,242,.30); --danger:var(--red-night); --ok:var(--mint); --ok-text:var(--mint-night); --ok-tint:rgba(43,217,169,.10); --ok-border:rgba(43,217,169,.30); --btn-primary-bg:var(--night-ink); --btn-primary-fg:var(--night); --bubble-agent:rgba(237,238,244,.07); --bubble-user-bg:var(--night-ink); --bubble-user-fg:var(--night); --glass:rgba(13,17,23,.72); --shadow-card:0 0 0 1px rgba(0,0,0,.30), 0 24px 64px rgba(0,0,0,.50); --shadow-soft:0 1px 2px rgba(0,0,0,.30), 0 12px 32px rgba(0,0,0,.35); --focus-ring:var(--cyan-night); color-scheme: dark; } /* v2.0 · layering — the scale is closed. No raw z-index in product code. Toasts sit above modals so a confirmation from a modal action stays visible; tooltips are last because they attach to whatever currently has focus. */ :root { --z-base:0; /* page content */ --z-raised:100; /* sticky headers, the composer bar */ --z-rail:200; /* sidebar rail, right panel */ --z-popover:300; /* dropdowns, menus, notifications */ --z-drawer:400; /* mobile sheets, side drawers */ --z-scrim:500; /* the modal backdrop */ --z-modal:600; /* modals, the command palette */ --z-toast:700; /* toasts */ --z-tooltip:800; /* tooltips */ } /* v2.0 · chart ramps — one hue, five steps. --chart-5 is always "most" AND always the step with the most contrast against its surface: darkest on canvas, brightest on night. The anchor flips with the mode. For two series use --chart-4 and --chart-2, never the ends. Both ramps pass the ordinal checks; re-run before changing them. */ :root[data-theme="light"], .theme-light { --chart-1:#5FBFE0; --chart-2:#1FA9CE; --chart-3:#0A8AAB; --chart-4:#07728C; --chart-5:#05596D; } :root[data-theme="dark"], .theme-dark { --chart-1:#057D95; --chart-2:#0897B3; --chart-3:#34B1CE; --chart-4:#54CAE8; --chart-5:#89E6FF; } /* v2.0 · density — two densities, one set of components. Density changes SPACE only: never type size, never radius, never stroke. Set data-density on the app root. Never the default on touch, where 44px is the floor. */ :root { --row-h:44px; --gap-section:24px; --pad-card:16px; --cell-y:11px; --cell-x:18px; } [data-density="compact"] { --row-h:36px; --gap-section:16px; --pad-card:12px; --cell-y:7px; --cell-x:14px; }
<!-- theme bootstrap — before first paint, in <head> --> <script> const saved = localStorage.getItem("aic-theme"); const mode = saved ?? (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"); document.documentElement.dataset.theme = mode; </script>
ConventionRule
Components use semantic onlyA component referencing a primitive (--cyan, --ink) is a review flag — it will break in the other theme. The two sanctioned exceptions: the toggle's on-state and meter fills may use --cyan when they must read identically on both themes.
Naming--{concept}-{variant}: surfaces and text are numbered by prominence (1 = strongest). Component tokens (--btn-primary-bg) exist only where a semantic pair genuinely flips between themes.
Breakpoints1024 and 640, hard-coded in media queries (CSS vars don't reach them) — keep them in a comment block at the top of every stylesheet.
Adding a tokenNew tokens need: both theme values, a row in the semantic table, and a component that uses it. No speculative tokens.
Dark ≠ duskProduct dark mode is flat night surfaces. The aurora, grain, and glow recipes are marketing-only and never ship inside the app shell.
Part B · audit → law

The remap.

Before a line of v2.0 was written, sixteen screenshots of the July 2026 product were audited and every visual violation catalogued — twenty-two of them. Each one became a rule with a binding replacement. This table is the migration checklist: when all rows are cleared, the product is on Quiet Sky.

#Where seenCurrentQuiet Sky replacement
R1Priorities, Today's Brief, sparkles, selected day, "Discuss" linksPurple/violet as the "AI" colorDelete the violet family. Agent presence = the dot system: --accent pips, --accent-tint fills, --accent-text labels. Sparkle glyphs retired.
R2Skills & Apps heroPink→purple gradient headlineTitle 1 in --text-1. Gradient text does not exist anywhere.
R3Calendar eventGreen "Join call" fillPrimary pill. Live-ness = glowing pip + "Live" ds-label--ok, never a green button.
R4DM / Room timelinesSlack-style colored usernamesNames in --text-1 600. Identity = avatar + name, never name color.
R5Discover tabOrange "Update available" chipds-label--accent. Orange is not a system color.
R6Priority advisory lineOrange warning text--text-2 + neutral pip. Danger only for destructive/stop. Urgency is copy + placement, not paint.
R7Sidebar logo, user avatarCrimson square markThe ai·com wordmark — ink letters + accent dot. Human avatars become circles.
R8Communication HealthGold/brown meterds-meter: accent fill, danger past the warn threshold only.
R9Wiki, dashboards, meeting linksDefault blue hyperlinks--accent-text, weight 500–600, underline on hover only.
R10Wiki paths, Vault secrets, metric chipsMonospace + red inline-code in chromeOnest. Source refs become neutral chips. Monospace survives only inside authored code blocks in content.
R11"Today 9 PM" chipRed/pink date chipNeutral chip; accent + live pip only when it is happening now. Danger is never a time color.
R12Knowledge graph nodes + legendRainbow categorical paletteConcept = accent · Synthesis = ink · Source = hollow neutral · Service = mint. No new hues.
R13Agent avatarsLetter squares + "ai" badge, indistinguishable from humansds-ava--agent: solid accent circle with a pulsing halo. Attribution ("mika · Maya's agent") is structural.
R14My Apps / Marketplace cardsDark thumbnails with purple gradient art--surface-2 wells at --r-inner, centered glyph or live preview. No gradients, no dark islands on light.
R15Every CTA in the productFour unrelated button systems — black pill, black rect, white rect, green fillOne system: ds-btn pills only — primary / ghost / quiet / deny, sizes lg·md·sm. The corner is always a pill.
R16Every tab rowThree competing tab patternsTwo, by rule: segmented ds-tabs for views of the same data; underline ds-tabs-line for sections/documents. Never mixed in one header row.
R17Priority card actionsUnlabeled icon-only actions in accent purpleQuiet icon buttons, --text-3 at rest, hover --text-1. Tooltip and aria-label, not either.
R18Notification popover, modalsFlat white sheets, mixed paddings, gray pill search--surface-1 + --r-frame + --shadow-card, hairline header, ds-input search recipe.
R19Danger zone rowsOrange "Delete account" text--danger row + danger icon; confirmation follows the checkpoint pattern.
R20The whole productLight mode onlyEvery surface ships both themes from semantic tokens: data-theme on <html>, prefers-color-scheme default, per-user persistence.
R21Empty recaps ("No recap yet")Italic gray placeholderA designed empty state: one sentence + one action. Italics do not exist in the system.
R22Selected sidebar itemFloating white card + border--accent-tint fill + --accent-text at --r-tight. Hover = --fill. No shadows in the rail.

R15, in miniature Remapped

The highest-visibility row, and the clearest illustration of what a remap actually does. Four button systems existed because four screens each solved the same problem locally. One system means one decision — which priority is this? — and the shape follows from the answer.

Before · four systems
New call Update Reach out Join call

Four radii, three fills, two type treatments, one meaning: "press me".

After · one system
Live

One shape. Priority is carried by fill, and liveness by the pip — never by hue on the button itself (R3).

Migration order

The order matters: it front-loads the visible wins and leaves the switch that looks hardest for last, when it has become trivial.

  1. Ship tokens.css and Onest; add the theme bootstrap.
  2. Replace the four button systems with ds-btn (R15) — the highest-visibility win.
  3. Kill the violet family, gradient text and sparkles (R1, R2); land the dot and agent avatar (R13).
  4. Normalize tabs (R16), sidebar states (R22), links (R9), monospace (R10).
  5. Component by component, then page sign-off against the per-surface checklists.
  6. Enable dark mode last. If steps 1–5 used semantic tokens honestly, it is a switch, not a project.

Compliance is not a matter of opinion: migration/quiet-sky-audit.mjs counts violations by rule with zero dependencies, so every phase has a number that goes down. Rules tagged exact are driven to zero; heuristic rules flag for review and are never CI-gated.

Part D14 · the drawn layer

One grid, one stroke, one filled shape.

106 drawings that have to sit beside each other in a 260px rail without any of them shouting. That only happens if they are constructed, not collected.

The family Extended

PropertyValueWhy
Grid24 × 24, 20 × 20 live area2px of air on every side, so an icon never collides with its neighbour's hit area
Stroke1.5px, round caps and joinsOptically matched to Onest at 13.5px body weight; Lucide-compatible
Corner radius2The smallest radius that still reads as intentional at 14px
Keylinessquare 18 · circle 20 · portrait 16×20 · landscape 20×16Equal optical mass, not equal bounding boxes
The particleØ3, filled — the only filled elementIt is the brand mark appearing inside the icon set; nothing else earns a fill
Sizes14 inline · 16 buttons and meta · 18 navigation · 20 headersFour sizes, no interpolation

Every glyph is measured after rendering: a script rasterizes the whole family and flags any drawing that misses its keyline by more than 1.8px. Craft you would never consciously notice — but you would feel a rail where one icon sits 2px heavy than its neighbours.

Colour roles

  • --text-3 at rest in chrome — rails, headers, toolbars.
  • --text-2 in content rows, beside body text.
  • --text-1 on hover and when active.
  • --accent only when the icon is the state signal — the live pip, the selected item's mark.

Never

  • Decorative colour. An icon is not a place to add a hue.
  • Filled squares, emoji-as-icons in chrome, or a second stroke weight.
  • The sparkle / wand / star glyph — retired platform-wide. The agent's mark is the dot, not a magic wand.
  • An icon-only button without both an aria-label and a tooltip.

All 106, one grid

Rendered live from the shipped sprite, inlined at the top of this document — one request, one cache entry, consumed as <svg class="ic ic--18"><use href="#ic-{name}"/></svg>. Icons take currentColor, so this whole grid re-colours with the theme.

Onest draws the tittle on the i and the period as the same circle. The logotype is built on exactly that rhyme: the dot above the i and the dot in ai·com are the identical particle, placed twice — and only one of them is lit. Every downstream asset — app icon, agent avatar, status pip, favicon — is that one particle at a different size.

ConstructionValueWhy
The particleØ172 units, on the y=264 spineThe same circle as the i's tittle, on the same optical line
Clearances175 left / 130 right — deliberately unequalA curve falls away from its tangent point, so an equal gap would look wider against the c than against the i's flat stem
Tracking−25 display · −18 UIThe UI cut is a real optical size, not the display file scaled
Clear spaceOne x-height on all four sidesMinimum, not target
Minimum size72px display · 48px UI · below 24px, the particle aloneUnder 24px the letters stop being letters, and the dot is the mark anyway
HaloRing at 2.25× the particle radiusMarks "working right now" without a second colour
Clear space · one x-height

The dashed box is the floor, not the target.

Three sizes · one master

Display · UI cut · the particle alone, below 24px.

Never re-set the wordmark in live type. Typing ai.com in Onest gives you a period at the wrong size sitting on the baseline. The masters are outlined vector paths, so no font has to load and nothing reflows — the letterfit is fixed forever. That rhyme between the tittle and the dot is the mark, and typing it destroys it. Every wordmark on this page, including the one in the sidebar, is <use href="#logo-display"/>.

Part I · layering

One scale, no raw numbers.

Ad-hoc z-index values are how a popover ends up under a sticky header. The scale is closed; components consume the token.

TokenValueWhat sits here
--z-base0Page content
--z-raised100Sticky page and table headers, the composer bar
--z-rail200Sidebar rail, right panel
--z-popover300Dropdowns, menus, pickers, notifications
--z-drawer400Mobile sheets, side drawers
--z-scrim500The modal backdrop
--z-modal600Modals, the command palette
--z-toast700Toasts — above modals, so a confirmation from a modal action stays visible
--z-tooltip800Tooltips — last, because they attach to whatever has focus

Nothing in product code may use a raw z-index. A component that needs to sit between two steps is a signal the scale is wrong — and the scale gets fixed, not the component.

Focus & dismissal

  • One scroll-lock owner. The innermost open layer locks body, records the position and restores it on close. Nested overlays never double-lock.
  • Focus moves into the layer on open — first interactive element, or the heading for a long modal — and returns to the trigger on close.
  • Modal-class layers trap focus. Popovers do not; they close on outside click, Esc, or a scroll of the surface beneath.

Non-negotiable

  • Esc closes the topmost layer and nothing else.
  • A layer opened from the keyboard must be dismissible from the keyboard, without a pointer. No exceptions.
  • No raw z-index, and no "just this once" value between two steps.
Part H · time

Waiting is a designed state.

The product is asynchronous end to end — every surface can be waiting on a model, a tool call, or a person. So waiting is not an absence to be covered up; it has its own rules. What the user sees is chosen by how long the wait is expected to be, not by what is convenient to build.

The loading ladder Extended

Expected waitShowNever
< 120msNothing — render the result.A flash of skeleton; it reads as a bug
120ms – 1sThe destination's skeleton.A spinner
1s – 10sSkeleton + a working line naming the task ("Reading 132 issues…").An indeterminate bar with no words
> 10sWorking line + Stop pill + ds-steps.Blocking the whole surface
StreamingStream into place; the cursor is a ds-pip--live.A percentage you cannot honour

Two hard rules. A spinner never appears alone — if you cannot describe the work, you cannot ask someone to wait for it. And a skeleton never breathes for more than ten seconds; past that it has become a lie, and the surface must escalate to a working line with a Stop.

Skeletons Extended

Skeletons mirror the real layout — same line count, same widths (last line 60%), same avatar sizes — because the jump on load is the defect, not the skeleton. One opacity breath at 1.6s, rows staggered 60ms. No sweeping shimmer: the system has no gradients, and a diagonal sweep on near-black reads as a rendering artifact. Skeletons are aria-hidden; the region carries aria-busy="true" and the working line is the live region.

Light
Reading 132 issues…
Dark
Reading 132 issues…

Optimistic — and the one thing that never is

ActionOptimisticOn failure
Send a messageBubble at 60% opacity, no timestampGains a --danger hairline + "Retry"
Check a priority itemCheckbox fills, title strikes throughReverts with a toast naming the reason
ReactChip appears in accent-tintChip removes itself; no toast — too small to interrupt for
Approve a checkpointNever.—

The exception is the rule that matters: approvals, denials and Stop are never optimistic. A checkpoint that looks approved before the server agrees is a trust failure — and trust is the thing this product sells.

Empty, loading, error — three states, three renderings

Empty

  • One designed sentence in --text-2 + one primary action, in a dashed --border-strong container at --r-card.
  • Never italic, never bare (R21).

Loading

  • The skeleton. Never the empty state's copy — "nothing here" and "not here yet" are different claims.

Error

  • A plain sentence in --danger: what happened, and the next step. Plus "Try again" as ds-btn--ghost.
  • No codes, no stack traces, no apology.

No recap yet — your agent writes one after the first call of the day.

Part J · input

It is called Command Center. It behaves like one.

Every shortcut below is discoverable from ⌘/ and from the palette — a shortcut that exists only in the docs does not exist.

The command palette Extended

Modal-class layer at --z-modal, width 640, top-anchored at 14vh — not centred, because the list grows downward and centring makes it jump. Selection moves with ↑ ↓; hover sets selection too, so pointer and keyboard always agree. An empty query shows Recent and the five most-used commands, not everything. No results offers "Ask your agent instead" — the palette is a front door to the agent, not a dead end.

Esc
Do
Approve the pending checkpointA
Review agent approvals⌘⇧A
Go to
Command CenterG C
WorkflowsG W
↑↓ move · ⏎ run · ⌘. stop the agent
Esc
Do
Approve the pending checkpointA
Review agent approvals⌘⇧A
Go to
Command CenterG C
WorkflowsG W
↑↓ move · ⏎ run · ⌘. stop the agent

The keyboard map

KeyDoesWhere
⌘KOpen the command paletteEverywhere
⌘/Shortcuts sheetEverywhere
⌘.Stop the agentAnywhere an agent is working
EscClose the topmost layer, return focusEverywhere
G then C W A K LGo to Command Center · Workflows · Skills & Apps · Knowledge · CalendarEverywhere
J K or ↑ ↓Move through the focused listLists, timelines, notifications
⏎Open / expand the focused rowLists
E / SHide / snooze the focused rowPriorities, awaiting reply
A R DApprove · Review · DenyThe focused checkpoint
⌘⏎ / ⇧⏎Send / newlineComposer
⌘FSearch this surfaceRooms, Knowledge

A shortcut never fires while a text field has focus except ⌘-combinations. Single-letter shortcuts require the list to hold focus, not the page.

Density Extended

Two densities, one set of components. Density changes space only — never type size, never radius, never stroke. Set with data-density="compact" on the app root. Compact is for tables, rooms and long lists on large screens; it is never the default on touch, where 44px is the floor.

 Comfortable (default)Compact
Row height44px36px
Section gap24px16px
Card padding16–18px12–14px
Table cell11px 18px7px 14px
Composer min-height44px36px

Drag & reorder

Only two things reorder: priority items and workflow steps. Everything else sorts. The row lifts to --shadow-card at 0.98 scale and 92% opacity; a 2px accent line marks the drop position. No ghost image, no rotation. The keyboard equivalent is mandatory — Space picks up, ↑ ↓ move, Space drops, Esc cancels, all announced through a live region ("Moved to position 2 of 6"). Drop is optimistic; failure restores the original order with a toast.

Ping Aaron + add agenda
Unblock Sid on Slack auth
Part K · data

What one colour does to a chart.

Quiet Sky has one accent and no gradients. That is not a limitation to work around — it decides the chart system.

The law

  • Magnitude is one hue. The cyan ramp, light → dark. The default for every chart in the product.
  • Identity is position and direct labels — not colour. Two or three series get ramp steps plus an end-label each.
  • Beyond three series: small multiples, or fold the tail into "Other". Never a generated hue.
  • Status colours are reserved. Mint and danger are state, never series 2, and always ship with an icon and a word.

Which means

  • There is no diverging ramp — there is no second hue to build one from. Polarity is two stacked fills with a 2px gap, both labelled.
  • There is no amber. Orange was deleted (R5, R6), so "warning" is copy and placement, not paint.
  • There is no pie chart. Three or more parts are bars.
  • Never a dual-axis chart. Two scales become two charts, or index to a common base.

Which form the data gets

The data's jobForm
One headline numberStat tile — no plot
Magnitude across categoriesHorizontal bars, sorted by value
Change over timeLine, 2px
Part-to-whole, 2 partsSingle stacked bar with a 2px gap + both labels
Part-to-whole, 3+ partsBars, not a pie. The system has no pie chart.

The ramps — validated, not chosen Extended

Both ramps pass the ordinal checks — monotone lightness, adjacent ΔL ≥ 0.06, light-end contrast ≥ 2:1 against that mode's own surface, single hue. Measured: the light ramp's lightest step #5FBFE0 reads 2.03:1 against --bg with a 3° hue spread across all five steps; the dark ramp's #057D95 reads 3.94:1 against #0D1117 at a 1° spread. The dark steps are selected, not inverted — derived against night and validated there, rather than computed from the light hexes. What does flip is the anchor: --chart-5 is always the largest value and always carries the most contrast against its surface — darkest on canvas, brightest on night. Get that backwards and "most" becomes the least visible mark on the chart. For two series use --chart-4 and --chart-2, not the ends, where one of the pair goes dim in one theme.

Light · on --bg #FBFBFD
123 45 · most
Dark · on --surface-1 #0D1117
123 45 · most

Charts

Bars capped at 24px thick with a 4px rounded data-end and a square baseline · lines 2px with an end-marker ringed 2px in the surface colour · hairline solid grid, never dashed · values at the tip and the line-end only, never on every point · a 2px surface gap between touching fills · text wears text tokens, never the data colour.

Light
Requests by connector
Slack 412 Gmail 338 Calendar 214 Linear 156 Notion 92 0 110 220 330 440
Requests by connector · last 30 days
ConnectorRequests
Slack412
Gmail338
Calendar214
Linear156
Notion92
Dark
Requests by connector
Slack 412 Gmail 338 Calendar 214 Linear 156 Notion 92 0 110 220 330 440
Requests by connector · last 30 days
ConnectorRequests
Slack412
Gmail338
Calendar214
Linear156
Notion92
Light
Where the work went
88 44 Aug Nov Feb May Jul 96 72 48 24 0
Handled by agent Escalated
Where the work went · monthly
MonthHandled by agentEscalated
Aug1812
Nov3419
Feb5224
May7032
Jul8844
Dark
Where the work went
88 44 Aug Nov Feb May Jul 96 72 48 24 0
Handled by agent Escalated
Where the work went · monthly
MonthHandled by agentEscalated
Aug1812
Nov3419
Feb5224
May7032
Jul8844

Every chart ships a hover layer and a table view behind a quiet toggle — the "View as table" buttons above are live. That is the accessibility contract, and it is also what people copy into a document. In print the table always wins: the chart drops and the numbers stay.

Stat tiles, meters, sparklines & stacks

Light
Handled by agent
88%
12 pts
Median first reply
19m
4m slower
Requests · last 14 days
1,212
You / them · #shipping-week
75 / 25
PR H+7 11 in the room
Dark
Handled by agent
88%
12 pts
Median first reply
19m
4m slower
Requests · last 14 days
1,212
You / them · #shipping-week
75 / 25
PR H+7 11 in the room

A delta chip always carries an arrow and a number — never colour alone. Bars cap at 24px thick; the meter track is 7px; the sparkline is 2px at 28px tall with an 8px end-dot. Avatar stacks cap at four faces with a 2px surface ring each and an overflow +N chip — and an agent is never folded into the overflow. You must always be able to see that an agent is in the room.

Tables

Micro-label headers on --surface-3, hairline rows, sticky header at --z-raised with a hairline that appears only once scrolled. Sort: one column at a time, chevrons-up-down in --text-3 resolving to a single chevron in --accent-text when active; sort state lives in the URL. Selection: a 44px checkbox column, indeterminate in the header when partial, and a selection bar that replaces the toolbar. Prefer "Load more" over numbered pages for feeds — and never infinite scroll on a surface that has a footer. Numerals are Onest 600, tabular in columns and proportional in prose.

Part L · sound

The same rule as the accent.

The sound identity is part of this system, not a side project — and like cyan, it only fires where it carries meaning. QuietSkySound.play(name).

SoundFires whenTier
signatureFirst launch of a session, and nowhere elseattention
sendYou send a messageambient
tapA human message arrives in the room you are looking atambient
pingA DM arrivesambient
mentionYou are mentionedattention
checkpointThe agent needs youattention
doneA verified-done strip landsattention
liveA call starts, or a workflow begins a runambient
callEndA call endsambient
stoppedYou pressed Stopattention
errorAn action failedattention

Silent

  • Never on hover, scroll, typing, focus change or navigation.
  • Never for something you are already looking at — an arriving message in the focused room plays tap; the same message while you are typing in it plays nothing.
  • Never two sounds inside 400ms. The later wins.
  • Muted entirely during a call except stopped and error.

Always

  • Attention-tier is off until the user opts in; ambient respects the OS setting.
  • A sound never carries information alone. Every sound accompanies a visible change — it is a second channel, never the only one.

The event map and the rules are ratified; the sounds themselves are not. A wide slate of candidates is being auditioned under the same test as the accent — it only fires where it carries meaning. Nothing final yet, which is why there is nothing to play on this page.

Part M · print

Paper is a ninth surface.

People print approvals, briefs and health tables, and a system that only exists on a screen fails at the moment someone takes it into a room.

Force the light theme — night surfaces waste ink and lose every hairline. Drop the rail, the mode switch and all hover-only chrome; they have nothing to say on paper. Cards lose their shadow and keep their hairline. Charts print their table view, not the plot: the numbers survive a photocopier and the marks do not. Every card and table carries break-inside: avoid. Page one gets the wordmark, the surface name and the date — a printout with no provenance is a rumour.

/* Part M — the whole of it */ @media print { :root { color-scheme: light; } .rail, .mode, [data-hover-only] { display: none; } .ds-chart svg, .ds-chart .ds-legend { display: none; } .ds-chart table { display: table; } .ds-card, .ds-chart, table { box-shadow: none; break-inside: avoid; } }

ai.com · Quiet Sky design system v2.0 · August 2026 · Internal · Foundations sources: landing.html (v4), strategy-deck.html (slides 11–12), product-spec.html. Application layer: app-design-system.md (Parts A–M) · migration/quiet-sky-audit.mjs · product screenshot audit, July 2026. Canonical = extracted verbatim; Extended = derived under the system's rules; Remapped = added because the audit found a violation. Terminology per the ratified glossary: Workflows (formerly Routines). Companion docs: quiet-sky-story.html (how this came together) · product-spec.html · strategy-deck.html (the July 2026 brand strategy, archived).