@adminiumjs/tokens 0.1.0-rc.1 → 0.1.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/LICENSES/FONTS.md +1 -1
- package/dist/index.d.ts +35 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/dist/pre-hydration.d.ts +1 -1
- package/dist/pre-hydration.js +1 -1
- package/package.json +1 -1
- package/src/accents.css +114 -13
- package/src/density.css +1 -1
- package/src/exceptions.css +45 -13
- package/src/fonts.css +1 -1
- package/src/index.ts +40 -8
- package/src/motion.css +1 -1
- package/src/pre-hydration.ts +1 -1
- package/src/tailwind.css +1 -1
- package/src/tokens.css +66 -10
- package/src/viz.css +1 -1
package/LICENSES/FONTS.md
CHANGED
|
@@ -14,4 +14,4 @@ and applies to the copies in `src/fonts/`. The fonts are unmodified upstream bui
|
|
|
14
14
|
permits bundling and redistribution with attribution and prohibits selling the fonts standalone.
|
|
15
15
|
|
|
16
16
|
CJK locales (`zh_CN`/`zh_TW`) intentionally use system font stacks (see `src/fonts.css`) and vendor
|
|
17
|
-
no CJK fonts — see
|
|
17
|
+
no CJK fonts — see 02-design-system.md §2.4 and 11-electron.md Open decisions.
|
package/dist/index.d.ts
CHANGED
|
@@ -2,26 +2,53 @@
|
|
|
2
2
|
* @adminium/tokens — JS-side constants for the four theming axes plus the pre-hydration
|
|
3
3
|
* script. CSS custom properties live in the sibling .css files; these exports exist so
|
|
4
4
|
* ThemeProvider, Storybook toolbars, charts and the desktop shell never hard-code axis
|
|
5
|
-
* values. See
|
|
5
|
+
* values. See 02-design-system.md §2.5.
|
|
6
6
|
*/
|
|
7
7
|
/** Theme axis. `system` resolves via `matchMedia("(prefers-color-scheme: dark)")`. */
|
|
8
8
|
export declare const THEMES: readonly ["light", "dark", "system"];
|
|
9
9
|
export type ThemePref = (typeof THEMES)[number];
|
|
10
10
|
/** A resolved theme as stamped on `<html data-theme>`. */
|
|
11
11
|
export type ResolvedTheme = Exclude<ThemePref, "system">;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Accent axis: the 8 switchable palettes (`data-accent`), name → LIGHT-theme hex
|
|
14
|
+
* (`--accent-light` in accents.css).
|
|
15
|
+
*
|
|
16
|
+
* This is ONE HALF of the accent. Each palette also has an `--accent-dark` hex that the dark
|
|
17
|
+
* theme selects into `--accent`, and it is a different colour, drastically so for `black`
|
|
18
|
+
* (#111111 light, #c9c9d4 dark). Anything that PAINTS an accent must therefore either read the
|
|
19
|
+
* CSS variable — which already resolves per theme — or pick from {@link ACCENTS_DARK} when the
|
|
20
|
+
* resolved theme is dark. Rendering `ACCENTS[a]` unconditionally shows the wrong colour on dark;
|
|
21
|
+
* that is what the accent-picker swatch used to do.
|
|
22
|
+
*/
|
|
13
23
|
export declare const ACCENTS: {
|
|
14
24
|
readonly indigo: "#4f46e5";
|
|
15
|
-
readonly blue: "#
|
|
16
|
-
readonly teal: "#
|
|
17
|
-
readonly violet: "#
|
|
18
|
-
readonly rose: "#
|
|
19
|
-
readonly red: "#
|
|
20
|
-
readonly orange: "#
|
|
25
|
+
readonly blue: "#1c59e0";
|
|
26
|
+
readonly teal: "#007167";
|
|
27
|
+
readonly violet: "#7936e9";
|
|
28
|
+
readonly rose: "#c40039";
|
|
29
|
+
readonly red: "#c0202f";
|
|
30
|
+
readonly orange: "#b03e00";
|
|
21
31
|
readonly black: "#111111";
|
|
22
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The dark half (`--accent-dark`). Derived from the light ramp by recipe — see the header of
|
|
35
|
+
* accents.css, which owns the values; these mirror them for JS that cannot read CSS (chart
|
|
36
|
+
* canvases, the desktop shell, docs tables).
|
|
37
|
+
*/
|
|
38
|
+
export declare const ACCENTS_DARK: {
|
|
39
|
+
readonly indigo: "#99a5ff";
|
|
40
|
+
readonly blue: "#7fabff";
|
|
41
|
+
readonly teal: "#49bbae";
|
|
42
|
+
readonly violet: "#b39dff";
|
|
43
|
+
readonly rose: "#ff848c";
|
|
44
|
+
readonly red: "#ff8582";
|
|
45
|
+
readonly orange: "#ff885b";
|
|
46
|
+
readonly black: "#c9c9d4";
|
|
47
|
+
};
|
|
23
48
|
/** `indigo` is the default. */
|
|
24
49
|
export type Accent = keyof typeof ACCENTS;
|
|
50
|
+
/** The accent hex actually painted for a resolved theme. */
|
|
51
|
+
export declare function accentHex(accent: Accent, theme: ResolvedTheme): string;
|
|
25
52
|
/** Density axis (`data-density`). */
|
|
26
53
|
export declare const DENSITIES: readonly ["comfortable", "compact"];
|
|
27
54
|
export type Density = (typeof DENSITIES)[number];
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sFAAsF;AACtF,eAAO,MAAM,MAAM,sCAAuC,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAChD,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEzD
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sFAAsF;AACtF,eAAO,MAAM,MAAM,sCAAuC,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAChD,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO;;;;;;;;;CASV,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAC;AAEX,+BAA+B;AAC/B,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,OAAO,CAAC;AAE1C,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAEtE;AAED,qCAAqC;AACrC,eAAO,MAAM,SAAS,qCAAsC,CAAC;AAC7D,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,4EAA4E;AAC5E,eAAO,MAAM,IAAI,yBAA0B,CAAC;AAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAExC,mFAAmF;AACnF,eAAO,MAAM,WAAW,mGASd,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,eAAe,4CAA6C,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;CAMnB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC;AAEX,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,21 +2,50 @@
|
|
|
2
2
|
* @adminium/tokens — JS-side constants for the four theming axes plus the pre-hydration
|
|
3
3
|
* script. CSS custom properties live in the sibling .css files; these exports exist so
|
|
4
4
|
* ThemeProvider, Storybook toolbars, charts and the desktop shell never hard-code axis
|
|
5
|
-
* values. See
|
|
5
|
+
* values. See 02-design-system.md §2.5.
|
|
6
6
|
*/
|
|
7
7
|
/** Theme axis. `system` resolves via `matchMedia("(prefers-color-scheme: dark)")`. */
|
|
8
8
|
export const THEMES = ["light", "dark", "system"];
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Accent axis: the 8 switchable palettes (`data-accent`), name → LIGHT-theme hex
|
|
11
|
+
* (`--accent-light` in accents.css).
|
|
12
|
+
*
|
|
13
|
+
* This is ONE HALF of the accent. Each palette also has an `--accent-dark` hex that the dark
|
|
14
|
+
* theme selects into `--accent`, and it is a different colour, drastically so for `black`
|
|
15
|
+
* (#111111 light, #c9c9d4 dark). Anything that PAINTS an accent must therefore either read the
|
|
16
|
+
* CSS variable — which already resolves per theme — or pick from {@link ACCENTS_DARK} when the
|
|
17
|
+
* resolved theme is dark. Rendering `ACCENTS[a]` unconditionally shows the wrong colour on dark;
|
|
18
|
+
* that is what the accent-picker swatch used to do.
|
|
19
|
+
*/
|
|
10
20
|
export const ACCENTS = {
|
|
11
21
|
indigo: "#4f46e5",
|
|
12
|
-
blue: "#
|
|
13
|
-
teal: "#
|
|
14
|
-
violet: "#
|
|
15
|
-
rose: "#
|
|
16
|
-
red: "#
|
|
17
|
-
orange: "#
|
|
22
|
+
blue: "#1c59e0",
|
|
23
|
+
teal: "#007167",
|
|
24
|
+
violet: "#7936e9",
|
|
25
|
+
rose: "#c40039",
|
|
26
|
+
red: "#c0202f",
|
|
27
|
+
orange: "#b03e00",
|
|
18
28
|
black: "#111111",
|
|
19
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* The dark half (`--accent-dark`). Derived from the light ramp by recipe — see the header of
|
|
32
|
+
* accents.css, which owns the values; these mirror them for JS that cannot read CSS (chart
|
|
33
|
+
* canvases, the desktop shell, docs tables).
|
|
34
|
+
*/
|
|
35
|
+
export const ACCENTS_DARK = {
|
|
36
|
+
indigo: "#99a5ff",
|
|
37
|
+
blue: "#7fabff",
|
|
38
|
+
teal: "#49bbae",
|
|
39
|
+
violet: "#b39dff",
|
|
40
|
+
rose: "#ff848c",
|
|
41
|
+
red: "#ff8582",
|
|
42
|
+
orange: "#ff885b",
|
|
43
|
+
black: "#c9c9d4",
|
|
44
|
+
};
|
|
45
|
+
/** The accent hex actually painted for a resolved theme. */
|
|
46
|
+
export function accentHex(accent, theme) {
|
|
47
|
+
return theme === "dark" ? ACCENTS_DARK[accent] : ACCENTS[accent];
|
|
48
|
+
}
|
|
20
49
|
/** Density axis (`data-density`). */
|
|
21
50
|
export const DENSITIES = ["comfortable", "compact"];
|
|
22
51
|
/** Text direction axis (`dir` on `<html>`). `rtl` iff locale is `ar_EG`. */
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAK3D
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAK3D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,SAAS;CACR,CAAC;AAEX;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,SAAS;CACR,CAAC;AAKX,4DAA4D;AAC5D,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,KAAoB;IAC5D,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,qCAAqC;AACrC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,aAAa,EAAE,SAAS,CAAU,CAAC;AAG7D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,CAAU,CAAC;AAG5C,mFAAmF;AACnF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACD,CAAC;AAEX,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAU,CAAC;AAE1E;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,aAAa;IACrB,OAAO,EAAE,cAAc;IACvB,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;CACJ,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAE,gBAAgB;IACvB,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,iBAAiB;IACzB,GAAG,EAAE,cAAc;CACX,CAAC;AAEX,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,aAAa;IACtB,MAAM,EAAE,OAAO;CACP,CAAC;AAEX,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/pre-hydration.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pre-hydration script — flash prevention. See
|
|
2
|
+
* Pre-hydration script — flash prevention. See 02-design-system.md §4.3.
|
|
3
3
|
*
|
|
4
4
|
* Inlined (as a string) as the FIRST <script> in <head> of apps/dashboard/index.html,
|
|
5
5
|
* the Electron renderer HTML and Storybook's preview-head.html, before any stylesheet
|
package/dist/pre-hydration.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pre-hydration script — flash prevention. See
|
|
2
|
+
* Pre-hydration script — flash prevention. See 02-design-system.md §4.3.
|
|
3
3
|
*
|
|
4
4
|
* Inlined (as a string) as the FIRST <script> in <head> of apps/dashboard/index.html,
|
|
5
5
|
* the Electron renderer HTML and Storybook's preview-head.html, before any stylesheet
|
package/package.json
CHANGED
package/src/accents.css
CHANGED
|
@@ -1,24 +1,125 @@
|
|
|
1
|
-
/* @adminium/tokens — accent palettes + derived accent tokens. See
|
|
1
|
+
/* @adminium/tokens — accent palettes + derived accent tokens. See 02-design-system.md §1.2/§2.3.
|
|
2
2
|
Everything accent-derived is computed from the single --accent hex; switching data-accent
|
|
3
|
-
|
|
3
|
+
swaps the light/dark pair below, from which the theme resolves that one hex. Derivation
|
|
4
|
+
recipes are defined here once, never re-derived in components.
|
|
5
|
+
|
|
6
|
+
PER-THEME PAIRS. Each accent now declares two canonical hexes — --accent-light and
|
|
7
|
+
--accent-dark — and the theme selects one into --accent, below. That selection happens here,
|
|
8
|
+
once: components still read --accent (and --accent-soft/-hover/-border/-selection/-glow) only,
|
|
9
|
+
and never branch on theme. Before this, the single light-tuned hex was reused unchanged on dark
|
|
10
|
+
surfaces, where --accent is the focus ring (focus-visible:outline-accent, 113 controls): black
|
|
11
|
+
measured 1.03:1 and indigo 2.92:1 against --surface #141419 — WCAG 2.4.7 and 1.4.11 failures.
|
|
12
|
+
|
|
13
|
+
THE DARK RAMP IS DERIVED FROM THE LIGHT ONE, and that is deliberate — do not re-describe it as
|
|
14
|
+
hand-tuned. Measured, each chromatic dark hex is exactly: its light sibling's OKLCH hue held
|
|
15
|
+
fixed (|dh| <= 0.53deg), OKLCH L raised to ~0.75 (the seven land at 0.724-0.754), and chroma
|
|
16
|
+
pushed to the sRGB gamut edge at that L and hue — six of the seven sit ON the boundary
|
|
17
|
+
(C / Cmax = 1.000); teal alone is held to 0.82 of it (C 0.104 of a possible 0.128) so a
|
|
18
|
+
low-chroma light teal does not turn neon in dark.
|
|
19
|
+
Why a recipe rather than taste: the constraints leave almost nothing to choose. Hue IS the
|
|
20
|
+
accent's identity and must not move; L is pinned from below by the dark gates listed further
|
|
21
|
+
down — at gamut-max chroma the minimum L clearing all of them currently measures 0.664 (teal)
|
|
22
|
+
to 0.702 (rose), and the ramp sits just above that, deliberately not ON it, because that floor
|
|
23
|
+
moves whenever a tint strength or a surface does (dropping dark --accent-soft from 20% to 12%
|
|
24
|
+
below lowered it by ~0.045); and with L and hue fixed the only free parameter left is how much
|
|
25
|
+
chroma sRGB will still hand you. Hand-picking would land in the same place with no way to
|
|
26
|
+
reproduce or re-derive it. What is gated is the measured contrast, not the provenance:
|
|
27
|
+
scripts/contrast-check.mjs re-measures every hex on every run.
|
|
28
|
+
`black` is the one genuinely hand-authored dark value (its hue is not its light sibling's —
|
|
29
|
+
light black is achromatic; C 0.015 is 18% of the max at its L 0.839). See THE BLACK ACCENT
|
|
30
|
+
ON DARK below.
|
|
31
|
+
|
|
32
|
+
Light hexes moved only where AA forced it: indigo (#4f46e5) and black (#111111) are untouched;
|
|
33
|
+
blue, teal, violet, rose, red and orange each took the minimum OKLCH-lightness step down that
|
|
34
|
+
clears the gates (dL from -0.011 for violet to -0.127 for orange), hue held to |dh| <= 0.47deg.
|
|
35
|
+
|
|
36
|
+
What every hex here clears (scripts/contrast-check.mjs measures all of it):
|
|
37
|
+
light white --accent-fg on --accent >= 4.5:1 (primary-button label; teal/red/orange were
|
|
38
|
+
3.74/3.91/3.56 and are the reason those three moved)
|
|
39
|
+
--accent as text on --surface/-2 >= 4.5:1
|
|
40
|
+
--accent on --accent-soft >= 4.5:1 (active sidebar row, Tag, soft Button) —
|
|
41
|
+
binding on --surface-3, where the 10% tint darkens the chip most; that pass is what
|
|
42
|
+
pulls blue/violet down as well, not just the three that failed the button label
|
|
43
|
+
dark --accent-fg #0f0f14 on --accent >= 4.5:1
|
|
44
|
+
--accent on --bg/--surface/-2/-3 >= 4.5:1 — well past the 3:1 non-text floor the
|
|
45
|
+
focus ring needs, because --accent is also text on those surfaces
|
|
46
|
+
--accent on --accent-soft >= 4.5:1
|
|
47
|
+
|
|
48
|
+
Darkening the light accent, rather than giving teal/red/orange their own --accent-fg, is the
|
|
49
|
+
deliberate choice: a per-accent --accent-fg would fix only the button label and leave
|
|
50
|
+
text-accent-on-surface (3.56-3.91:1) and text-accent-on-accent-soft (3.15-3.44:1) failing,
|
|
51
|
+
and it would put a theme-and-accent conditional back into the token layer. One --accent-fg per
|
|
52
|
+
theme keeps the contract "components read --accent and --accent-fg, full stop".
|
|
53
|
+
|
|
54
|
+
THE BLACK ACCENT ON DARK — the documented override called for in 15-quality.md.
|
|
55
|
+
`black` is the neutral/monochrome accent: it means "no hue, the strongest neutral this theme
|
|
56
|
+
can carry", not literally the colour black. In light that resolves to #111111 (18.88:1 on
|
|
57
|
+
--surface). In dark it cannot: #111111 is 1.03:1 on --surface #141419 — invisible as a focus
|
|
58
|
+
ring, as a fill and as text. It resolves instead to #c9c9d4, a light cool neutral drawn from
|
|
59
|
+
the dark neutral family: 11.18:1 on --surface, 9.38:1 on --surface-3, 11.64:1 against
|
|
60
|
+
--accent-fg — and only 1.49:1 against --fg #f4f4f6, close enough to the text colour that a
|
|
61
|
+
monochrome accent still reads as monochrome, far enough that an accent fill does not read as
|
|
62
|
+
plain body text. */
|
|
4
63
|
:root,
|
|
5
|
-
[data-accent="indigo"] { --accent: #4f46e5; }
|
|
6
|
-
[data-accent="blue"] { --accent: #
|
|
7
|
-
[data-accent="teal"] { --accent: #
|
|
8
|
-
[data-accent="violet"] { --accent: #
|
|
9
|
-
[data-accent="rose"] { --accent: #
|
|
10
|
-
[data-accent="red"] { --accent: #
|
|
11
|
-
[data-accent="orange"] { --accent: #
|
|
12
|
-
[data-accent="black"] { --accent: #111111; }
|
|
64
|
+
[data-accent="indigo"] { --accent-light: #4f46e5; --accent-dark: #99a5ff; }
|
|
65
|
+
[data-accent="blue"] { --accent-light: #1c59e0; --accent-dark: #7fabff; }
|
|
66
|
+
[data-accent="teal"] { --accent-light: #007167; --accent-dark: #49bbae; }
|
|
67
|
+
[data-accent="violet"] { --accent-light: #7936e9; --accent-dark: #b39dff; }
|
|
68
|
+
[data-accent="rose"] { --accent-light: #c40039; --accent-dark: #ff848c; }
|
|
69
|
+
[data-accent="red"] { --accent-light: #c0202f; --accent-dark: #ff8582; }
|
|
70
|
+
[data-accent="orange"] { --accent-light: #b03e00; --accent-dark: #ff885b; }
|
|
71
|
+
[data-accent="black"] { --accent-light: #111111; --accent-dark: #c9c9d4; }
|
|
13
72
|
|
|
73
|
+
/* THE 12% TINT CEILING. Every translucent accent tint below is capped at 12%, and that number is
|
|
74
|
+
measured, not chosen: a tint composites over the surface under it, so text painted on the tint
|
|
75
|
+
loses contrast, and the weakest gated foreground (--fg-subtle) on the deepest grey
|
|
76
|
+
(--surface-3) is what binds. With the monochrome accent — the extreme in both themes — the
|
|
77
|
+
worst pair measures 4.557:1 at 12% and 4.444:1 at 13% in dark (4.698 / 4.595 light). So 12% is
|
|
78
|
+
the last strength at which ANY neutral copy on ANY accent tint on ANY surface still clears
|
|
79
|
+
WCAG 1.4.3. scripts/contrast-check.mjs gates all of it (group text-on-soft / text-on-tint).
|
|
80
|
+
|
|
81
|
+
That is why the previous values are gone:
|
|
82
|
+
--accent-soft dark was 20% — measured --fg-muted 4.09:1 and --fg-subtle 3.11:1 on
|
|
83
|
+
--surface-3, both live in the axe sweep (active nav rows, sticky headers, chips).
|
|
84
|
+
--accent-selection was 22% — an earlier note here claimed it "keeps --fg at >=9.9:1", which
|
|
85
|
+
is true and beside the point: ::selection paints over WHATEVER text the user drags across,
|
|
86
|
+
including secondary and tertiary copy, which measured 4.36:1 and 3.33:1.
|
|
87
|
+
--accent-border was 25% — and the note here asserted it "has no consumer … so no WCAG
|
|
88
|
+
obligation attaches". The first half is still literally true of the TOKEN (no `bg-`/
|
|
89
|
+
`border-accent-border` utility and no var(--accent-border) read outside tailwind.css), but
|
|
90
|
+
the conclusion was wrong twice over: an unconsumed token still has to be safe for its FIRST
|
|
91
|
+
consumer, and the same 25%-accent-over-surface recipe IS painted under text today through
|
|
92
|
+
Tailwind's alpha syntax — RankedEntityList's proportional bar is `bg-accent/25` sitting
|
|
93
|
+
behind `text-fg-subtle` rank numbers (3.26:1 dark / 3.48:1 light; `text-fg` on it is fine
|
|
94
|
+
at 7.58 / 8.93). Lowering the token to 12% makes `bg-accent-border` safe; the component's
|
|
95
|
+
own alpha utility is a separate, component-level fix.
|
|
96
|
+
The 1.4.11 reading is unchanged and still correct: these tints are decorative, component state
|
|
97
|
+
is drawn with `border-accent` / `outline-accent` (the full accent, >=4.5:1), so no non-text
|
|
98
|
+
contrast floor attaches to the tints themselves. --accent-glow stays a drop-shadow with no
|
|
99
|
+
foreground. */
|
|
14
100
|
:root {
|
|
101
|
+
--accent: var(--accent-light);
|
|
15
102
|
--accent-soft: color-mix(in srgb, var(--accent) 10%, transparent);
|
|
16
103
|
--accent-hover: color-mix(in srgb, var(--accent) 82%, #000);
|
|
17
|
-
--accent-selection: color-mix(in srgb, var(--accent)
|
|
18
|
-
--accent-border: color-mix(in srgb, var(--accent)
|
|
104
|
+
--accent-selection: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
105
|
+
--accent-border: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
19
106
|
--accent-glow: 0 2px 8px color-mix(in srgb, var(--accent) 36%, transparent);
|
|
20
107
|
}
|
|
21
108
|
|
|
109
|
+
/* Same specificity as :root above, so source order decides — this block must stay last.
|
|
110
|
+
--accent-hover inverts with the theme: mixing toward #000 is "darker, therefore pressed" only
|
|
111
|
+
while --accent is dark. On dark it would push an already-dark hover further into the surface
|
|
112
|
+
(indigo's old dark hover measured 2.22:1 on --surface), so dark mixes toward #fff instead.
|
|
113
|
+
Every dark hover value stays >=8.96:1 against --accent-fg and >=7.22:1 on --surface-3, and
|
|
114
|
+
both halves of that are now gated: `accent-hover` measures the button label on the hover fill
|
|
115
|
+
at 4.5:1, `state-fill` measures the hover fill against the resting surface at the 1.4.11 3:1
|
|
116
|
+
floor — which is the check that fails closed if anyone mixes the dark accent toward #000 again.
|
|
117
|
+
|
|
118
|
+
--accent-soft is 12% here rather than the light ramp's 10% (see THE 12% TINT CEILING above):
|
|
119
|
+
a tint of a LIGHT hue over a near-black surface reads weaker than the mirror case, so dark
|
|
120
|
+
takes the whole allowance. It was 20% until the tint ceiling was measured. */
|
|
22
121
|
[data-theme="dark"] {
|
|
23
|
-
--accent
|
|
122
|
+
--accent: var(--accent-dark);
|
|
123
|
+
--accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
124
|
+
--accent-hover: color-mix(in srgb, var(--accent) 88%, #fff);
|
|
24
125
|
}
|
package/src/density.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @adminium/tokens — density axis (data-density). See
|
|
1
|
+
/* @adminium/tokens — density axis (data-density). See 02-design-system.md §1.8.
|
|
2
2
|
Two canonical densities; the comps' third "power" density is deliberately dropped. */
|
|
3
3
|
:root,
|
|
4
4
|
[data-density="comfortable"] {
|
package/src/exceptions.css
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
/* @adminium/tokens — canonical theming exceptions. See
|
|
1
|
+
/* @adminium/tokens — canonical theming exceptions. See 02-design-system.md §6.
|
|
2
2
|
Two deliberate breaks from the active theme, implemented as scope classes that re-declare
|
|
3
3
|
the full token set on a subtree (token cascade does the rest — children need no changes).
|
|
4
|
-
These scopes copy canonical hand-tuned values; they do not derive them.
|
|
4
|
+
These scopes copy canonical hand-tuned values; they do not derive them.
|
|
5
|
+
|
|
6
|
+
They now also pin the ACCENT side of the theme, because accents.css resolves --accent per
|
|
7
|
+
theme (--accent-light / --accent-dark). A dark code block inside a light page would otherwise
|
|
8
|
+
inherit the light accent onto a #0f0f14 surface — where the black accent measures 1.03:1 — and
|
|
9
|
+
vice versa. Re-declaring --accent/--accent-fg/--accent-hover here keeps the exception scopes
|
|
10
|
+
self-consistent without teaching any component about the theme.
|
|
11
|
+
|
|
12
|
+
EVERY accent-derived token has to be re-declared for that to hold, not just --accent itself.
|
|
13
|
+
A custom property's var() is substituted on the element that DECLARES it, so an --accent-soft
|
|
14
|
+
left to accents.css would arrive here already resolved against the ROOT's accent — the light
|
|
15
|
+
accent inside a dark code block. --accent-selection and --accent-border were missing for
|
|
16
|
+
exactly that reason and are pinned below.
|
|
17
|
+
|
|
18
|
+
scripts/contrast-check.mjs replays both scopes as real subtrees (each root theme x each accent
|
|
19
|
+
x each scope) and gates every pair, so the copied values below cannot drift from tokens.css
|
|
20
|
+
without turning CI red. */
|
|
5
21
|
|
|
6
22
|
/* Code/terminal surfaces are ALWAYS dark, both themes:
|
|
7
23
|
CodeBlock, Terminal, JsonViewer, LogBox, connection-string previews */
|
|
@@ -14,9 +30,14 @@
|
|
|
14
30
|
--border: rgba(255,255,255,.07);
|
|
15
31
|
--border-strong: rgba(255,255,255,.13);
|
|
16
32
|
--fg: #f4f4f6;
|
|
17
|
-
--fg-muted: #
|
|
18
|
-
--fg-subtle: #
|
|
19
|
-
--accent
|
|
33
|
+
--fg-muted: #b7b7c3;
|
|
34
|
+
--fg-subtle: #a1a1ad;
|
|
35
|
+
--accent: var(--accent-dark);
|
|
36
|
+
--accent-fg: #0f0f14;
|
|
37
|
+
--accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
38
|
+
--accent-hover: color-mix(in srgb, var(--accent) 88%, #fff);
|
|
39
|
+
--accent-selection: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
40
|
+
--accent-border: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
20
41
|
--pos: #3ecf8e;
|
|
21
42
|
--pos-soft: rgba(62,207,142,.14);
|
|
22
43
|
--warn: #e0a458;
|
|
@@ -28,12 +49,18 @@
|
|
|
28
49
|
--shadow: 0 1px 2px rgba(0,0,0,.4);
|
|
29
50
|
--shadow-md: 0 6px 20px rgba(0,0,0,.5);
|
|
30
51
|
--shadow-lg: 0 16px 40px rgba(0,0,0,.6);
|
|
31
|
-
/* JSON syntax tokens (fixed, never themed)
|
|
52
|
+
/* JSON syntax tokens (fixed, never themed). These are TEXT on the surfaces above, so the gate
|
|
53
|
+
measures them like any other foreground. --code-gray (punctuation, nulls, comments) was
|
|
54
|
+
#7d7d8a: 4.71:1 on --surface but 4.27:1 on --surface-2 and 3.79:1 on --surface-3, which
|
|
55
|
+
JsonViewer's alternating rows and LogBox's inset panels both use. Raised by the minimum
|
|
56
|
+
OKLCH lightness step that clears AA on the deepest of them (hue held, drift 0.01deg):
|
|
57
|
+
4.52 / 5.09 / 5.62 : 1. It stays well below --fg-subtle #a1a1ad, so punctuation still reads
|
|
58
|
+
dimmer than tertiary prose. The other four already cleared 7.5:1+. */
|
|
32
59
|
--code-blue: #7cc5ff;
|
|
33
60
|
--code-green: #8fe388;
|
|
34
61
|
--code-orange: #e6b673;
|
|
35
62
|
--code-purple: #c8a6ff;
|
|
36
|
-
--code-gray: #
|
|
63
|
+
--code-gray: #8a8a98;
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
/* Email previews and QR tiles are ALWAYS light, both themes
|
|
@@ -47,16 +74,21 @@
|
|
|
47
74
|
--border: #ececef;
|
|
48
75
|
--border-strong: #e2e2e8;
|
|
49
76
|
--fg: #191920;
|
|
50
|
-
--fg-muted: #
|
|
51
|
-
--fg-subtle: #
|
|
77
|
+
--fg-muted: #4a4a54;
|
|
78
|
+
--fg-subtle: #5a5a65;
|
|
79
|
+
--accent: var(--accent-light);
|
|
80
|
+
--accent-fg: #ffffff;
|
|
52
81
|
--accent-soft: color-mix(in srgb, var(--accent) 10%, transparent);
|
|
53
|
-
--
|
|
82
|
+
--accent-hover: color-mix(in srgb, var(--accent) 82%, #000);
|
|
83
|
+
--accent-selection: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
84
|
+
--accent-border: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
85
|
+
--pos: #0b7d59;
|
|
54
86
|
--pos-soft: #e6f5ee;
|
|
55
|
-
--warn: #
|
|
87
|
+
--warn: #a95800;
|
|
56
88
|
--warn-soft: #fbf0e2;
|
|
57
|
-
--danger: #
|
|
89
|
+
--danger: #cf273c;
|
|
58
90
|
--danger-soft: #fdecec;
|
|
59
|
-
--info: #
|
|
91
|
+
--info: #1c59e0;
|
|
60
92
|
--info-soft: #e7edfd;
|
|
61
93
|
--shadow: 0 1px 2px rgba(20,20,35,.04), 0 1px 3px rgba(20,20,35,.05);
|
|
62
94
|
--shadow-md: 0 4px 14px rgba(20,20,35,.09);
|
package/src/fonts.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @adminium/tokens — @font-face + per-locale family stacks. See
|
|
1
|
+
/* @adminium/tokens — @font-face + per-locale family stacks. See 02-design-system.md §2.4.
|
|
2
2
|
Font binaries are unmodified upstream builds vendored from @fontsource packages into ./fonts/
|
|
3
3
|
by scripts/copy-fonts.mjs (never subset locally — "Plex" is an OFL Reserved Font Name).
|
|
4
4
|
CJK is not self-hosted; zh_CN/zh_TW use system fallback stacks (v1 policy). */
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @adminium/tokens — JS-side constants for the four theming axes plus the pre-hydration
|
|
3
3
|
* script. CSS custom properties live in the sibling .css files; these exports exist so
|
|
4
4
|
* ThemeProvider, Storybook toolbars, charts and the desktop shell never hard-code axis
|
|
5
|
-
* values. See
|
|
5
|
+
* values. See 02-design-system.md §2.5.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/** Theme axis. `system` resolves via `matchMedia("(prefers-color-scheme: dark)")`. */
|
|
@@ -11,20 +11,52 @@ export type ThemePref = (typeof THEMES)[number];
|
|
|
11
11
|
/** A resolved theme as stamped on `<html data-theme>`. */
|
|
12
12
|
export type ResolvedTheme = Exclude<ThemePref, "system">;
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Accent axis: the 8 switchable palettes (`data-accent`), name → LIGHT-theme hex
|
|
16
|
+
* (`--accent-light` in accents.css).
|
|
17
|
+
*
|
|
18
|
+
* This is ONE HALF of the accent. Each palette also has an `--accent-dark` hex that the dark
|
|
19
|
+
* theme selects into `--accent`, and it is a different colour, drastically so for `black`
|
|
20
|
+
* (#111111 light, #c9c9d4 dark). Anything that PAINTS an accent must therefore either read the
|
|
21
|
+
* CSS variable — which already resolves per theme — or pick from {@link ACCENTS_DARK} when the
|
|
22
|
+
* resolved theme is dark. Rendering `ACCENTS[a]` unconditionally shows the wrong colour on dark;
|
|
23
|
+
* that is what the accent-picker swatch used to do.
|
|
24
|
+
*/
|
|
15
25
|
export const ACCENTS = {
|
|
16
26
|
indigo: "#4f46e5",
|
|
17
|
-
blue: "#
|
|
18
|
-
teal: "#
|
|
19
|
-
violet: "#
|
|
20
|
-
rose: "#
|
|
21
|
-
red: "#
|
|
22
|
-
orange: "#
|
|
27
|
+
blue: "#1c59e0",
|
|
28
|
+
teal: "#007167",
|
|
29
|
+
violet: "#7936e9",
|
|
30
|
+
rose: "#c40039",
|
|
31
|
+
red: "#c0202f",
|
|
32
|
+
orange: "#b03e00",
|
|
23
33
|
black: "#111111",
|
|
24
34
|
} as const;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The dark half (`--accent-dark`). Derived from the light ramp by recipe — see the header of
|
|
38
|
+
* accents.css, which owns the values; these mirror them for JS that cannot read CSS (chart
|
|
39
|
+
* canvases, the desktop shell, docs tables).
|
|
40
|
+
*/
|
|
41
|
+
export const ACCENTS_DARK = {
|
|
42
|
+
indigo: "#99a5ff",
|
|
43
|
+
blue: "#7fabff",
|
|
44
|
+
teal: "#49bbae",
|
|
45
|
+
violet: "#b39dff",
|
|
46
|
+
rose: "#ff848c",
|
|
47
|
+
red: "#ff8582",
|
|
48
|
+
orange: "#ff885b",
|
|
49
|
+
black: "#c9c9d4",
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
25
52
|
/** `indigo` is the default. */
|
|
26
53
|
export type Accent = keyof typeof ACCENTS;
|
|
27
54
|
|
|
55
|
+
/** The accent hex actually painted for a resolved theme. */
|
|
56
|
+
export function accentHex(accent: Accent, theme: ResolvedTheme): string {
|
|
57
|
+
return theme === "dark" ? ACCENTS_DARK[accent] : ACCENTS[accent];
|
|
58
|
+
}
|
|
59
|
+
|
|
28
60
|
/** Density axis (`data-density`). */
|
|
29
61
|
export const DENSITIES = ["comfortable", "compact"] as const;
|
|
30
62
|
export type Density = (typeof DENSITIES)[number];
|
package/src/motion.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @adminium/tokens — motion vocabulary. See
|
|
1
|
+
/* @adminium/tokens — motion vocabulary. See 02-design-system.md §5.
|
|
2
2
|
Keyframe names keep the comps' nb- prefix for 1:1 traceability when porting.
|
|
3
3
|
Conventions: micro-transitions .1–.16s ease; entrances use cubic-bezier(.2,.7,.3,1). */
|
|
4
4
|
|
package/src/pre-hydration.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pre-hydration script — flash prevention. See
|
|
2
|
+
* Pre-hydration script — flash prevention. See 02-design-system.md §4.3.
|
|
3
3
|
*
|
|
4
4
|
* Inlined (as a string) as the FIRST <script> in <head> of apps/dashboard/index.html,
|
|
5
5
|
* the Electron renderer HTML and Storybook's preview-head.html, before any stylesheet
|
package/src/tailwind.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @adminium/tokens — Tailwind v4 theme mapping. See
|
|
1
|
+
/* @adminium/tokens — Tailwind v4 theme mapping. See 02-design-system.md §3.1.
|
|
2
2
|
Import order in each app's entry CSS:
|
|
3
3
|
@import "tailwindcss";
|
|
4
4
|
@import "@adminium/tokens/index.css";
|
package/src/tokens.css
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
|
-
/* @adminium/tokens — core semantic tokens. Values are canonical; see
|
|
2
|
-
The dark palette is
|
|
1
|
+
/* @adminium/tokens — core semantic tokens. Values are canonical; see 02-design-system.md §1.1.
|
|
2
|
+
The dark NEUTRAL palette in this file is authored independently of the light one, not derived
|
|
3
|
+
from it: the light/dark OKLCH lightness pairs sum to 1.120-1.223 (--bg 1.120, --surface 1.194,
|
|
4
|
+
--surface-3 1.223, --fg 1.184, --fg-muted 1.196, --fg-subtle 1.184), so no inversion, offset or other single
|
|
5
|
+
rule relates the two columns. That sentence covers THIS file only — the dark ACCENT ramp in
|
|
6
|
+
accents.css IS mechanically derived from the light accents, on purpose, and that file states
|
|
7
|
+
the recipe and why. Do not carry this claim across to it.
|
|
8
|
+
|
|
9
|
+
CONTRAST. Every foreground here clears WCAG 2.1 AA (4.5:1) against the WORST backdrop it is
|
|
10
|
+
actually painted on — which is not --surface, and not even --surface-3, but a translucent tint
|
|
11
|
+
composited over --surface-3: --surface-3 is a real background for tertiary text
|
|
12
|
+
(CalendarLegendFilter's `text-fg-subtle` chip has `hover:bg-surface-3`; CountBadge/DeltaPill/
|
|
13
|
+
AvatarStack paint `bg-surface-3 text-fg-muted`), and accent/semantic tints sit on top of it.
|
|
14
|
+
scripts/contrast-check.mjs measures every such pair across both themes, all 8 accents and the
|
|
15
|
+
exception scopes; do not change a value here without re-running it.
|
|
16
|
+
|
|
17
|
+
The two grey steps below moved together on purpose. --fg-subtle had to darken from #9a9aa5
|
|
18
|
+
(2.471:1 on --surface-3 — the single largest source of contrast failures in the app) far enough
|
|
19
|
+
to clear 4.5:1 on the tinted backdrops too. Holding --fg-muted still would have collapsed the
|
|
20
|
+
secondary/tertiary ladder into one grey, so --fg-muted followed it down. The result is a real
|
|
21
|
+
but narrower ladder — see THE TEXT-LADDER TRADE-OFF at the tokens below for every measured
|
|
22
|
+
number. AA on a 4-surface ramp with tints on top leaves much less room than the original
|
|
23
|
+
palette assumed. */
|
|
3
24
|
:root {
|
|
4
25
|
color-scheme: light;
|
|
5
26
|
--bg: #f6f6f8;
|
|
@@ -9,16 +30,35 @@
|
|
|
9
30
|
--border: #ececef;
|
|
10
31
|
--border-strong: #e2e2e8;
|
|
11
32
|
--fg: #191920;
|
|
12
|
-
|
|
13
|
-
|
|
33
|
+
/* THE TEXT-LADDER TRADE-OFF — read before "restoring" any separation here.
|
|
34
|
+
The three text tiers are closer together than they were, and that is the price of AA on this
|
|
35
|
+
palette, not an oversight. Measured now: muted <-> subtle 1.286:1 in light (was 1.890:1, back
|
|
36
|
+
when the pair was #6b6b76 / #9a9aa5) and 1.287:1 in dark (was 1.917:1, #9a9aa6 / #6a6a76);
|
|
37
|
+
fg <-> muted 1.997:1 light, 1.808:1 dark.
|
|
38
|
+
The rungs bunched because the BOTTOM of the ladder had to come up while the TOP could not
|
|
39
|
+
come down. --fg-subtle is not sized by plain --surface-3 — it clears that comfortably
|
|
40
|
+
(6.038:1 light / 6.025:1 dark) — but by the worst backdrop tertiary text is actually painted
|
|
41
|
+
on: a 12% accent tint OVER --surface-3. With the `black` accent that composites to #d6d6d9 in
|
|
42
|
+
light and #383840 in dark, where the tokens below measure subtle 4.698:1 / 4.557:1, muted
|
|
43
|
+
6.042:1 / 5.865:1 and --fg 12.065:1 / 10.602:1. --fg is brand-fixed near-black/near-white, so
|
|
44
|
+
everything else has to fit underneath it.
|
|
45
|
+
Pushing --fg-subtle back toward its surface for "more contrast between the greys" therefore
|
|
46
|
+
REMOVES contrast where it is measured and re-breaks WCAG 1.4.3, almost immediately: light has
|
|
47
|
+
two 8-bit steps of headroom (#5c5c67 = 4.555:1 passes, #5d5d68 = 4.486:1 fails) and dark has
|
|
48
|
+
one (#a0a0ac = 4.502:1 passes, #9f9fab = 4.448:1 fails). If the tiers must read further
|
|
49
|
+
apart, widen from the other end — the fg <-> muted gap above is the only slack left — and
|
|
50
|
+
re-run scripts/contrast-check.mjs, which measures the tinted backdrops as well as the plain
|
|
51
|
+
ones. */
|
|
52
|
+
--fg-muted: #4a4a54;
|
|
53
|
+
--fg-subtle: #5a5a65;
|
|
14
54
|
--accent-fg: #ffffff;
|
|
15
|
-
--pos: #
|
|
55
|
+
--pos: #0b7d59;
|
|
16
56
|
--pos-soft: #e6f5ee;
|
|
17
|
-
--warn: #
|
|
57
|
+
--warn: #a95800;
|
|
18
58
|
--warn-soft: #fbf0e2;
|
|
19
|
-
--danger: #
|
|
59
|
+
--danger: #cf273c;
|
|
20
60
|
--danger-soft: #fdecec;
|
|
21
|
-
--info: #
|
|
61
|
+
--info: #1c59e0;
|
|
22
62
|
--info-soft: #e7edfd;
|
|
23
63
|
--shadow: 0 1px 2px rgba(20,20,35,.04), 0 1px 3px rgba(20,20,35,.05);
|
|
24
64
|
--shadow-md: 0 4px 14px rgba(20,20,35,.09);
|
|
@@ -26,6 +66,15 @@
|
|
|
26
66
|
--scrim: rgba(10,10,15,.5);
|
|
27
67
|
}
|
|
28
68
|
|
|
69
|
+
/* Each light semantic tone above is the minimum OKLCH-lightness darkening (hue held to <0.3deg)
|
|
70
|
+
that puts it at >=4.5:1 on its own -soft partner, which is where it is smallest — StatusPill
|
|
71
|
+
and Alert set 11.5-13px text in --pos/--warn/--danger/--info on --pos-soft/…-soft. Measured
|
|
72
|
+
after the move: 4.56 / 4.57 / 4.59 / 5.04:1 (the light -soft partners are opaque, so the
|
|
73
|
+
backing surface does not change the number).
|
|
74
|
+
The dark tones are untouched — theirs are translucent, so they DO vary with the surface:
|
|
75
|
+
5.46-7.16:1 over --surface, 4.51-5.86:1 over --surface-3, the tightest (--danger on
|
|
76
|
+
--surface-3, 4.51:1) still clearing AA. */
|
|
77
|
+
|
|
29
78
|
[data-theme="dark"] {
|
|
30
79
|
color-scheme: dark;
|
|
31
80
|
--bg: #0a0a0d;
|
|
@@ -35,8 +84,15 @@
|
|
|
35
84
|
--border: rgba(255,255,255,.07);
|
|
36
85
|
--border-strong: rgba(255,255,255,.13);
|
|
37
86
|
--fg: #f4f4f6;
|
|
38
|
-
--
|
|
39
|
-
|
|
87
|
+
/* Same trade-off as light, mirrored: 7.754:1 / 6.025:1 on plain --surface-3 but 5.865:1 /
|
|
88
|
+
4.557:1 on the 12% black-accent tint over it (#383840), which is what sizes them — 1.287:1
|
|
89
|
+
apart, and --fg-subtle has ONE 8-bit step of headroom left. See THE TEXT-LADDER TRADE-OFF in
|
|
90
|
+
the light block above before touching either. */
|
|
91
|
+
--fg-muted: #b7b7c3;
|
|
92
|
+
--fg-subtle: #a1a1ad;
|
|
93
|
+
/* Dark --accent is a light hue (see accents.css), so the primary-button label inverts:
|
|
94
|
+
white on #99a5ff is 2.3:1, #0f0f14 on it is 8.4:1. One value, no per-accent branch. */
|
|
95
|
+
--accent-fg: #0f0f14;
|
|
40
96
|
--pos: #3ecf8e;
|
|
41
97
|
--pos-soft: rgba(62,207,142,.14);
|
|
42
98
|
--warn: #e0a458;
|
package/src/viz.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @adminium/tokens — data-viz palette. See
|
|
1
|
+
/* @adminium/tokens — data-viz palette. See 02-design-system.md §1.3.
|
|
2
2
|
Fixed 8-color categorical palette (order canonical; series i gets --viz-((i mod 8)+1)),
|
|
3
3
|
sequential accent ramp for heatmaps/choropleth intensity, and chart area/ribbon fill.
|
|
4
4
|
@adminium/charts consumes only these vars — no hex literals in chart code. */
|