yuicss (YUI-342)
How Yui looks, as one stylesheet. It styles every agent screen, and its tokens will drive the app's own chrome too, so a restyle reaches everything at once. The gallery at yuigui.com/yuicss draws all of it in three agent looks, light and dark; it is the visual contract the app is checked against. Plan: docs/specs/yl-screens-yuicss.md in the repo.
Source: site/lib/yuicss/. Built file: /yuicss/yuicss.css on the site (site/public/yuicss/yuicss.css), generated by node site/lib/yuicss/build.mjs; the site build fails when it is stale.
1. Four layers
- Tokens.
tokens.jsonis the one source: color, type scale, space scale, shape, motion.build.mjscompiles it to CSS variables on.yuicss;YuiTokens.swiftcomes later (YUI-346).theme.mjsturns an agent look (the same recipe astheme accent=... font=... radius=... motion=..., compiled bylook.mjswith the app's contrast guard) into the variables below. The agent's look sets these and nothing else. - Classless defaults. Every element looks finished with no class:
h1toh6,p,a,button,input,textarea,select,label,ul,ol,table,img,details,progress,dialogand the rest. Buttons are big tap targets in the accent. The first button is the primary one; a sibling after it steps down to a tint on its own. A container's children stagger in with the look's enter motion; Reduce Motion is respected. - Utilities. A Tailwind-named subset:
row,col,grid-3,items-*,justify-*,gap-*,p-*,m-*,w-*,h-*,text-*,bold,bg-accent-200,text-muted,rounded-*,shadow-*,spin,pulse,float,enter-pop,delay-*. Same names as Tailwind, so a model writes them right first time. Arbitrary values (h-[62%]) are inline styles the renderer makes withutilities.mjs; colors there are tokens only, never a hex, so contrast holds. - Components.
card,hero,chip,tabs,sheet,toast,progress,ring,avatar,badge,toggle,slider,stepper,segmented,field,empty, and every preset as a part:say,list,table,stat,timer,chart,map,shapes,sketch,math,steps,calc,gallery,image,compare,camera,mic,page,deck,timeline,game,flow.
2. The variables
Set on the .yuicss root (the body in the app, a frame on a page). .dark switches the palette; so does the site's data-theme.
- Color:
--paper,--surface,--ink,--muted,--line,--accent,--accent-ink(text on the accent),--accent-text(the accent as text, 4.5:1 on paper),--accent-50to--accent-900(50 sits by the paper and 900 far from it, in light and in dark, sobg-accent-100is always a soft tint; 50 to 300 carry ink),--good,--warn,--bad, each with-ink,-textand-soft. - Type:
--font,--font-rounded|default|serif|mono,--text-xsto--text-4xl,--leading-*,--weight-*,--weight-heading(the look's weight). - Space:
--space-*,--gap(12px, every container),--pad(20px, the screen),--control(52px, buttons and inputs),--tap(44px). - Shape:
--radius(cards and pictures: round 24, soft 18, square 10, yui 22),--radius-control(round 999, soft 14, square 8, yui 16),--radius-smto--radius-full,--shadow-soft,--shadow-lift,--line-w. - Motion:
--mo-enter,--mo-handoff,--mo-stagger,--mo-beat,--mo-open,--mo-breath,--mo-ease(motion.mjs),--enter-name(y-rise|pop|slide|drop|fade),--pulse-play(paused for a still look).
3. The guard
Every look, light and dark, passes before it ships (yuicss.test.mjs runs all 28 sets): ink and muted at 4.5:1 on paper and surface, accent at 3:1 on paper, accent-ink at 4.5:1 on accent, the accent as text at 4.5:1, ink at 4.5:1 on accent 50 to 300, and good, warn and bad each at 3:1 as a fill with a 4.5:1 ink, 4.5:1 as text, and ink readable on their soft tint. Yui's own coral is the brand and ships as is, like the app.
4. Rules for the layers above
- If an example screen needs more than two classes on a line, yuicss is missing a default. Fix yuicss, not the example.
- New class names come with their frame in the gallery. The gallery may use only classes the sheet defines (the test checks).
- Colors are tokens. No hex anywhere above layer 1.