Style guide

From the CentrOS iOS app

This page documents the design system every page of this site is built from: the CentrOS iOS app’s sky, clear Liquid Glass sections, iOS system colours and text styles, and its floating control layer. Every page loads two shared stylesheets with no build step: public/css/style.css, and public/css/sky.css (the sky’s gradient ground, shown before the first WebGL frame); the case-study pages and this page add a small page-local file from public/css/pages/. Every token value below is read live from public/css/style.css with getComputedStyle, and every specimen is the real markup.

Design intent

5

When a new component is in doubt, it has to serve one of these.

  1. Every page stands on the skyA slowly drifting cosmic aurora with its own hue per page, dark by default as the app was designed. Content sits in clear Liquid Glass inset-grouped sections that read exactly like the app’s cards.
  2. Content first, controls float above itContent → glass control layer → person, never page → boxes → buttons. A large title opens each page; the only chrome is an account capsule, a floating tab bar with Contact set apart, and system-glass sheets. The chrome recedes while you read and returns when you reach for it.
  3. Colour means one thing everywhereThrough the app’s Tone: blue for action, yellow for waiting, green for settled, orange for caution, red for stop. Chrome stays label-coloured. Type is the system font in iOS text styles, and serif is only for words a person wrote.
  4. Simple is not minimalEvery approved fact stays one tap away in native disclosure rows that work without JavaScript. Nothing looks pressable unless it does something; anything that cannot act is drawn as a chip.
  5. Mobile first, flawless everywhereBuilt at 390 px and checked from 320 to 430 px, in 844 × 390 landscape and on desktop, where the iPad readable column sits centred on the sky. Reduced motion, reduced transparency, increased contrast, forced colours, print and no-JS are all handled.

Colour

Every value prints from getComputedStyle and follows the appearance you chose in the contact sheet. Literal colours live only in the token block at the top of style.css.

System colours

13

The iOS 26 system colours, exact. Dots, icons and tiles use them; text uses the AA-safe Tone colours below.

  • --blueaction, links, focus; Home’s sky key
  • --greensettled, verified, on
  • --yellowwaiting on someone
  • --orangecaution
  • --redstop: a rule stopped it
  • --purplea fact; identity tiles
  • --cyanidentity; the Activity sky key (AXED)
  • --tealidentity
  • --mintidentity
  • --indigoidentity; CentrOS tiles
  • --pinkidentity
  • --brownidentity
  • --grayneutral tiles; this page’s sky key

Labels, fills and backgrounds

16

  • --labelprimary text, icons, chrome
  • --label-2secondary text on glass (AA-tuned)
  • --label-2-skysecondary text set straight on the sky
  • --label-3chevrons, decorative only
  • --label-4quiet dots
  • --fill-1row press, switch track
  • --fill-2pressed chip
  • --fill-3neutral chip, code, segmented track
  • --fill-4wells inside a card, row hover
  • --fill-quietquiet pill
  • --separatorhairlines between rows
  • --bgthe inverse of the label: primary pill text
  • --bg-grouped-2the reduce-transparency card
  • --bg-elevatedthe opaque sheet
  • --bg-elevated-2rows on an opaque sheet
  • --focusthe focus ring

Tone

5

One meaning each (Tone.swift). The system colour marks dots and icons, --fg-* is the text colour and --wash-* the 16 % fill behind a chip.

  • Action Sendthe next step, links · text --fg-action wash --wash-action
  • Waiting Waitingwaiting on someone · text --fg-waiting wash --wash-waiting
  • Settled Settleddone, verified · text --fg-settled wash --wash-settled
  • Caution Checklook before you act · text --fg-caution wash --wash-caution
  • Stop Stoppeda rule stopped it · text --fg-stop wash --wash-stop

Sky hues

6

Each page lights the sky in its own hue with <body data-sky>. Show one here to watch this page’s sky, and the glass rims with it, cross-fade over 3.5 s. Reload to return to ash.

  • accent · HomeApp: Home. Blue, Tone.action
  • violet · CentrOSApp: World. “Indigo: the night sky, not a purple”
  • teal · AXEDApp: Activity. Cyan
  • rose · Ask sheet only (never a page sky)App: Ask. “Amber: sitting at the fire”
  • ash · Style guideApp: Kept out. Gray
  • stop · Not used as a pageApp: a draft a check refused. Red

