@holistics/anfra-design 0.0.0-stage → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +325 -0
- package/fonts.css +11 -0
- package/index.css +4 -0
- package/package.json +33 -4
- package/tokens.css +319 -0
- package/type.css +33 -0
- package/README.md +0 -3
package/DESIGN.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: alpha
|
|
3
|
+
name: anfra
|
|
4
|
+
description: anfra's product UI, in anfra core (anfra serve, the SDK's plugin UI) and anfra Cloud. Paper and ink with one violet accent, dense and quiet, on the anfra brand.
|
|
5
|
+
colors:
|
|
6
|
+
primary: 'oklch(0.565 0.194 300.3)'
|
|
7
|
+
primary-hover: 'oklch(0.517 0.192 299.1)'
|
|
8
|
+
on-primary: 'oklch(1 0 0)'
|
|
9
|
+
surface: 'oklch(1 0 0)'
|
|
10
|
+
surface-chrome: 'oklch(0.955 0.007 88.6)'
|
|
11
|
+
surface-sunken: 'oklch(0.973 0.005 95.1)'
|
|
12
|
+
on-surface: 'oklch(0.201 0.022 301.1)'
|
|
13
|
+
on-surface-weak: 'oklch(0.392 0.021 304.3)'
|
|
14
|
+
placeholder: 'oklch(0.485 0.022 306.3)'
|
|
15
|
+
disabled-surface: 'oklch(0.201 0.022 301.1 / 0.04)'
|
|
16
|
+
disabled-text: 'oklch(0.723 0.017 306.3)'
|
|
17
|
+
link: 'oklch(0.484 0.181 298.1)'
|
|
18
|
+
selected: 'oklch(0.946 0.027 304.8)'
|
|
19
|
+
inverse-surface: 'oklch(0.201 0.022 301.1)'
|
|
20
|
+
inverse-on-surface: 'oklch(0.961 0.007 304.2)'
|
|
21
|
+
error: 'oklch(0.549 0.199 27.1)'
|
|
22
|
+
error-text: 'oklch(0.501 0.17 27.2)'
|
|
23
|
+
error-container: 'oklch(0.971 0.014 22.8)'
|
|
24
|
+
warning-text: 'oklch(0.501 0.1 70.3)'
|
|
25
|
+
warning-container: 'oklch(0.973 0.028 84.6)'
|
|
26
|
+
success-text: 'oklch(0.479 0.1 151.8)'
|
|
27
|
+
success-container: 'oklch(0.972 0.021 152.2)'
|
|
28
|
+
typography:
|
|
29
|
+
title:
|
|
30
|
+
fontFamily: Inter
|
|
31
|
+
fontSize: 20px
|
|
32
|
+
fontWeight: 600
|
|
33
|
+
lineHeight: 28px
|
|
34
|
+
heading:
|
|
35
|
+
fontFamily: Inter
|
|
36
|
+
fontSize: 14px
|
|
37
|
+
fontWeight: 600
|
|
38
|
+
lineHeight: 20px
|
|
39
|
+
body:
|
|
40
|
+
fontFamily: Inter
|
|
41
|
+
fontSize: 14px
|
|
42
|
+
fontWeight: 400
|
|
43
|
+
lineHeight: 20px
|
|
44
|
+
label:
|
|
45
|
+
fontFamily: Inter
|
|
46
|
+
fontSize: 14px
|
|
47
|
+
fontWeight: 500
|
|
48
|
+
lineHeight: 20px
|
|
49
|
+
caption:
|
|
50
|
+
fontFamily: Inter
|
|
51
|
+
fontSize: 12px
|
|
52
|
+
fontWeight: 400
|
|
53
|
+
lineHeight: 16px
|
|
54
|
+
code:
|
|
55
|
+
fontFamily: Inter
|
|
56
|
+
fontSize: 20px
|
|
57
|
+
fontWeight: 400
|
|
58
|
+
lineHeight: 28px
|
|
59
|
+
letterSpacing: 0.5em
|
|
60
|
+
fontFeature: '"tnum"'
|
|
61
|
+
mono-label:
|
|
62
|
+
fontFamily: Geist Mono
|
|
63
|
+
fontSize: 12px
|
|
64
|
+
fontWeight: 400
|
|
65
|
+
lineHeight: 16px
|
|
66
|
+
letterSpacing: 0.025em
|
|
67
|
+
rounded:
|
|
68
|
+
md: 6px
|
|
69
|
+
lg: 10px
|
|
70
|
+
xl: 14px
|
|
71
|
+
pill: 9999px
|
|
72
|
+
spacing:
|
|
73
|
+
unit: 4px
|
|
74
|
+
control-height: 32px
|
|
75
|
+
field-gap: 8px
|
|
76
|
+
form-gap: 24px
|
|
77
|
+
panel-inset: 8px
|
|
78
|
+
sheet-padding: 24px
|
|
79
|
+
sheet-width: 384px
|
|
80
|
+
logomark-sheet: 48px
|
|
81
|
+
components:
|
|
82
|
+
button-primary:
|
|
83
|
+
backgroundColor: '{colors.primary}'
|
|
84
|
+
textColor: '{colors.on-primary}'
|
|
85
|
+
typography: '{typography.label}'
|
|
86
|
+
rounded: '{rounded.lg}'
|
|
87
|
+
height: '{spacing.control-height}'
|
|
88
|
+
padding: 10px
|
|
89
|
+
button-primary-hover:
|
|
90
|
+
backgroundColor: '{colors.primary-hover}'
|
|
91
|
+
textColor: '{colors.on-primary}'
|
|
92
|
+
button-outline:
|
|
93
|
+
backgroundColor: '{colors.surface}'
|
|
94
|
+
textColor: '{colors.on-surface}'
|
|
95
|
+
typography: '{typography.label}'
|
|
96
|
+
rounded: '{rounded.lg}'
|
|
97
|
+
height: '{spacing.control-height}'
|
|
98
|
+
button-ghost:
|
|
99
|
+
textColor: '{colors.on-surface-weak}'
|
|
100
|
+
typography: '{typography.label}'
|
|
101
|
+
rounded: '{rounded.lg}'
|
|
102
|
+
height: '{spacing.control-height}'
|
|
103
|
+
button-link:
|
|
104
|
+
textColor: '{colors.link}'
|
|
105
|
+
typography: '{typography.label}'
|
|
106
|
+
height: '{spacing.control-height}'
|
|
107
|
+
button-disabled:
|
|
108
|
+
backgroundColor: '{colors.disabled-surface}'
|
|
109
|
+
textColor: '{colors.disabled-text}'
|
|
110
|
+
input:
|
|
111
|
+
backgroundColor: '{colors.surface}'
|
|
112
|
+
textColor: '{colors.on-surface}'
|
|
113
|
+
typography: '{typography.body}'
|
|
114
|
+
rounded: '{rounded.lg}'
|
|
115
|
+
height: '{spacing.control-height}'
|
|
116
|
+
padding: 10px
|
|
117
|
+
input-placeholder:
|
|
118
|
+
backgroundColor: '{colors.surface}'
|
|
119
|
+
textColor: '{colors.placeholder}'
|
|
120
|
+
input-code:
|
|
121
|
+
typography: '{typography.code}'
|
|
122
|
+
height: '{spacing.control-height}'
|
|
123
|
+
panel:
|
|
124
|
+
backgroundColor: '{colors.surface}'
|
|
125
|
+
textColor: '{colors.on-surface}'
|
|
126
|
+
rounded: '{rounded.xl}'
|
|
127
|
+
chrome:
|
|
128
|
+
backgroundColor: '{colors.surface-chrome}'
|
|
129
|
+
textColor: '{colors.on-surface}'
|
|
130
|
+
well:
|
|
131
|
+
backgroundColor: '{colors.surface-sunken}'
|
|
132
|
+
textColor: '{colors.on-surface-weak}'
|
|
133
|
+
sheet:
|
|
134
|
+
backgroundColor: '{colors.surface}'
|
|
135
|
+
textColor: '{colors.on-surface}'
|
|
136
|
+
rounded: '{rounded.xl}'
|
|
137
|
+
padding: '{spacing.sheet-padding}'
|
|
138
|
+
width: '{spacing.sheet-width}'
|
|
139
|
+
row-selected:
|
|
140
|
+
backgroundColor: '{colors.selected}'
|
|
141
|
+
textColor: '{colors.on-surface}'
|
|
142
|
+
tooltip:
|
|
143
|
+
backgroundColor: '{colors.inverse-surface}'
|
|
144
|
+
textColor: '{colors.inverse-on-surface}'
|
|
145
|
+
typography: '{typography.caption}'
|
|
146
|
+
rounded: '{rounded.md}'
|
|
147
|
+
alert-danger:
|
|
148
|
+
backgroundColor: '{colors.error-container}'
|
|
149
|
+
textColor: '{colors.on-surface}'
|
|
150
|
+
rounded: '{rounded.xl}'
|
|
151
|
+
field-error:
|
|
152
|
+
textColor: '{colors.error-text}'
|
|
153
|
+
typography: '{typography.body}'
|
|
154
|
+
button-destructive:
|
|
155
|
+
backgroundColor: '{colors.error}'
|
|
156
|
+
textColor: '{colors.on-primary}'
|
|
157
|
+
typography: '{typography.label}'
|
|
158
|
+
rounded: '{rounded.lg}'
|
|
159
|
+
status-warning:
|
|
160
|
+
backgroundColor: '{colors.warning-container}'
|
|
161
|
+
textColor: '{colors.warning-text}'
|
|
162
|
+
typography: '{typography.caption}'
|
|
163
|
+
rounded: '{rounded.pill}'
|
|
164
|
+
status-success:
|
|
165
|
+
backgroundColor: '{colors.success-container}'
|
|
166
|
+
textColor: '{colors.success-text}'
|
|
167
|
+
typography: '{typography.caption}'
|
|
168
|
+
rounded: '{rounded.pill}'
|
|
169
|
+
mono-label:
|
|
170
|
+
textColor: '{colors.placeholder}'
|
|
171
|
+
typography: '{typography.mono-label}'
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
# anfra design
|
|
175
|
+
|
|
176
|
+
## Overview
|
|
177
|
+
|
|
178
|
+
anfra's product UI is a working notebook on warm paper: ink for everything, one violet pen for the one thing the reader follows. It is a tool for analysts who read models, metrics and query results all day, so it is dense, calm and exact. Nothing glows, nothing floats without a reason, and no screen tries to impress.
|
|
179
|
+
|
|
180
|
+
- **Paper and ink first.** Paper chrome frames a white work panel. Text, rules and icons are ink.
|
|
181
|
+
- **One violet.** Violet marks the one primary action of a view, links, focus and selection. It is never decoration.
|
|
182
|
+
- **Drawn, not decorated.** Hairlines carry structure. Shadows only lift what floats.
|
|
183
|
+
- **One density.** Every screen uses the same control height, type scale and spacing.
|
|
184
|
+
|
|
185
|
+
**One language, two apps.** This file holds the rules every anfra screen follows, in anfra core (`anfra serve`'s pages in `web/appserve`, and the plugin UI the SDK draws in any host) and in anfra Cloud. It is public, and it is the source: anfra Cloud's `web/DESIGN.md` extends it with Cloud-only rules (its signed-out pages, its forms) and its Tailwind and shadcn-vue notes, and never restates or overrides a rule here. The brand's principles, logo and marketing pages live in the brand file (`holistics/anfra-landing`, `DESIGN.md` on `main`).
|
|
186
|
+
|
|
187
|
+
The front matter holds the light theme's values. The implementation is `tokens.css`, `fonts.css` and `type.css` beside this file, published as `@holistics/anfra-design`; it holds both themes. A change goes into both, here first.
|
|
188
|
+
|
|
189
|
+
## Colors
|
|
190
|
+
|
|
191
|
+
Colors are in `tokens.css`, in two tiers, after the Holistics Design System. A host adds its own names on top (a third tier), and never a color of its own.
|
|
192
|
+
|
|
193
|
+
| Tier | Names | Used by |
|
|
194
|
+
| --- | --- | --- |
|
|
195
|
+
| 1 Primitives | `--anfra-{ink,paper,violet,red,amber,green,white,black}-{step}`, OKLCH | Tier 2 only |
|
|
196
|
+
| 2 Semantic | `--anfra-color-{scope}-{semantic}-{state}`, scope = `background`, `text`, `icon`, `border`, `focus-ring` | Every component, in every host |
|
|
197
|
+
| 3 Host aliases | Cloud: Tailwind's `text-weak`, `bg-hover`, shadcn's `--primary`. appserve: its stylesheet | That host's components |
|
|
198
|
+
|
|
199
|
+
The same word is a different color for each scope: `--anfra-color-text-weak`, `--anfra-color-background-hover`, `--anfra-color-border-strong`, `--anfra-color-icon-weak`. Below, a token is named without its `--anfra-color-` prefix.
|
|
200
|
+
|
|
201
|
+
- **Paper** `background-base-default` {colors.surface-chrome} is the chrome: the sidebar and the frame around the panel. **White** `background-default` {colors.surface} is the work panel, cards and dialogs. **Sunken paper** `background-secondary-default` {colors.surface-sunken} is a well inside the panel: code, read-only fields, card footers.
|
|
202
|
+
- **Ink** `text-default` {colors.on-surface} carries titles, body text and values. **Weak ink** `text-weak` {colors.on-surface-weak} is secondary text and quiet controls. **Muted ink** `text-placeholder` {colors.placeholder} is the one muted color: descriptions, captions, muted labels and placeholders. There is no second muted color.
|
|
203
|
+
- **Violet** {colors.primary} is the one accent: `background-highlight-default` for the one filled button of a view, `text-highlight-default` or `text-link-default` {colors.link} for violet text. The violet wash `background-interactive-highlight-default` {colors.selected} marks a selected row or option, always with a checked control and `aria-selected`.
|
|
204
|
+
- **Status** is restrained red, amber and green; info is neutral ink, never blue or violet. A status always has a label or an icon, and never fills a large surface: `background-{danger,warning,success,info}-secondary-default` behind `text-{s}-default`.
|
|
205
|
+
- **Disabled** is `background-disabled` and `text-disabled`, plus `border-disabled` on a control with a border. Never lower the opacity instead.
|
|
206
|
+
- **Neutral states** are `background-hover` and `background-active`; they work on paper and on white.
|
|
207
|
+
- **Errors**: `text-danger-default` {colors.error-text} for error text; `background-danger-default` {colors.error} is the solid fill, never text.
|
|
208
|
+
- **Dark** redefines Tier 2 only, under `.dark` or `[data-theme="dark"]` on `<html>`. A host follows the system by default; light and dark are choices, stored per device.
|
|
209
|
+
|
|
210
|
+
## Typography
|
|
211
|
+
|
|
212
|
+
Inter for all text; Geist Mono for code, revisions, mono labels and names the user writes in code. Both are bundled (`fonts.css`, `--anfra-font-sans`, `--anfra-font-mono`), never loaded from a CDN: an on-prem install, or `anfra serve` on a laptop, may be offline.
|
|
213
|
+
|
|
214
|
+
A screen uses three sizes, 20, 14 and 12px: to add emphasis, change weight or color, not size. `type.css` has each role as a `font` shorthand (`font: var(--anfra-type-body)`).
|
|
215
|
+
|
|
216
|
+
| Role | Token | Size / leading | Weight | Use |
|
|
217
|
+
| --- | --- | --- | --- | --- |
|
|
218
|
+
| title | {typography.title} | 20 / 28px | 600 | The one heading of a page, a step or a dialog |
|
|
219
|
+
| heading | {typography.heading} | 14 / 20px | 600 | Section headings, card titles |
|
|
220
|
+
| body | {typography.body} | 14 / 20px | 400, 450 in dark | Descriptions, field text, alerts, list rows, menu items |
|
|
221
|
+
| label | {typography.label} | 14 / 20px | 500 | Buttons, links, field labels, the current page, names |
|
|
222
|
+
| caption | {typography.caption} | 12 / 16px | 400 | Dividers, notes under a button, roles, timestamps, tooltips, shortcuts |
|
|
223
|
+
| mono-label | {typography.mono-label} | 12 / 16px | 400 | Uppercase kinds and revisions |
|
|
224
|
+
|
|
225
|
+
- **No other weights**, except: caption at 500 for badges, status pills, group labels and initial tiles; 500 on a name inside a sentence; 500 on the current item of a nav.
|
|
226
|
+
- **A new role gets a new name**, never a size suffix (`heading`, not `body-lg`).
|
|
227
|
+
- **A name in a sentence** (an organization slug, an address) is Inter 500, never mono.
|
|
228
|
+
- Tabular numbers wherever numbers change or line up.
|
|
229
|
+
|
|
230
|
+
## Layout
|
|
231
|
+
|
|
232
|
+
One density for every screen, on a 4px unit {spacing.unit}.
|
|
233
|
+
|
|
234
|
+
- **Work screens**: the paper chrome holds the sidebar; the white panel is inset {spacing.panel-inset} on the paper, with a 14px radius, a 1px `border-default` and no shadow. The header bar is navigation (a breadcrumb); the page's subject is its own heading.
|
|
235
|
+
- **One control height**: {spacing.control-height} for every field and button.
|
|
236
|
+
- **A panel docked beside the work** (the plugins' panel) sits inside the white panel, behind a 1px `border-default`, with its tabs in a 48px header.
|
|
237
|
+
|
|
238
|
+
## Elevation & Depth
|
|
239
|
+
|
|
240
|
+
Depth comes from tone and hairlines: paper behind, white in front, 1px rules between. Shadows are neutral ink, never colored, and only two exist: `--anfra-e1` for a resting card, `--anfra-e2` for what floats (menus, popovers, dialogs). On dark, both become a border.
|
|
241
|
+
|
|
242
|
+
## Shapes
|
|
243
|
+
|
|
244
|
+
Soft, not round. Controls and surfaces nest by radius: the smaller the thing, the smaller the corner.
|
|
245
|
+
|
|
246
|
+
- `--anfra-radius-md` {rounded.md}: menu items, nav items, chips, tooltips.
|
|
247
|
+
- `--anfra-radius-lg` {rounded.lg}: buttons, fields, alerts.
|
|
248
|
+
- `--anfra-radius-xl` {rounded.xl}: cards, popovers, dialogs, the panel.
|
|
249
|
+
- `--anfra-radius-pill` {rounded.pill}: status pills and counters only, never buttons.
|
|
250
|
+
|
|
251
|
+
## Components
|
|
252
|
+
|
|
253
|
+
Each host builds these from its own toolkit (Cloud: shadcn-vue; appserve and the SDK: plain HTML and CSS), and each looks the same.
|
|
254
|
+
|
|
255
|
+
### Buttons
|
|
256
|
+
|
|
257
|
+
| Variant | Look | Use |
|
|
258
|
+
| --- | --- | --- |
|
|
259
|
+
| default | Violet fill {colors.primary}, white label | The one primary action of a view |
|
|
260
|
+
| outline | White, `border-strong`, ink label | Every other action that needs weight |
|
|
261
|
+
| ghost | No border, weak ink, `background-hover` on hover | Quiet actions: toolbar buttons, "Back", "Sign out" |
|
|
262
|
+
| link | Violet text, underline on hover | Task actions that do the job another way |
|
|
263
|
+
| destructive | Red fill {colors.error}, white label | A destructive action |
|
|
264
|
+
|
|
265
|
+
- Labels are the label role. Buttons are {spacing.control-height} high; a smaller button never carries an action in a form or a list row.
|
|
266
|
+
- A toggled toolbar button (a panel open, a mode on) shows `background-active` and `aria-pressed`.
|
|
267
|
+
- Every pressable control scales to 0.97 on press.
|
|
268
|
+
|
|
269
|
+
### Fields
|
|
270
|
+
|
|
271
|
+
- **Rest**: white, `border-field`, the body role, `text-placeholder` for the placeholder.
|
|
272
|
+
- **Focus**: no outline; the border turns violet (`border-highlight-strong`) and doubles to 2px.
|
|
273
|
+
- **Error**: the border is red (`border-danger-strong`) at rest and on focus, never violet. The message is `text-danger-default` under the field and clears as soon as the user types again.
|
|
274
|
+
|
|
275
|
+
### Surfaces and status
|
|
276
|
+
|
|
277
|
+
- **Current nav item**: on the paper, a white chip with a violet icon; in a nav inside the panel (tabs, settings), `background-active` and weight 500. Both carry `aria-current="page"` or `aria-selected`.
|
|
278
|
+
- **Alerts**: a tinted container with an icon and the body role.
|
|
279
|
+
- **Badges and status pills**: caption at 500, a label or an icon always beside the color.
|
|
280
|
+
- **Tooltips**: inverse ink (`background-inverted-default`, `text-inverted-default`), the caption role, `--anfra-radius-md`.
|
|
281
|
+
|
|
282
|
+
### Icons
|
|
283
|
+
|
|
284
|
+
Lucide, at 16px in controls and 14px in dense rows, `currentColor`, never filled. Core draws the same icons from their path data, so it carries no icon library.
|
|
285
|
+
|
|
286
|
+
### Logo
|
|
287
|
+
|
|
288
|
+
The product shows the logomark only: violet on light, the inverse on dark, at the top of the sidebar. Never set the mark beside typed "anfra".
|
|
289
|
+
|
|
290
|
+
## Do's and Don'ts
|
|
291
|
+
|
|
292
|
+
- **Do** use one filled violet button per view; every other action is outline, ghost or link.
|
|
293
|
+
- **Do** pick a type role for every text, and keep three sizes on a screen: 20, 14 and 12px.
|
|
294
|
+
- **Do** give every status a label or an icon; **don't** use red and green for good and bad in charts.
|
|
295
|
+
- **Do** keep every control {spacing.control-height} high.
|
|
296
|
+
- **Don't** lower opacity for disabled, or use a fill color as text.
|
|
297
|
+
- **Don't** add glows, gradients, glass, colored shadows or textures.
|
|
298
|
+
- **Don't** animate more than the properties that change, or for longer than 300ms on a control.
|
|
299
|
+
- **Don't** set the logomark beside typed "anfra".
|
|
300
|
+
- **Don't** add a color to a host: add a token here first.
|
|
301
|
+
|
|
302
|
+
## Motion
|
|
303
|
+
|
|
304
|
+
`--anfra-ease-out` for UI, under 300ms: 90ms press (scale to 0.97), 160ms hover, 220ms panels (`--anfra-t-press`, `--anfra-t-hover`, `--anfra-t-ui`). Menus and tooltips scale from 0.97, never slide. `prefers-reduced-motion` removes movement and keeps short fades.
|
|
305
|
+
|
|
306
|
+
## Content
|
|
307
|
+
|
|
308
|
+
- "anfra" is lowercase, even first in a sentence.
|
|
309
|
+
- Text of one sentence has no end period; two or more sentences keep all of theirs.
|
|
310
|
+
- Users read "organization", never "org", "tenant" or "workspace". Code and URLs keep `org`.
|
|
311
|
+
|
|
312
|
+
## Accessibility
|
|
313
|
+
|
|
314
|
+
- Contrast follows WCAG 2.2 AA: text 4.5:1; icons, field borders and the focus outline 3:1. A new token is measured in both themes before it ships.
|
|
315
|
+
- Focus is a 2px violet outline (`focus-ring-default`) offset 3px on everything focusable; a control keeps its own border. Text fields show focus on their border instead.
|
|
316
|
+
- Color never carries meaning alone: a status, an error or a met rule also has text or an icon.
|
|
317
|
+
|
|
318
|
+
## Implementation
|
|
319
|
+
|
|
320
|
+
- **Package**: `@holistics/anfra-design`, released with anfra at its version. `index.css` imports `fonts.css`, `tokens.css` and `type.css`.
|
|
321
|
+
- **anfra Cloud** imports it in `web/src/main.css` and maps Tier 2 onto Tailwind and shadcn's aliases there.
|
|
322
|
+
- **appserve** imports it in `web/appserve/src/style.css`; its stylesheet uses Tier 2 tokens only.
|
|
323
|
+
- **The SDK's plugin UI** reads the theme a host passes (`--anfra-color-bg` and the rest, `web/sdk/src/common/theme.ts`); a host takes those from Tier 2.
|
|
324
|
+
- **To change a rule or a token**: a PR here, with `tokens.css` and this file in step; then each host takes the release. A rule for one page goes in that page's spec, not here.
|
|
325
|
+
- **Checks**: `pnpm --filter @holistics/anfra-design test` (every reference resolves, dark redefines only Tier 2, only Tier 1 holds raw colors); `npx @google/design.md lint web/design/DESIGN.md`.
|
package/fonts.css
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Inter for all text, Geist Mono for code and names written in code. Bundled, never loaded from a
|
|
3
|
+
* CDN: an on-prem install, or `anfra serve` on a laptop, may be offline.
|
|
4
|
+
*/
|
|
5
|
+
@import '@fontsource-variable/inter';
|
|
6
|
+
@import '@fontsource-variable/geist-mono';
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--anfra-font-sans: 'Inter Variable', ui-sans-serif, system-ui, sans-serif;
|
|
10
|
+
--anfra-font-mono: 'Geist Mono Variable', ui-monospace, monospace;
|
|
11
|
+
}
|
package/index.css
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holistics/anfra-design",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.14.2",
|
|
4
|
+
"description": "anfra's design tokens, type and rules: one design language for anfra core (appserve, the SDK's plugin UI) and anfra Cloud",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/holistics/anfra.git",
|
|
9
|
+
"directory": "web/design"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./index.css",
|
|
14
|
+
"./index.css": "./index.css",
|
|
15
|
+
"./tokens.css": "./tokens.css",
|
|
16
|
+
"./fonts.css": "./fonts.css",
|
|
17
|
+
"./type.css": "./type.css",
|
|
18
|
+
"./DESIGN.md": "./DESIGN.md",
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"index.css",
|
|
23
|
+
"tokens.css",
|
|
24
|
+
"fonts.css",
|
|
25
|
+
"type.css",
|
|
26
|
+
"DESIGN.md"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "node --test"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@fontsource-variable/geist-mono": "^5.3.0",
|
|
33
|
+
"@fontsource-variable/inter": "^5.3.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/tokens.css
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* anfra's design tokens: the one source of colour, elevation and motion for anfra core (appserve,
|
|
3
|
+
* the SDK's plugin UI) and anfra Cloud. DESIGN.md beside this file says which token to use for what.
|
|
4
|
+
* Tier 1 primitives --anfra-{hue}-{step} raw OKLCH, never used by components
|
|
5
|
+
* Tier 2 semantic --anfra-color-{scope}-{semantic}-{state} scope = background | text | icon | border | focus-ring
|
|
6
|
+
* A host maps Tier 2 onto its own names (Cloud: Tailwind and shadcn's aliases; appserve: its stylesheet).
|
|
7
|
+
* Dark redefines Tier 2 only, under `.dark` (Cloud) or `[data-theme="dark"]` (appserve) on <html>.
|
|
8
|
+
* Moved from anfra-cloud web/src/main.css, values unchanged.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* ------------------------------------------------------------------ Tier 1: primitives */
|
|
12
|
+
:root {
|
|
13
|
+
--anfra-ink-0: oklch(1 0 0); /* #ffffff */
|
|
14
|
+
--anfra-ink-100: oklch(0.961 0.007 304.2); /* #f3f1f6 */
|
|
15
|
+
--anfra-ink-200: oklch(0.879 0.016 302.5); /* #d9d5e0 */
|
|
16
|
+
--anfra-ink-300: oklch(0.723 0.017 306.3); /* #a8a3ae */
|
|
17
|
+
--anfra-ink-400: oklch(0.679 0.024 300); /* #9a95a5 */
|
|
18
|
+
--anfra-ink-500: oklch(0.531 0.024 300.8); /* #6e6978 */
|
|
19
|
+
--anfra-ink-550: oklch(0.485 0.022 306.3); /* #625c69 */
|
|
20
|
+
--anfra-ink-600: oklch(0.47 0.023 301.8); /* #5d5866 */
|
|
21
|
+
--anfra-ink-700: oklch(0.392 0.021 304.3); /* #48434f */
|
|
22
|
+
--anfra-ink-750: oklch(0.343 0.025 298.2); /* #3a3644 */
|
|
23
|
+
--anfra-ink-800: oklch(0.286 0.021 301.7); /* #2c2833 */
|
|
24
|
+
--anfra-ink-850: oklch(0.251 0.017 300.4); /* #232029 */
|
|
25
|
+
--anfra-ink-875: oklch(0.223 0.014 298.3); /* #1c1a21 */
|
|
26
|
+
--anfra-ink-900: oklch(0.201 0.022 301.1); /* #18141f */
|
|
27
|
+
--anfra-ink-950: oklch(0.176 0.008 297); /* #111014 */
|
|
28
|
+
--anfra-ink-1000: oklch(0.157 0.009 296.9); /* #0d0c10 */
|
|
29
|
+
--anfra-ink-a4: oklch(0.201 0.022 301.1 / 0.04); /* #18141f @ 4% */
|
|
30
|
+
--anfra-ink-a5: oklch(0.201 0.022 301.1 / 0.05); /* #18141f @ 5% */
|
|
31
|
+
--anfra-ink-a8: oklch(0.201 0.022 301.1 / 0.08); /* #18141f @ 8% */
|
|
32
|
+
--anfra-ink-a9: oklch(0.201 0.022 301.1 / 0.09); /* #18141f @ 9% */
|
|
33
|
+
--anfra-ink-a12: oklch(0.201 0.022 301.1 / 0.12); /* #18141f @ 12% */
|
|
34
|
+
--anfra-ink-a24: oklch(0.201 0.022 301.1 / 0.24); /* #18141f @ 24% */
|
|
35
|
+
--anfra-ink-a40: oklch(0.201 0.022 301.1 / 0.4); /* #18141f @ 40% */
|
|
36
|
+
--anfra-ink-a48: oklch(0.201 0.022 301.1 / 0.48); /* #18141f @ 48% */
|
|
37
|
+
|
|
38
|
+
--anfra-white-a4: oklch(1 0 0 / 0.04); /* #ffffff @ 4% */
|
|
39
|
+
--anfra-white-a6: oklch(1 0 0 / 0.06); /* #ffffff @ 6% */
|
|
40
|
+
--anfra-white-a8: oklch(1 0 0 / 0.08); /* #ffffff @ 8% */
|
|
41
|
+
--anfra-white-a10: oklch(1 0 0 / 0.1); /* #ffffff @ 10% */
|
|
42
|
+
|
|
43
|
+
--anfra-black-a60: oklch(0 0 0 / 0.6); /* #000000 @ 60% */
|
|
44
|
+
|
|
45
|
+
--anfra-paper-25: oklch(0.985 0.004 91.4); /* #fbfaf7 */
|
|
46
|
+
--anfra-paper-50: oklch(0.973 0.005 95.1); /* #f7f6f2 */
|
|
47
|
+
--anfra-paper-100: oklch(0.955 0.007 88.6); /* #f2f0eb */
|
|
48
|
+
--anfra-paper-200: oklch(0.925 0.01 87.5); /* #e9e6df */
|
|
49
|
+
|
|
50
|
+
--anfra-violet-100: oklch(0.946 0.027 304.8); /* #f1e9fc */
|
|
51
|
+
--anfra-violet-200: oklch(0.904 0.049 303.6); /* #e6d8fb */
|
|
52
|
+
--anfra-violet-300: oklch(0.878 0.072 302.8); /* #e0ccff */
|
|
53
|
+
--anfra-violet-400: oklch(0.794 0.124 300.7); /* #c9a9ff */
|
|
54
|
+
--anfra-violet-500: oklch(0.66 0.18 298.5); /* #a274f0 */
|
|
55
|
+
--anfra-violet-600: oklch(0.565 0.194 300.3); /* #8a51d4 */
|
|
56
|
+
--anfra-violet-700: oklch(0.517 0.192 299.1); /* #7a43c4 */
|
|
57
|
+
--anfra-violet-800: oklch(0.484 0.181 298.1); /* #6e3db5 */
|
|
58
|
+
--anfra-violet-900: oklch(0.386 0.146 297.6); /* #4f2a86 */
|
|
59
|
+
--anfra-violet-a18: oklch(0.565 0.194 300.3 / 0.18); /* #8a51d4 @ 18% */
|
|
60
|
+
--anfra-violet-a26: oklch(0.565 0.194 300.3 / 0.26); /* #8a51d4 @ 26% */
|
|
61
|
+
--anfra-violet-a40: oklch(0.565 0.194 300.3 / 0.4); /* #8a51d4 @ 40% */
|
|
62
|
+
|
|
63
|
+
--anfra-red-50: oklch(0.971 0.014 22.8); /* #fff2f1 */
|
|
64
|
+
--anfra-red-200: oklch(0.871 0.061 27.2); /* #fac6bf */
|
|
65
|
+
--anfra-red-300: oklch(0.779 0.121 27); /* #fb988d */
|
|
66
|
+
--anfra-red-400: oklch(0.7 0.171 27); /* #f66d62 */
|
|
67
|
+
--anfra-red-500: oklch(0.549 0.199 27.1); /* #cc2827 */
|
|
68
|
+
--anfra-red-700: oklch(0.501 0.17 27.2); /* #b02b27 */
|
|
69
|
+
--anfra-red-900: oklch(0.361 0.094 23.9); /* #662524 */
|
|
70
|
+
--anfra-red-950: oklch(0.239 0.039 12.4); /* #2f171a */
|
|
71
|
+
|
|
72
|
+
--anfra-amber-50: oklch(0.973 0.028 84.6); /* #fff5e1 */
|
|
73
|
+
--anfra-amber-200: oklch(0.881 0.08 78.2); /* #f5d29c */
|
|
74
|
+
--anfra-amber-300: oklch(0.84 0.12 69.6); /* #fdbc6f */
|
|
75
|
+
--anfra-amber-400: oklch(0.8 0.15 70.5); /* #faab3f */
|
|
76
|
+
--anfra-amber-500: oklch(0.64 0.139 69.5); /* #c17a00 */
|
|
77
|
+
--anfra-amber-700: oklch(0.501 0.1 70.3); /* #875814 */
|
|
78
|
+
--anfra-amber-900: oklch(0.427 0.072 72.5); /* #67481d */
|
|
79
|
+
--anfra-amber-950: oklch(0.267 0.028 66.2); /* #2f2317 */
|
|
80
|
+
|
|
81
|
+
--anfra-green-50: oklch(0.972 0.021 152.2); /* #ecfaef */
|
|
82
|
+
--anfra-green-200: oklch(0.87 0.06 151.8); /* #b8e0c1 */
|
|
83
|
+
--anfra-green-300: oklch(0.8 0.12 151.9); /* #7fd497 */
|
|
84
|
+
--anfra-green-400: oklch(0.721 0.15 151.9); /* #4dbf74 */
|
|
85
|
+
--anfra-green-500: oklch(0.559 0.13 152); /* #26894c */
|
|
86
|
+
--anfra-green-600: oklch(0.53 0.121 151.9); /* #267f47 */
|
|
87
|
+
--anfra-green-700: oklch(0.479 0.1 151.8); /* #296d40 */
|
|
88
|
+
--anfra-green-900: oklch(0.394 0.069 155.6); /* #235136 */
|
|
89
|
+
--anfra-green-950: oklch(0.256 0.025 165.3); /* #172720 */
|
|
90
|
+
/* dark v2 additions */
|
|
91
|
+
--anfra-ink-250: oklch(
|
|
92
|
+
0.835 0.018 300
|
|
93
|
+
); /* #cac6d3 dark placeholder text (descriptions, captions), Lc 70+ on chrome/panel/card/raised */
|
|
94
|
+
--anfra-ink-450: oklch(
|
|
95
|
+
0.58 0.022 300
|
|
96
|
+
); /* #7c7886 dark field border, >= 3.59:1 on all dark grounds */
|
|
97
|
+
--anfra-ink-825: oklch(0.262 0.017 300); /* #26232c dark raised surface, current chip */
|
|
98
|
+
--anfra-ink-925: oklch(0.19 0.012 300); /* #151318 dark work panel */
|
|
99
|
+
--anfra-violet-350: oklch(0.845 0.085 300); /* #d4c0fc dark violet text / link */
|
|
100
|
+
--anfra-red-250: oklch(0.82 0.09 27); /* #f9aea5 dark danger text */
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ------------------------------------------------------------------ Tier 2: semantic, light (:root) */
|
|
104
|
+
:root {
|
|
105
|
+
color-scheme: light;
|
|
106
|
+
|
|
107
|
+
--anfra-color-background-default: var(
|
|
108
|
+
--anfra-ink-0
|
|
109
|
+
); /* Work panel (inset main area), page default */
|
|
110
|
+
--anfra-color-background-base-default: var(--anfra-paper-100); /* App chrome and sidebar ground */
|
|
111
|
+
--anfra-color-background-secondary-default: var(
|
|
112
|
+
--anfra-paper-50
|
|
113
|
+
); /* Sunken area in the panel: code, read-only field, well, card footer */
|
|
114
|
+
--anfra-color-background-card-default: var(
|
|
115
|
+
--anfra-ink-0
|
|
116
|
+
); /* Card in the panel (light: white + border-default) */
|
|
117
|
+
--anfra-color-background-raised-default: var(
|
|
118
|
+
--anfra-ink-0
|
|
119
|
+
); /* Popover, menu, dialog, sheet, toast (+ border-strong + shadow-e2) */
|
|
120
|
+
--anfra-color-background-current-default: var(
|
|
121
|
+
--anfra-ink-0
|
|
122
|
+
); /* Current nav item chip on the chrome */
|
|
123
|
+
--anfra-color-background-hover: var(
|
|
124
|
+
--anfra-ink-a5
|
|
125
|
+
); /* Neutral hover layer (works on paper and on white) */
|
|
126
|
+
--anfra-color-background-active: var(--anfra-ink-a9); /* Neutral pressed layer; open trigger */
|
|
127
|
+
--anfra-color-background-disabled: var(
|
|
128
|
+
--anfra-ink-a4
|
|
129
|
+
); /* Disabled control fill (all variants, never violet) */
|
|
130
|
+
--anfra-color-background-inverted-default: var(--anfra-ink-900); /* Tooltip, kbd hint */
|
|
131
|
+
--anfra-color-background-interactive-highlight-default: var(
|
|
132
|
+
--anfra-violet-100
|
|
133
|
+
); /* Selected row / option / cell (violet wash) */
|
|
134
|
+
--anfra-color-background-interactive-highlight-hover: var(
|
|
135
|
+
--anfra-violet-200
|
|
136
|
+
); /* Hover on a selected item */
|
|
137
|
+
--anfra-color-background-interactive-overlay: var(
|
|
138
|
+
--anfra-ink-a40
|
|
139
|
+
); /* Scrim behind dialog and sheet */
|
|
140
|
+
--anfra-color-background-skeleton: var(--anfra-ink-a5); /* Skeleton block */
|
|
141
|
+
--anfra-color-background-highlight-default: var(--anfra-violet-600); /* Primary (violet) fill */
|
|
142
|
+
--anfra-color-background-highlight-hover: var(--anfra-violet-700); /* Primary fill hover */
|
|
143
|
+
--anfra-color-background-highlight-active: var(--anfra-violet-800); /* Primary fill pressed */
|
|
144
|
+
--anfra-color-background-highlight-secondary-default: var(
|
|
145
|
+
--anfra-violet-100
|
|
146
|
+
); /* Subtle violet: drop target, checked choice card */
|
|
147
|
+
--anfra-color-background-highlight-secondary-hover: var(
|
|
148
|
+
--anfra-violet-200
|
|
149
|
+
); /* Subtle violet hover */
|
|
150
|
+
--anfra-color-background-danger-default: var(--anfra-red-500); /* Destructive button fill */
|
|
151
|
+
--anfra-color-background-danger-hover: var(--anfra-red-700); /* Destructive fill hover/pressed */
|
|
152
|
+
--anfra-color-background-danger-secondary-default: var(
|
|
153
|
+
--anfra-red-50
|
|
154
|
+
); /* Danger alert/badge bg; destructive menu item highlight */
|
|
155
|
+
--anfra-color-background-warning-secondary-default: var(
|
|
156
|
+
--anfra-amber-50
|
|
157
|
+
); /* Warning alert/badge bg */
|
|
158
|
+
--anfra-color-background-success-default: var(
|
|
159
|
+
--anfra-green-600
|
|
160
|
+
); /* Success solid (small badge/dot only) */
|
|
161
|
+
--anfra-color-background-success-secondary-default: var(
|
|
162
|
+
--anfra-green-50
|
|
163
|
+
); /* Success alert/badge bg */
|
|
164
|
+
--anfra-color-background-info-secondary-default: var(
|
|
165
|
+
--anfra-ink-a5
|
|
166
|
+
); /* Info alert/badge bg (info = neutral) */
|
|
167
|
+
--anfra-color-background-selection: var(--anfra-violet-200); /* ::selection background */
|
|
168
|
+
|
|
169
|
+
--anfra-color-text-default: var(--anfra-ink-900); /* Headings, body, values */
|
|
170
|
+
--anfra-color-text-weak: var(--anfra-ink-700); /* Secondary text, nav item at rest, alert body */
|
|
171
|
+
--anfra-color-text-placeholder: var(
|
|
172
|
+
--anfra-ink-550
|
|
173
|
+
); /* Descriptions, captions, muted labels, input placeholder */
|
|
174
|
+
--anfra-color-text-disabled: var(--anfra-ink-300); /* Disabled label (WCAG-exempt) */
|
|
175
|
+
--anfra-color-text-highlight-default: var(
|
|
176
|
+
--anfra-violet-800
|
|
177
|
+
); /* Violet text (= --primary-text) */
|
|
178
|
+
--anfra-color-text-link-default: var(--anfra-violet-800); /* Links */
|
|
179
|
+
--anfra-color-text-link-hover: var(--anfra-violet-900); /* Link hover */
|
|
180
|
+
--anfra-color-text-on-fill: var(--anfra-ink-0); /* Text on violet / danger / success solid */
|
|
181
|
+
--anfra-color-text-inverted-default: var(
|
|
182
|
+
--anfra-ink-100
|
|
183
|
+
); /* Text on background-inverted-default */
|
|
184
|
+
--anfra-color-text-danger-default: var(
|
|
185
|
+
--anfra-red-700
|
|
186
|
+
); /* Error message, destructive item text */
|
|
187
|
+
--anfra-color-text-warning-default: var(--anfra-amber-700); /* Warning text */
|
|
188
|
+
--anfra-color-text-success-default: var(--anfra-green-700); /* Success text */
|
|
189
|
+
--anfra-color-text-info-default: var(--anfra-ink-700); /* Info text (neutral) */
|
|
190
|
+
--anfra-color-text-selection: var(--anfra-ink-900); /* ::selection text */
|
|
191
|
+
|
|
192
|
+
--anfra-color-icon-default: var(--anfra-ink-700); /* Icons at rest */
|
|
193
|
+
--anfra-color-icon-weak: var(--anfra-ink-550); /* Secondary icons, chevrons */
|
|
194
|
+
--anfra-color-icon-hover: var(--anfra-ink-900); /* Icon on hover */
|
|
195
|
+
--anfra-color-icon-disabled: var(--anfra-ink-300); /* Disabled icon (exempt) */
|
|
196
|
+
--anfra-color-icon-highlight-default: var(
|
|
197
|
+
--anfra-violet-600
|
|
198
|
+
); /* Current nav icon, checked mark */
|
|
199
|
+
--anfra-color-icon-on-fill: var(--anfra-ink-0); /* Icon on solid fills */
|
|
200
|
+
--anfra-color-icon-inverted-default: var(--anfra-ink-100); /* Icon on inverted bg */
|
|
201
|
+
--anfra-color-icon-danger-default: var(--anfra-red-500); /* Danger icon */
|
|
202
|
+
--anfra-color-icon-warning-default: var(--anfra-amber-500); /* Warning icon */
|
|
203
|
+
--anfra-color-icon-success-default: var(--anfra-green-500); /* Success icon */
|
|
204
|
+
--anfra-color-icon-info-default: var(--anfra-ink-550); /* Info icon (neutral) */
|
|
205
|
+
|
|
206
|
+
--anfra-color-border-default: var(
|
|
207
|
+
--anfra-ink-a12
|
|
208
|
+
); /* Hairlines, card edge, dividers (decorative) */
|
|
209
|
+
--anfra-color-border-weak: var(--anfra-ink-a8); /* Row dividers, current chip edge (decorative) */
|
|
210
|
+
--anfra-color-border-strong: var(
|
|
211
|
+
--anfra-ink-a24
|
|
212
|
+
); /* Frames: popover, dialog, outline button, inset panel edge */
|
|
213
|
+
--anfra-color-border-hover: var(--anfra-ink-550); /* Field / outline button border on hover */
|
|
214
|
+
--anfra-color-border-field: var(
|
|
215
|
+
--anfra-ink-a48
|
|
216
|
+
); /* Input, checkbox, switch track boundary (3:1) */
|
|
217
|
+
--anfra-color-border-disabled: var(--anfra-ink-a12); /* Disabled control border */
|
|
218
|
+
--anfra-color-border-highlight-default: var(--anfra-violet-200); /* Subtle violet edge */
|
|
219
|
+
--anfra-color-border-highlight-strong: var(
|
|
220
|
+
--anfra-violet-600
|
|
221
|
+
); /* Selected edge, tab indicator, checked choice card (3:1) */
|
|
222
|
+
--anfra-color-border-danger-default: var(--anfra-red-200); /* Danger alert edge */
|
|
223
|
+
--anfra-color-border-danger-strong: var(--anfra-red-500); /* Invalid field (3:1) */
|
|
224
|
+
--anfra-color-border-warning-default: var(--anfra-amber-200); /* Warning alert edge */
|
|
225
|
+
--anfra-color-border-success-default: var(--anfra-green-200); /* Success alert edge */
|
|
226
|
+
|
|
227
|
+
--anfra-color-focus-ring-default: var(--anfra-violet-600); /* 2px focus outline, offset 3px */
|
|
228
|
+
|
|
229
|
+
/* Elevation (light): shadows. */
|
|
230
|
+
--anfra-e1: 0 1px 0 rgb(24 20 31 / 0.04), 0 1px 2px rgb(24 20 31 / 0.06);
|
|
231
|
+
--anfra-e2:
|
|
232
|
+
0 1px 0 rgb(24 20 31 / 0.03), 0 18px 40px -18px rgb(24 20 31 / 0.28),
|
|
233
|
+
0 2px 6px -2px rgb(24 20 31 / 0.08);
|
|
234
|
+
|
|
235
|
+
/* Motion (DESIGN.md §10). Unchanged. */
|
|
236
|
+
--anfra-t-press: 90ms;
|
|
237
|
+
--anfra-t-hover: 160ms;
|
|
238
|
+
--anfra-t-ui: 220ms;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ------------------------------------------------------------------ Tier 2: semantic, dark (.dark or [data-theme="dark"]) */
|
|
242
|
+
.dark,
|
|
243
|
+
[data-theme="dark"] {
|
|
244
|
+
color-scheme: dark;
|
|
245
|
+
|
|
246
|
+
--anfra-color-background-default: var(
|
|
247
|
+
--anfra-ink-925
|
|
248
|
+
); /* was ink-950: chrome -> panel dL 0.019 -> 0.033 */
|
|
249
|
+
--anfra-color-background-base-default: var(--anfra-ink-1000);
|
|
250
|
+
--anfra-color-background-secondary-default: var(--anfra-ink-1000);
|
|
251
|
+
--anfra-color-background-card-default: var(--anfra-ink-875);
|
|
252
|
+
--anfra-color-background-raised-default: var(
|
|
253
|
+
--anfra-ink-825
|
|
254
|
+
); /* was ink-850: card -> raised dL 0.028 -> 0.039 */
|
|
255
|
+
--anfra-color-background-current-default: var(
|
|
256
|
+
--anfra-ink-825
|
|
257
|
+
); /* was ink-875 (= nav hover color) */
|
|
258
|
+
--anfra-color-background-hover: var(--anfra-white-a6);
|
|
259
|
+
--anfra-color-background-active: var(--anfra-white-a10);
|
|
260
|
+
--anfra-color-background-disabled: var(--anfra-white-a4);
|
|
261
|
+
--anfra-color-background-inverted-default: var(--anfra-ink-100);
|
|
262
|
+
--anfra-color-background-interactive-highlight-default: var(--anfra-violet-a18);
|
|
263
|
+
--anfra-color-background-interactive-highlight-hover: var(--anfra-violet-a26);
|
|
264
|
+
--anfra-color-background-interactive-overlay: var(--anfra-black-a60);
|
|
265
|
+
--anfra-color-background-skeleton: var(--anfra-white-a6);
|
|
266
|
+
--anfra-color-background-highlight-secondary-default: var(--anfra-violet-a18);
|
|
267
|
+
--anfra-color-background-highlight-secondary-hover: var(--anfra-violet-a26);
|
|
268
|
+
--anfra-color-background-danger-secondary-default: var(--anfra-red-950);
|
|
269
|
+
--anfra-color-background-warning-secondary-default: var(--anfra-amber-950);
|
|
270
|
+
--anfra-color-background-success-secondary-default: var(--anfra-green-950);
|
|
271
|
+
--anfra-color-background-info-secondary-default: var(--anfra-white-a6);
|
|
272
|
+
--anfra-color-background-selection: var(--anfra-violet-a40);
|
|
273
|
+
|
|
274
|
+
--anfra-color-text-default: var(--anfra-ink-100);
|
|
275
|
+
--anfra-color-text-weak: var(--anfra-ink-200);
|
|
276
|
+
--anfra-color-text-placeholder: var(--anfra-ink-250); /* was ink-400: Lc 45 -> 72 */
|
|
277
|
+
--anfra-color-text-disabled: var(--anfra-ink-500); /* was ink-600 (exempt) */
|
|
278
|
+
--anfra-color-text-highlight-default: var(--anfra-violet-350); /* was violet-400: Lc 63 -> 73 */
|
|
279
|
+
--anfra-color-text-link-default: var(--anfra-violet-350); /* was violet-400 */
|
|
280
|
+
--anfra-color-text-link-hover: var(--anfra-violet-300);
|
|
281
|
+
--anfra-color-text-inverted-default: var(--anfra-ink-900);
|
|
282
|
+
--anfra-color-text-danger-default: var(--anfra-red-250); /* was red-300: Lc 60 -> 68 */
|
|
283
|
+
--anfra-color-text-warning-default: var(--anfra-amber-300);
|
|
284
|
+
--anfra-color-text-success-default: var(--anfra-green-300);
|
|
285
|
+
--anfra-color-text-info-default: var(--anfra-ink-200);
|
|
286
|
+
--anfra-color-text-selection: var(--anfra-ink-100);
|
|
287
|
+
|
|
288
|
+
--anfra-color-icon-default: var(--anfra-ink-200);
|
|
289
|
+
--anfra-color-icon-weak: var(--anfra-ink-300); /* was ink-400 */
|
|
290
|
+
--anfra-color-icon-hover: var(--anfra-ink-100);
|
|
291
|
+
--anfra-color-icon-disabled: var(--anfra-ink-500); /* was ink-600 (exempt) */
|
|
292
|
+
--anfra-color-icon-highlight-default: var(--anfra-violet-500);
|
|
293
|
+
--anfra-color-icon-inverted-default: var(--anfra-ink-900);
|
|
294
|
+
--anfra-color-icon-danger-default: var(--anfra-red-400);
|
|
295
|
+
--anfra-color-icon-warning-default: var(--anfra-amber-400);
|
|
296
|
+
--anfra-color-icon-success-default: var(--anfra-green-400);
|
|
297
|
+
--anfra-color-icon-info-default: var(--anfra-ink-300); /* was ink-400 */
|
|
298
|
+
|
|
299
|
+
--anfra-color-border-default: var(--anfra-ink-750); /* was ink-800: card edge 1.20 -> 1.47:1 */
|
|
300
|
+
--anfra-color-border-weak: var(--anfra-white-a8); /* was white-a6 */
|
|
301
|
+
--anfra-color-border-strong: var(--anfra-ink-700); /* was ink-750 */
|
|
302
|
+
--anfra-color-border-hover: var(--anfra-ink-400);
|
|
303
|
+
--anfra-color-border-field: var(
|
|
304
|
+
--anfra-ink-450
|
|
305
|
+
); /* was ink-500: 3.02 -> 3.59:1 min on rest grounds */
|
|
306
|
+
--anfra-color-border-disabled: var(--anfra-white-a8);
|
|
307
|
+
--anfra-color-border-highlight-default: var(--anfra-violet-a40);
|
|
308
|
+
--anfra-color-border-highlight-strong: var(--anfra-violet-500);
|
|
309
|
+
--anfra-color-border-danger-default: var(--anfra-red-900);
|
|
310
|
+
--anfra-color-border-danger-strong: var(--anfra-red-400);
|
|
311
|
+
--anfra-color-border-warning-default: var(--anfra-amber-900);
|
|
312
|
+
--anfra-color-border-success-default: var(--anfra-green-900);
|
|
313
|
+
|
|
314
|
+
--anfra-color-focus-ring-default: var(--anfra-violet-500);
|
|
315
|
+
|
|
316
|
+
/* A shadow does not show on dark: lift with a border instead (DESIGN.md §6). */
|
|
317
|
+
--anfra-e1: 0 0 0 1px var(--anfra-color-border-default);
|
|
318
|
+
--anfra-e2: 0 0 0 1px var(--anfra-color-border-strong);
|
|
319
|
+
}
|
package/type.css
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The type roles (DESIGN.md, Typography) as `font` shorthands, for hosts without Tailwind:
|
|
3
|
+
* `font: var(--anfra-type-body)`. A screen uses three sizes, 20, 14 and 12px. Shape and spacing
|
|
4
|
+
* sit here too, so plain CSS has every scale DESIGN.md names.
|
|
5
|
+
*/
|
|
6
|
+
:root {
|
|
7
|
+
--anfra-type-title: 600 1.25rem/1.75rem var(--anfra-font-sans);
|
|
8
|
+
--anfra-type-heading: 600 0.875rem/1.25rem var(--anfra-font-sans);
|
|
9
|
+
--anfra-type-body: 400 0.875rem/1.25rem var(--anfra-font-sans);
|
|
10
|
+
--anfra-type-label: 500 0.875rem/1.25rem var(--anfra-font-sans);
|
|
11
|
+
--anfra-type-caption: 400 0.75rem/1rem var(--anfra-font-sans);
|
|
12
|
+
--anfra-type-mono-label: 400 0.75rem/1rem var(--anfra-font-mono);
|
|
13
|
+
|
|
14
|
+
/* Shapes: the smaller the thing, the smaller the corner. */
|
|
15
|
+
--anfra-radius-md: 6px; /* menu items, nav items, chips, tooltips */
|
|
16
|
+
--anfra-radius-lg: 10px; /* buttons, fields, alerts */
|
|
17
|
+
--anfra-radius-xl: 14px; /* cards, popovers, dialogs, the panel */
|
|
18
|
+
--anfra-radius-pill: 9999px; /* status pills and counters only */
|
|
19
|
+
|
|
20
|
+
/* Spacing, on a 4px unit. */
|
|
21
|
+
--anfra-space-unit: 4px;
|
|
22
|
+
--anfra-control-height: 32px;
|
|
23
|
+
--anfra-field-gap: 8px; /* a label and its field */
|
|
24
|
+
--anfra-form-gap: 24px; /* one field and the next */
|
|
25
|
+
--anfra-panel-inset: 8px;
|
|
26
|
+
--anfra-sheet-padding: 24px;
|
|
27
|
+
--anfra-sheet-width: 384px;
|
|
28
|
+
--anfra-logomark-sheet: 48px; /* the logomark atop a sheet */
|
|
29
|
+
|
|
30
|
+
/* Motion: under 300ms on a control. */
|
|
31
|
+
--anfra-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
32
|
+
--anfra-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
33
|
+
}
|
package/README.md
DELETED