Dark and light, side by side

Dark is the default; Light and Match device are in the contact sheet. Both previews re-declare the token block, so each value prints as that appearance resolves it.

Dark

  • Guest replyDrafted, waiting for the ownerSend
  • ChipsActionWaitingSettledStopNeutral
  • --label
  • --label-2
  • --separator
  • --fill-3
  • --blue
  • --green
  • --yellow
  • --orange
  • --red
  • --fg-action
  • --glass-card-bg

Light

  • Guest replyDrafted, waiting for the ownerSend
  • ChipsActionWaitingSettledStopNeutral
  • --label
  • --label-2
  • --separator
  • --fill-3
  • --blue
  • --green
  • --yellow
  • --orange
  • --red
  • --fg-action
  • --glass-card-bg

Type

14

The system font (SF on Apple devices) in iOS text styles at the default Dynamic Type size, in rem so browser text size scales them. Sentence case, no uppercase, no italics: emphasis is weight. Sizes print as rendered here.

Space

Measured from the app at 1 pt = 1 CSS px. Each bar is drawn from its value and measured live; bars longer than the box are cut.

Geometry

4

Concentric: a rounded thing inside another echoes its curve, so the inner radius is the outer one minus the inset.

Glass

Content is the surface; controls float above it. No content sits inside a second pane of glass: wells inside cards use --fill-4.

Recipes

5

Glass is used sparingly so content stays dominant: one clear layer for content, one regular layer for the controls above it. Values print for the current appearance.

Clear card .card
--glass-card-bg
--glass-card-filter content sections; the rim takes the page’s sky hue in dark, white in light; no shadow
Regular control .glass
--glass-ctl-bg
--glass-ctl-filter tab bar, Contact circle, account capsule, back circle, Done
Sheet .sheet
--glass-sheet-bg
--glass-sheet-filter the system sheet: neutral grey, dense enough that nothing bleeds under text
Selected tab .tabbar__thumb
--tab-selected the selection is the lighter capsule, never a tint
Scroll edge .topbar::before
--edge-dim an 8 px blur plus a dim under the toolbar row, fading out 28 px below

Cards, one and apart

A clear card. The sky shows through, blurred, with its hue intact; the rim is 1 px, lighter than the inside.

Controls on the sky

The back circle, the account capsule and a capsule, all .glass. They brighten and grow a little when pressed.

The real tab bar floats at the bottom of every page (top centre from 1024 px). This one is static; its tabs link back here and its mail circle starts an email.

Sheet

A static sheet group. The real one is a native <dialog>: a floating bottom sheet on phones, a centred 540 px form sheet from 768 px.

Contact

  • Emaila grouped row on the sheet
  • Appearancegroups inset 16, radius 26

A footer under a group, in footnote.

Open the real sheet

When glass steps aside

  • Reduced transparency: cards become the system’s own opaque card (--bg-grouped-2) with no rim; controls, the sheet and the scroll edge turn opaque. The sky still shows between cards.
  • Increased contrast: a solid visible rim on cards and controls, stronger secondary labels and separators.
  • Forced colours: the sky is hidden; cards, controls, the sheet and chips get CanvasText borders.
  • No backdrop-filter support: glass falls back to near-opaque fills.

Components

Every specimen is the real markup with the shared classes listed above it. Specimen ids are prefixed sg-, and links stay on this page unless they say otherwise.

Section header

.sec__head .sec__icon .sec__title .sec__detail .sec__intro .sec__foot

Needs you

3

An intro on the sky, in subheadline.

Symbol 20 px, title in headline, detail in footnote, all secondary label colour. On a page the title is an h2, or an h3 in a group.

Large title and intro

.lt .lt__title .lt__sub .intro .intro__title .intro__text

An intro title states a section’s claim

Its text follows in subheadline, on the sky.

The large title is this page’s own heading above; once it scrolls under the toolbar row, the inline .topbar__title fades in.

Rows

.card .list .list--glyph .list--tile .list--avatar .row .row--top .row--avatar .row__text .row__title .row__sub .row__meta .row__trail .row__chev .row__ext .row__body .row__go .row__link

  • Tile row with a stretched linkA body line in subheadline. The whole row is the link’s target; its name is only the link text.Seen in the components
  • PersonRound avatar with a status dotFootnote metaSend
  • CompanyRounded-square avatarLater

Disclosure row

.disc .disc__body .disc__note .disc__stack .disc__role .disc__when .more

  • A closed rowIts summary already states the key fact

    The body is in the DOM all along, so it prints, searches and works without JavaScript. A deep link to an id inside opens it.

    Stack HTML · CSS · no build step

  • An open rowThe chevron turns 90°

    A role, a companyMonth 20XX – Month 20XX · Place

    • A bullet inside the body.
    2 more
    • A second bullet.
    • A third bullet.

Chips

.chip .chip--action .chip--waiting .chip--settled .chip--caution .chip--stop

On requestNewIn progressIn productionCheckStopped

A chip states something and never acts. 20 px tall, caption 1 at 500, on its tone’s 16 % wash.

Pills

.pill .pill--primary .pill--tinted .is-done .copy

A pill always does something. The visible capsule is 32 px inside a 44 px hit box. The Copy pill appears only on https, where copying can work.

Buttons

.btn .btn--inverse .btn.glass .btn--block .actions

50 px capsules for the one or two main actions of a page; a secondary button set on the sky floats as glass.

Avatars, tiles, glyphs and dots

.avatar .avatar--co .avatar--30 .avatar--56 .av-1…9 .badge-dot .tile .tile--40 .tile--text .tile--everything .glyph .dot

People are round, companies rounded squares, initials on a gradient lighter at the top. Tiles are 32 px (40 where one stands in for a company). The rainbow tile is the app’s one gradient, kept here and nowhere else.

Settings controls

.row--pick .pick .seg .seg__opt .switch

  • Segmented control

The picker row is the contact sheet’s own control: a native <select> under a blue trailing value. These specimens change nothing; Appearance and Background live in the sheet.

Claims and bullets

.claims .claim .claim__why .claims--terms .bullets .bullets--sm

Font
The system font: SF on Apple devices
Serif
Only for words someone wroteWhy: the app sets mail in serif and everything else in SF.
Icons
  • Lucide on the web
  • SF Symbols in the app
Term
A term over its definition, in headline over subheadline.

Stats and timeline

.stat .stat__n .stat__l .timeline .timeline__when

  • 40M+AXED reads
  • 3,980+CentrOS tests on main
  1. Nov 2022LLMs deployed across dev & business workflows
  2. Feb 2026CentrOS in production

Numbers use tabular digits, as rows, never count-ups.

Trace and receipt

.trace .trace__head .trace__who .trace__what .trace__foot .receipt .receipt__arrow .proposal__label .proposal__claim .proposal__not

Specimenwho did what

  1. routerclassified the request and chose a lane
  2. executordrafted the action with its sources
  3. verifierchecked the evidence

Waitingfor the owner

Proposed

A proposal’s claim

Not done until someone approves it

Result

What actually happened

Labels in mono are the machine voice.

Mail and quote

.mail .mail__head .mail__from .mail__when .mail__body .quote

A guest

Specimen text

Hi, we land late on Friday. Is self check-in still possible after midnight?

Thanks!

Words a person wrote are set in serif.

Specimen text

Serif appears only here: words someone wrote.

Flow

.flow .flow__step .flow__arrow .flow__label .flow__detail

archived

Contract closed and durable. Evidence, tool calls, gate decisions, and approver (if any) are retained for audit. Read-only from this point — the audit trail outlives the runtime.

  • All 11 states, defined8 on the main path · 3 failure paths
    draft
    Contract materialized but not yet routed. Risk tier and lane assigned by the router on the next tick.
    routed
    Contract has been classified and assigned a policy lane. Lane A proceeds to executor; lane B/C waits for owner confirmation first.
    executing
    Executor is calling tools, pulling RAG context, and writing checkpoints. Crash here resumes from the last checkpoint, not the beginning.
    eval-pending
    Executor finished; adversary is critiquing the evidence trail. Low-confidence outcomes route to gate-pending or held.
    gate-pending
    Required gates haven't all passed. Verifier holds the contract until evidence/adversary/verifier all return ✓ or the owner intervenes.
    approved
    Owner approved a lane B/C contract from the inbox. Executor proceeds to perform the action.
    executed
    Action complete. Final state written. Contract awaits archival.
    archived
    Contract closed and durable. Evidence, tool calls, gate decisions, and approver (if any) are retained for audit. Read-only from this point — the audit trail outlives the runtime.
    rolled-back
    A gate detected an issue post-execution. Rollback gate reversed the action and the contract closed with a failure summary in the audit trail.
    held
    Owner clicked Hold from the inbox. Contract paused until evidence is refreshed or owner re-decides.
    stop-ship
    Critical gate (e.g., adversary flagged a hard violation) fired. Contract is hard-blocked and only an admin override can release it.

The CentrOS contract lifecycle. Nodes ship disabled, so without JavaScript they are static chips and the archived definition is already on the page. With JavaScript, one node at a time is aria-pressed and the detail is announced politely.

Table

.table

RoleTokenWhere
Section header--t-headline.sec__title
Row subtitle--t-subhead.row__sub
Chip--t-caption1.chip

Below 560 px each row stacks, label over value.

Work card, stub and frame

.work .work__head .work__title .work__status .work__why .work__flow .work__receipts .work__actions .stub .frame__bar

CentrOS

In productionsince Feb 2026

An orchestration platform that turns messy business workflows into agent systems — agents draft guest replies, process refunds and vendor invoices, and an owner approves anything irreversible.

router → executor → adversary → verifier → owner inbox

23-unit hospitality operation · 3,980+ tests on main

In progressUnbuilt things carry a stub like this one instead of a fake button. Until then, try the live demo.

Read the case study

Frame barOpen the demo

The CentrOS demo’s iframe sits below this bar from 768 px; on phones a poster shows instead.

Chrome

.topbar .topbar__back .topbar__title .topbar__account .tabbar .tabbar__tabs .tabbar__thumb .tab .tab__label .tabbar__ask .sheet .sheet__bar .sheet__grab .sheet__title .sheet__done .sheet__scroll .sgroup .sgroup__foot .sheet__fine

  • Top barNo bar background. A back circle on pushed pages (like this one), the inline title once the large title scrolls under, and the account capsule, which opens the contact sheet.
  • Tab barHome, CentrOS, AXED in one glass capsule, the current one in a lighter inner capsule (none on this page). Contact is set apart as the app sets Ask apart. It minimises to two 48 px circles while you scroll down and returns when you scroll up, near the top, on a tap or on keyboard focus. From 1024 px it floats at the top and never minimises.
  • SheetContact details plus Appearance (Dark, Light, Match device), Background (Sky, Solid) and New sky. Done, Esc, the backdrop or a downward drag close it, and focus returns to the opener. The sky settles behind it. Without JavaScript the openers jump to the page’s own Contact section.

Page furniture

.skip .wrap .foot .vh .nobr .nums .js-only .kicker .card--text .card--pad .apart .group

.skip is the first Tab stop and moves focus to main. .vh hides text visually but keeps it for screen readers, such as “(opens in a new tab)” after every external link. .wrap is the one reading column.

Icons

66

accessibility
activity
arrow-down
arrow-right
arrow-up-right
badge-check
book-open
briefcase-business
building-2
chevron-down
chevron-left
chevron-right
chevrons-up-down
code-xml
component
cpu
database
file-text
gauge
github
globe
graduation-cap
hammer
hand
handshake
history
house
inbox
layers
layout-grid
linkedin
list
lock
mail
maximize-2
message-square
package
palette
phone
play
plug
puzzle
receipt
repeat
rocket
route
ruler
scale
search
settings-2
shield-alert
shield-check
sparkles
split
swatch-book
target
timer
trending-up
triangle-alert
type
user-round
user-round-check
users
workflow
wrench
zap

Lucide, ISC licence. One sprite, public/images/icons.svg; each icon is <svg class="i"><use href="…#name">, 2 px strokes in currentColor, the web twin of the app’s SF Symbols.

Motion

Nothing moves unless you do something, except the sky.

What moves, and when

9

  • State changeschevrons, the segmented thumb, the switch knob--ease-smooth, the app’s .smooth spring, over
  • Tab bar minimise and restorewidth, height and padding--dur-min on --ease-smooth
  • Sheet on phonesup from below, back down--ease-sheet over
  • Sheet from 768 pxscale .97 → 1 plus a fade0.35 s and 0.25 s
  • The sky settles behind a sheetdims, inside sky.js0.8 s
  • Sky hue and appearancecross-fade to new colours--ease-sky over
  • Pressrows fill instantly, out over 0.25 s; pills and buttons dim to .65, back over 0.2 sglass controls grow to 1.06 and brighten over 0.15 s
  • Inline title and scroll edgeopacity--dur-fade
  • On loadnothing movesevery transition is off until load plus one frame

Never animated: no keyframes, load animations, count-ups, scroll-linked effects or parallax on content. Under reduced motion the sheet fades instead of sliding and the tab bar and chevrons change instantly.

The sky

The slowest thing on the screen.

  • Baked, then made to flowSix keyframes are drawn once, then a light pass cross-fades them forward and back on a 60 s loop and carries the picture along a slow current.
  • Light on the deviceDrawn at about half the screen’s pixels and about a dozen times a second at rest; never redrawn for a scroll.
  • Parallax, the only oneThe picture is 1.35 screens tall and slides at 0.15 of the scroll.
  • Holds stillUnder reduced motion it is one still frame; it pauses while the tab is hidden and its clock stops, so it never jumps.
  • FallbacksA CSS gradient of each page’s sky shows before the first frame, without JavaScript, without WebGL and while a lost context comes back. Background: Solid draws one plain colour and no canvas. Forced colours and print hide it.

Try it

  • Open this rowThe chevron turns on the smooth spring

    The chevron turned 90° over 0.3 s because you opened it. The body appears without a height tween. Under reduced motion the chevron turns instantly.

Accessibility

Every preference the browser exposes is handled in the last block of style.css, after every component, so it always wins.

  • Focus. Every control shows a 3 px blue :focus-visible ring (Highlight under forced colours). “Skip to content” is the first Tab stop and moves focus to main; scroll padding keeps a focused element clear of the top bar and the tab bar.
  • Targets. Every link, button and summary outside running prose is at least 44 × 44 px; pills draw a 32 px capsule inside a 44 px hit box.
  • Contrast. Every text pair passes WCAG AA against the rendered sky, sampled at several sky moments. --label-2 and the --fg-* tone colours are raised above the app’s values to get there, and a soft halo sits behind text set straight on the sky.
  • Reduced motion. The sky is one still frame, the sheet fades, and the tab bar and chevrons change instantly.
  • Reduced transparency. Cards become opaque system cards with no rim; controls, the sheet and the scroll edge turn opaque.
  • Increased contrast. Solid rims, stronger labels and separators, and inline links underlined at 2 px.
  • Forced colours. The sky is hidden; cards, controls, the sheet and chips get system borders, the current tab is outlined in Highlight, and the top bar turns opaque.
  • Print. Every disclosure opens before printing and returns to how you left it afterwards. The chrome, the sky and the demo frame are hidden, and external links print their URL.
  • No JavaScript. The site is dark with the CSS sky, every fact is reachable through native <details>, the tab bar stays expanded, the Contact buttons jump to the page’s Contact section, and lifecycle nodes stay static chips.
  • Structure. One h1 per page, an h2 for every section, and no skipped levels. Landmarks: one main, one primary nav, one footer.
  • Privacy. No cookies and no tracking. Local storage holds only an appearance or background you choose, in this browser.

Contact

Contact

Shren PatelAI agent orchestration engineer

Canada, remote · EST/PST.

Solid draws a plain colour instead of the sky, so your device does less. Both choices are saved in this browser only.

No cookies, no tracking.