@hanzo/design 0.5.11 → 0.5.13
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/dist/preference.d.ts +30 -0
- package/dist/preference.d.ts.map +1 -1
- package/dist/preference.js +57 -0
- package/dist/tokens.gen.d.ts +14 -0
- package/dist/tokens.gen.d.ts.map +1 -1
- package/dist/tokens.gen.js +14 -0
- package/package.json +8 -10
- package/scripts/check-preference.mjs +45 -0
- package/scripts/gen-tokens.mjs +14 -2
- package/src/preference.ts +65 -0
- package/src/tokens.gen.ts +14 -0
- package/styles.css +49 -18
- package/tailwind.css +49 -18
- package/tokens/colors.css +19 -0
- package/tokens/typography.css +30 -18
package/dist/preference.d.ts
CHANGED
|
@@ -42,6 +42,11 @@ export interface Preference {
|
|
|
42
42
|
* above 1 opens the display end and tightens the small one.
|
|
43
43
|
*/
|
|
44
44
|
ratio?: number;
|
|
45
|
+
/**
|
|
46
|
+
* A modular scale for the display rungs — 1.618 for golden, 1.25 for a major
|
|
47
|
+
* third. Absent means the authored ramp, which is the tuned default.
|
|
48
|
+
*/
|
|
49
|
+
modular?: number;
|
|
45
50
|
density?: Density;
|
|
46
51
|
/** Which face the page is set in. */
|
|
47
52
|
font?: Face;
|
|
@@ -74,6 +79,31 @@ export declare const TYPE_MAX = 1.4;
|
|
|
74
79
|
*/
|
|
75
80
|
export declare const RATIO_MIN = 0.75;
|
|
76
81
|
export declare const RATIO_MAX = 1.5;
|
|
82
|
+
/**
|
|
83
|
+
* A MODULAR scale — the classical one, where each display rung is the one below
|
|
84
|
+
* it times a fixed ratio. Golden is 1.618; the musical intervals designers name
|
|
85
|
+
* are 1.2 (minor third), 1.25 (major third), 1.333 (perfect fourth) and 1.5
|
|
86
|
+
* (perfect fifth).
|
|
87
|
+
*
|
|
88
|
+
* This is a different RULE from `ratio`, not another dial on it. `ratio` tunes
|
|
89
|
+
* the contrast of the ramp `tokens/typography.css` authored; this REPLACES that
|
|
90
|
+
* ramp's display half with a geometric one. Naming a golden-ratio preset as a
|
|
91
|
+
* contrast value would have been the dishonest version of this feature.
|
|
92
|
+
*
|
|
93
|
+
* Bounded below 1.05 because a ratio at 1 is not a scale — every display rung
|
|
94
|
+
* collapses onto the one before it — and above 2 because doubling every step
|
|
95
|
+
* puts the fourth rung past a phone's whole width.
|
|
96
|
+
*
|
|
97
|
+
* Golden is exactly 1.618 here and is NOT clamped down to something tamer,
|
|
98
|
+
* because a scale that quietly gives you not-golden when you asked for golden is
|
|
99
|
+
* worse than one that refuses. What makes that safe is the ceiling below: this
|
|
100
|
+
* ramp has EIGHT display rungs and a classical modular scale is used with about
|
|
101
|
+
* four, so at 1.618 the eighth would be 799px. Measured, --text-8xl and
|
|
102
|
+
* --text-9xl are referenced in 15 files across the fleet, so that is a broken
|
|
103
|
+
* page and not a hypothetical.
|
|
104
|
+
*/
|
|
105
|
+
export declare const MODULAR_MIN = 1.05;
|
|
106
|
+
export declare const MODULAR_MAX = 2;
|
|
77
107
|
/**
|
|
78
108
|
* Is this a colour, or is it something being smuggled into a style attribute?
|
|
79
109
|
*
|
package/dist/preference.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preference.d.ts","sourceRoot":"","sources":["../src/preference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,8CAA8C;AAC9C,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qCAAqC;IACrC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,OAAO,CAAC;AAC9B,eAAO,MAAM,SAAS,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"preference.d.ts","sourceRoot":"","sources":["../src/preference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,8CAA8C;AAC9C,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qCAAqC;IACrC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,OAAO,CAAC;AAC9B,eAAO,MAAM,SAAS,MAAM,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,OAAO,CAAC;AAChC,eAAO,MAAM,WAAW,IAAI,CAAC;AAmE7B;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAS1C;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0D1D;AAED,2EAA2E;AAC3E,wBAAgB,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,SAAc,GAAG,MAAM,CAKjE"}
|
package/dist/preference.js
CHANGED
|
@@ -49,6 +49,43 @@ export const TYPE_MAX = 1.4;
|
|
|
49
49
|
*/
|
|
50
50
|
export const RATIO_MIN = 0.75;
|
|
51
51
|
export const RATIO_MAX = 1.5;
|
|
52
|
+
/**
|
|
53
|
+
* A MODULAR scale — the classical one, where each display rung is the one below
|
|
54
|
+
* it times a fixed ratio. Golden is 1.618; the musical intervals designers name
|
|
55
|
+
* are 1.2 (minor third), 1.25 (major third), 1.333 (perfect fourth) and 1.5
|
|
56
|
+
* (perfect fifth).
|
|
57
|
+
*
|
|
58
|
+
* This is a different RULE from `ratio`, not another dial on it. `ratio` tunes
|
|
59
|
+
* the contrast of the ramp `tokens/typography.css` authored; this REPLACES that
|
|
60
|
+
* ramp's display half with a geometric one. Naming a golden-ratio preset as a
|
|
61
|
+
* contrast value would have been the dishonest version of this feature.
|
|
62
|
+
*
|
|
63
|
+
* Bounded below 1.05 because a ratio at 1 is not a scale — every display rung
|
|
64
|
+
* collapses onto the one before it — and above 2 because doubling every step
|
|
65
|
+
* puts the fourth rung past a phone's whole width.
|
|
66
|
+
*
|
|
67
|
+
* Golden is exactly 1.618 here and is NOT clamped down to something tamer,
|
|
68
|
+
* because a scale that quietly gives you not-golden when you asked for golden is
|
|
69
|
+
* worse than one that refuses. What makes that safe is the ceiling below: this
|
|
70
|
+
* ramp has EIGHT display rungs and a classical modular scale is used with about
|
|
71
|
+
* four, so at 1.618 the eighth would be 799px. Measured, --text-8xl and
|
|
72
|
+
* --text-9xl are referenced in 15 files across the fleet, so that is a broken
|
|
73
|
+
* page and not a hypothetical.
|
|
74
|
+
*/
|
|
75
|
+
export const MODULAR_MIN = 1.05;
|
|
76
|
+
export const MODULAR_MAX = 2;
|
|
77
|
+
/**
|
|
78
|
+
* The rungs a modular scale REGENERATES, in order, and the one it starts from.
|
|
79
|
+
*
|
|
80
|
+
* It deliberately stops at the display register. A geometric scale through the
|
|
81
|
+
* interface rungs is unusable at any real ratio: at 1.25 from a 14px base the
|
|
82
|
+
* next rungs are 17.5 and 21.9, so the 13px nav label and the 15px lead — the
|
|
83
|
+
* near-linear steps a dense interface is built on — do not exist. `xl` is the
|
|
84
|
+
* anchor because it is the last interface rung, so the display half continues
|
|
85
|
+
* from where the interface ends rather than restarting under it.
|
|
86
|
+
*/
|
|
87
|
+
const DISPLAY_RUNGS = ["2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"];
|
|
88
|
+
const MODULAR_ANCHOR_REM = 1.0625; // --text-xl, 17px
|
|
52
89
|
/**
|
|
53
90
|
* Density moves SPACING only, and its range is much tighter than type's.
|
|
54
91
|
*
|
|
@@ -128,6 +165,26 @@ export function vars(p) {
|
|
|
128
165
|
if (typeof p.ratio === "number" && Number.isFinite(p.ratio)) {
|
|
129
166
|
out["--type-ratio"] = round(clamp(p.ratio, RATIO_MIN, RATIO_MAX));
|
|
130
167
|
}
|
|
168
|
+
if (typeof p.modular === "number" && Number.isFinite(p.modular)) {
|
|
169
|
+
// Each display rung is the anchor times the ratio to its step, emitted as an
|
|
170
|
+
// explicit property. An INLINE custom property on :root outranks the
|
|
171
|
+
// stylesheet, so these simply replace the authored rungs — nothing has to be
|
|
172
|
+
// unset first, and the interface rungs the sheet declares are untouched
|
|
173
|
+
// because none is named here. It multiplies out with `--type-scale` for free,
|
|
174
|
+
// since every rung is still read through that ramp's own calc.
|
|
175
|
+
const r = clamp(p.modular, MODULAR_MIN, MODULAR_MAX);
|
|
176
|
+
DISPLAY_RUNGS.forEach((rung, i) => {
|
|
177
|
+
const rem = MODULAR_ANCHOR_REM * Math.pow(r, i + 1);
|
|
178
|
+
// THE SAME clamp the authored ramp carries, read from the same two names.
|
|
179
|
+
// A regenerated rung and an authored one must be bounded identically or
|
|
180
|
+
// the bound is a property of which code path produced the value, which is
|
|
181
|
+
// exactly the kind of "it depends" a design system exists to delete. The
|
|
182
|
+
// bounds are declared once, in tokens/typography.css, and referenced here
|
|
183
|
+
// — never restated, so moving one moves both.
|
|
184
|
+
out[`--text-${rung}`] =
|
|
185
|
+
`clamp(var(--text-floor), calc(${round(rem)}rem * var(--type-scale, 1)), var(--text-ceiling))`;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
131
188
|
if (p.density && p.density in DENSITY) {
|
|
132
189
|
out["--density"] = round(DENSITY[p.density]);
|
|
133
190
|
}
|
package/dist/tokens.gen.d.ts
CHANGED
|
@@ -15,20 +15,25 @@ export declare const colors: {
|
|
|
15
15
|
readonly 'pure-white': "#FFFFFF";
|
|
16
16
|
readonly 'hanzo-black': "#0A0A0B";
|
|
17
17
|
readonly 'hanzo-white': "#FFFFFF";
|
|
18
|
+
readonly 'white-03': "rgb(255 255 255 / .03)";
|
|
18
19
|
readonly 'white-05': "rgb(255 255 255 / .05)";
|
|
19
20
|
readonly 'white-06': "rgb(255 255 255 / .06)";
|
|
20
21
|
readonly 'white-08': "rgb(255 255 255 / .08)";
|
|
21
22
|
readonly 'white-10': "rgb(255 255 255 / .10)";
|
|
23
|
+
readonly 'white-14': "rgb(255 255 255 / .14)";
|
|
22
24
|
readonly 'white-15': "rgb(255 255 255 / .15)";
|
|
23
25
|
readonly 'white-16': "rgb(255 255 255 / .16)";
|
|
26
|
+
readonly 'white-18': "rgb(255 255 255 / .18)";
|
|
24
27
|
readonly 'white-20': "rgb(255 255 255 / .20)";
|
|
25
28
|
readonly 'white-22': "rgb(255 255 255 / .22)";
|
|
26
29
|
readonly 'white-30': "rgb(255 255 255 / .30)";
|
|
27
30
|
readonly 'white-40': "rgb(255 255 255 / .40)";
|
|
31
|
+
readonly 'white-45': "rgb(255 255 255 / .45)";
|
|
28
32
|
readonly 'white-55': "rgb(255 255 255 / .55)";
|
|
29
33
|
readonly 'white-60': "rgb(255 255 255 / .60)";
|
|
30
34
|
readonly 'white-78': "rgb(255 255 255 / .78)";
|
|
31
35
|
readonly 'white-80': "rgb(255 255 255 / .80)";
|
|
36
|
+
readonly 'white-92': "rgb(255 255 255 / .92)";
|
|
32
37
|
readonly background: "#0a0a0a";
|
|
33
38
|
readonly foreground: "#fafafa";
|
|
34
39
|
readonly card: "#0f0f0f";
|
|
@@ -93,6 +98,8 @@ export declare const colors: {
|
|
|
93
98
|
export declare const typography: {
|
|
94
99
|
readonly 'type-scale': "1";
|
|
95
100
|
readonly 'type-ratio': "1";
|
|
101
|
+
readonly 'text-floor': "0.625rem";
|
|
102
|
+
readonly 'text-ceiling': "30vw";
|
|
96
103
|
readonly 'text-xs': "0.6875rem";
|
|
97
104
|
readonly 'leading-xs': "1rem";
|
|
98
105
|
readonly 'text-sm': "0.8125rem";
|
|
@@ -311,20 +318,25 @@ export declare const cssVars: {
|
|
|
311
318
|
readonly '--pure-white': "#FFFFFF";
|
|
312
319
|
readonly '--hanzo-black': "#0A0A0B";
|
|
313
320
|
readonly '--hanzo-white': "#FFFFFF";
|
|
321
|
+
readonly '--white-03': "rgb(255 255 255 / .03)";
|
|
314
322
|
readonly '--white-05': "rgb(255 255 255 / .05)";
|
|
315
323
|
readonly '--white-06': "rgb(255 255 255 / .06)";
|
|
316
324
|
readonly '--white-08': "rgb(255 255 255 / .08)";
|
|
317
325
|
readonly '--white-10': "rgb(255 255 255 / .10)";
|
|
326
|
+
readonly '--white-14': "rgb(255 255 255 / .14)";
|
|
318
327
|
readonly '--white-15': "rgb(255 255 255 / .15)";
|
|
319
328
|
readonly '--white-16': "rgb(255 255 255 / .16)";
|
|
329
|
+
readonly '--white-18': "rgb(255 255 255 / .18)";
|
|
320
330
|
readonly '--white-20': "rgb(255 255 255 / .20)";
|
|
321
331
|
readonly '--white-22': "rgb(255 255 255 / .22)";
|
|
322
332
|
readonly '--white-30': "rgb(255 255 255 / .30)";
|
|
323
333
|
readonly '--white-40': "rgb(255 255 255 / .40)";
|
|
334
|
+
readonly '--white-45': "rgb(255 255 255 / .45)";
|
|
324
335
|
readonly '--white-55': "rgb(255 255 255 / .55)";
|
|
325
336
|
readonly '--white-60': "rgb(255 255 255 / .60)";
|
|
326
337
|
readonly '--white-78': "rgb(255 255 255 / .78)";
|
|
327
338
|
readonly '--white-80': "rgb(255 255 255 / .80)";
|
|
339
|
+
readonly '--white-92': "rgb(255 255 255 / .92)";
|
|
328
340
|
readonly '--background': "#0a0a0a";
|
|
329
341
|
readonly '--foreground': "#fafafa";
|
|
330
342
|
readonly '--card': "#0f0f0f";
|
|
@@ -386,6 +398,8 @@ export declare const cssVars: {
|
|
|
386
398
|
readonly '--chrome-dot-green': "rgb(34 197 94 / .6)";
|
|
387
399
|
readonly '--type-scale': "1";
|
|
388
400
|
readonly '--type-ratio': "1";
|
|
401
|
+
readonly '--text-floor': "0.625rem";
|
|
402
|
+
readonly '--text-ceiling': "30vw";
|
|
389
403
|
readonly '--text-xs': "0.6875rem";
|
|
390
404
|
readonly '--leading-xs': "1rem";
|
|
391
405
|
readonly '--text-sm': "0.8125rem";
|
package/dist/tokens.gen.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8FT,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEb,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2CV,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;;;;;;;;;;;CAYP,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;CAST,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BZ,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAaT,CAAA;AAEV,6DAA6D;AAC7D,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAA;AAEV,gEAAgE;AAChE,eAAO,MAAM,KAAK;;;;;;CAMR,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI,IAEP,CAAA;AAEV,sFAAsF;AACtF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmRV,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAA"}
|
package/dist/tokens.gen.js
CHANGED
|
@@ -18,20 +18,25 @@ export const colors = {
|
|
|
18
18
|
'pure-white': '#FFFFFF',
|
|
19
19
|
'hanzo-black': '#0A0A0B',
|
|
20
20
|
'hanzo-white': '#FFFFFF',
|
|
21
|
+
'white-03': 'rgb(255 255 255 / .03)',
|
|
21
22
|
'white-05': 'rgb(255 255 255 / .05)',
|
|
22
23
|
'white-06': 'rgb(255 255 255 / .06)',
|
|
23
24
|
'white-08': 'rgb(255 255 255 / .08)',
|
|
24
25
|
'white-10': 'rgb(255 255 255 / .10)',
|
|
26
|
+
'white-14': 'rgb(255 255 255 / .14)',
|
|
25
27
|
'white-15': 'rgb(255 255 255 / .15)',
|
|
26
28
|
'white-16': 'rgb(255 255 255 / .16)',
|
|
29
|
+
'white-18': 'rgb(255 255 255 / .18)',
|
|
27
30
|
'white-20': 'rgb(255 255 255 / .20)',
|
|
28
31
|
'white-22': 'rgb(255 255 255 / .22)',
|
|
29
32
|
'white-30': 'rgb(255 255 255 / .30)',
|
|
30
33
|
'white-40': 'rgb(255 255 255 / .40)',
|
|
34
|
+
'white-45': 'rgb(255 255 255 / .45)',
|
|
31
35
|
'white-55': 'rgb(255 255 255 / .55)',
|
|
32
36
|
'white-60': 'rgb(255 255 255 / .60)',
|
|
33
37
|
'white-78': 'rgb(255 255 255 / .78)',
|
|
34
38
|
'white-80': 'rgb(255 255 255 / .80)',
|
|
39
|
+
'white-92': 'rgb(255 255 255 / .92)',
|
|
35
40
|
'background': '#0a0a0a',
|
|
36
41
|
'foreground': '#fafafa',
|
|
37
42
|
'card': '#0f0f0f',
|
|
@@ -96,6 +101,8 @@ export const colors = {
|
|
|
96
101
|
export const typography = {
|
|
97
102
|
'type-scale': '1',
|
|
98
103
|
'type-ratio': '1',
|
|
104
|
+
'text-floor': '0.625rem',
|
|
105
|
+
'text-ceiling': '30vw',
|
|
99
106
|
'text-xs': '0.6875rem',
|
|
100
107
|
'leading-xs': '1rem',
|
|
101
108
|
'text-sm': '0.8125rem',
|
|
@@ -314,20 +321,25 @@ export const cssVars = {
|
|
|
314
321
|
'--pure-white': '#FFFFFF',
|
|
315
322
|
'--hanzo-black': '#0A0A0B',
|
|
316
323
|
'--hanzo-white': '#FFFFFF',
|
|
324
|
+
'--white-03': 'rgb(255 255 255 / .03)',
|
|
317
325
|
'--white-05': 'rgb(255 255 255 / .05)',
|
|
318
326
|
'--white-06': 'rgb(255 255 255 / .06)',
|
|
319
327
|
'--white-08': 'rgb(255 255 255 / .08)',
|
|
320
328
|
'--white-10': 'rgb(255 255 255 / .10)',
|
|
329
|
+
'--white-14': 'rgb(255 255 255 / .14)',
|
|
321
330
|
'--white-15': 'rgb(255 255 255 / .15)',
|
|
322
331
|
'--white-16': 'rgb(255 255 255 / .16)',
|
|
332
|
+
'--white-18': 'rgb(255 255 255 / .18)',
|
|
323
333
|
'--white-20': 'rgb(255 255 255 / .20)',
|
|
324
334
|
'--white-22': 'rgb(255 255 255 / .22)',
|
|
325
335
|
'--white-30': 'rgb(255 255 255 / .30)',
|
|
326
336
|
'--white-40': 'rgb(255 255 255 / .40)',
|
|
337
|
+
'--white-45': 'rgb(255 255 255 / .45)',
|
|
327
338
|
'--white-55': 'rgb(255 255 255 / .55)',
|
|
328
339
|
'--white-60': 'rgb(255 255 255 / .60)',
|
|
329
340
|
'--white-78': 'rgb(255 255 255 / .78)',
|
|
330
341
|
'--white-80': 'rgb(255 255 255 / .80)',
|
|
342
|
+
'--white-92': 'rgb(255 255 255 / .92)',
|
|
331
343
|
'--background': '#0a0a0a',
|
|
332
344
|
'--foreground': '#fafafa',
|
|
333
345
|
'--card': '#0f0f0f',
|
|
@@ -389,6 +401,8 @@ export const cssVars = {
|
|
|
389
401
|
'--chrome-dot-green': 'rgb(34 197 94 / .6)',
|
|
390
402
|
'--type-scale': '1',
|
|
391
403
|
'--type-ratio': '1',
|
|
404
|
+
'--text-floor': '0.625rem',
|
|
405
|
+
'--text-ceiling': '30vw',
|
|
392
406
|
'--text-xs': '0.6875rem',
|
|
393
407
|
'--leading-xs': '1rem',
|
|
394
408
|
'--text-sm': '0.8125rem',
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/design",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"packageManager": "pnpm@11.17.0",
|
|
3
|
+
"version": "0.5.13",
|
|
5
4
|
"description": "Hanzo Design System — monochrome, dark-default tokens + components + brand assets, the single source of truth for every Hanzo surface. CSS + typed programmatic tokens.",
|
|
6
5
|
"license": "MIT OR Apache-2.0",
|
|
7
6
|
"repository": {
|
|
@@ -32,13 +31,6 @@
|
|
|
32
31
|
"./skills/*": "./skills/*",
|
|
33
32
|
"./tailwind.css": "./tailwind.css"
|
|
34
33
|
},
|
|
35
|
-
"scripts": {
|
|
36
|
-
"gen": "node scripts/gen-tokens.mjs",
|
|
37
|
-
"test": "node scripts/check-tokens.mjs && node scripts/check-preference.mjs && node scripts/lint.mjs .",
|
|
38
|
-
"build": "pnpm gen && pnpm test && tsc -p tsconfig.json && node scripts/check-dist.mjs",
|
|
39
|
-
"prepublishOnly": "pnpm build",
|
|
40
|
-
"lint": "node scripts/lint.mjs"
|
|
41
|
-
},
|
|
42
34
|
"devDependencies": {
|
|
43
35
|
"typescript": "^5.9.3"
|
|
44
36
|
},
|
|
@@ -71,5 +63,11 @@
|
|
|
71
63
|
},
|
|
72
64
|
"bin": {
|
|
73
65
|
"hanzo-design-lint": "./scripts/lint.mjs"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"gen": "node scripts/gen-tokens.mjs",
|
|
69
|
+
"test": "node scripts/check-tokens.mjs && node scripts/check-preference.mjs && node scripts/lint.mjs .",
|
|
70
|
+
"build": "pnpm gen && pnpm test && tsc -p tsconfig.json && node scripts/check-dist.mjs",
|
|
71
|
+
"lint": "node scripts/lint.mjs"
|
|
74
72
|
}
|
|
75
|
-
}
|
|
73
|
+
}
|
|
@@ -102,6 +102,12 @@ check("EVERY ramp rung carries its multiplier — no rung can opt out", () => {
|
|
|
102
102
|
const value = m[1].trim();
|
|
103
103
|
if (value === "0") continue; // zero times anything is zero
|
|
104
104
|
if (value.startsWith("var(")) continue; // an alias inherits its target's calc
|
|
105
|
+
// --text-floor / --text-ceiling are the BOUNDS every rung is clamped
|
|
106
|
+
// between, not rungs. A bound that scaled with the knob would move with
|
|
107
|
+
// the value it exists to bound and could never bind — which is the whole
|
|
108
|
+
// reason a floor is stated in absolute units and a ceiling in the
|
|
109
|
+
// viewport's.
|
|
110
|
+
if (/^--text-(floor|ceiling):/.test(m[0])) continue;
|
|
105
111
|
if (!value.includes(`var(${knob}`)) bare.push(`${file}: ${m[0].trim()}`);
|
|
106
112
|
}
|
|
107
113
|
}
|
|
@@ -144,6 +150,45 @@ check("an unknown stored value is refused, not passed through", () => {
|
|
|
144
150
|
eq(vars({ width: "enormous" }), {});
|
|
145
151
|
});
|
|
146
152
|
|
|
153
|
+
check("a modular scale regenerates the DISPLAY rungs, geometrically", () => {
|
|
154
|
+
const v = vars({ modular: 1.618 });
|
|
155
|
+
const names = Object.keys(v);
|
|
156
|
+
eq(names.length, 8, "a modular scale emits the eight display rungs:");
|
|
157
|
+
// Each rung is the one below it times the ratio — that IS the scale.
|
|
158
|
+
const rem = (n) => parseFloat(v[`--text-${n}`].match(/([\d.]+)rem/)[1]);
|
|
159
|
+
const rungs = ["2xl","3xl","4xl","5xl","6xl","7xl","8xl","9xl"];
|
|
160
|
+
for (let i = 1; i < rungs.length; i++) {
|
|
161
|
+
const r = rem(rungs[i]) / rem(rungs[i - 1]);
|
|
162
|
+
ok(Math.abs(r - 1.618) < 0.001, `${rungs[i]}/${rungs[i-1]} = ${r}, want the ratio`);
|
|
163
|
+
}
|
|
164
|
+
// Anchored on xl (17px), so the display half continues the interface rather
|
|
165
|
+
// than restarting under it.
|
|
166
|
+
ok(Math.abs(rem("2xl") - 1.0625 * 1.618) < 0.001, "2xl must be xl x ratio");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
check("a modular scale leaves the INTERFACE rungs alone", () => {
|
|
170
|
+
// A geometric scale through xs..xl is unusable at any real ratio: the 13px nav
|
|
171
|
+
// label and the 15px lead simply do not exist on one.
|
|
172
|
+
const emitted = Object.keys(vars({ modular: 1.618 }));
|
|
173
|
+
for (const n of ["--text-xs", "--text-sm", "--text-base", "--text-lg", "--text-xl"]) {
|
|
174
|
+
ok(!emitted.includes(n), `${n} is the interface register and must not be regenerated`);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
check("a modular scale still answers to the size knob", () => {
|
|
179
|
+
// It multiplies out with --type-scale rather than freezing a px value.
|
|
180
|
+
ok(vars({ modular: 1.5 })["--text-4xl"].includes("var(--type-scale, 1)"),
|
|
181
|
+
"a regenerated rung must carry the size knob");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
check("the modular ratio is CLAMPED to something that is still a scale", () => {
|
|
185
|
+
// At 1 every display rung collapses onto the one below it.
|
|
186
|
+
const flat = vars({ modular: 1 });
|
|
187
|
+
const rem = (v, n) => parseFloat(v[`--text-${n}`].match(/([\d.]+)rem/)[1]);
|
|
188
|
+
ok(rem(flat, "3xl") > rem(flat, "2xl"), "a clamped ratio must still ascend");
|
|
189
|
+
eq(vars({ modular: 99 })["--text-2xl"], vars({ modular: 2 })["--text-2xl"], "max:");
|
|
190
|
+
});
|
|
191
|
+
|
|
147
192
|
check("a colour lands on both --primary and --accent", () => {
|
|
148
193
|
const v = vars({ accent: "#808000" });
|
|
149
194
|
eq(v["--primary"], "#808000");
|
package/scripts/gen-tokens.mjs
CHANGED
|
@@ -64,12 +64,24 @@ function parse(css) {
|
|
|
64
64
|
* against a knob the table does not have.
|
|
65
65
|
*/
|
|
66
66
|
const KNOB = /^calc\(\s*([^*]+?)\s*\*\s*var\(--(?:type-scale|density),\s*1\)\s*\)$/
|
|
67
|
-
|
|
67
|
+
// The BOUNDS peel first. Every rung is `clamp(floor, value, ceiling)` — one
|
|
68
|
+
// rule at both ends — and the table carries the VALUE: a bound is a rendering
|
|
69
|
+
// decision the browser makes against a live viewport, so a JS table cannot hold
|
|
70
|
+
// one and must not pretend to. `max(floor, value)` is the older one-ended form,
|
|
71
|
+
// kept so a token file mid-migration still generates.
|
|
72
|
+
const BOUNDS = [
|
|
73
|
+
/^clamp\(\s*[^,]+,\s*(calc\(.*\))\s*,\s*[^,]+\)$/,
|
|
74
|
+
/^max\(\s*[\d.]+[a-z%]*\s*,\s*(calc\(.+\))\s*\)$/,
|
|
75
|
+
]
|
|
68
76
|
const RUNG =
|
|
69
77
|
/^calc\(\(\s*([\d.]+)(r?em|px)\s*([+-])\s*([\d.]+)(?:r?em|px)\s*\*\s*var\(--type-ratio,\s*1\)\s*\)\s*\*\s*var\(--type-scale,\s*1\)\s*\)$/
|
|
70
78
|
|
|
71
79
|
const scale = (v) => {
|
|
72
|
-
|
|
80
|
+
let inner = v
|
|
81
|
+
for (const b of BOUNDS) {
|
|
82
|
+
const m = inner.match(b)
|
|
83
|
+
if (m) { inner = m[1]; break }
|
|
84
|
+
}
|
|
73
85
|
const r = inner.match(RUNG)
|
|
74
86
|
if (r) {
|
|
75
87
|
const [, anchor, unit, sign, delta] = r
|
package/src/preference.ts
CHANGED
|
@@ -46,6 +46,11 @@ export interface Preference {
|
|
|
46
46
|
* above 1 opens the display end and tightens the small one.
|
|
47
47
|
*/
|
|
48
48
|
ratio?: number;
|
|
49
|
+
/**
|
|
50
|
+
* A modular scale for the display rungs — 1.618 for golden, 1.25 for a major
|
|
51
|
+
* third. Absent means the authored ramp, which is the tuned default.
|
|
52
|
+
*/
|
|
53
|
+
modular?: number;
|
|
49
54
|
density?: Density;
|
|
50
55
|
/** Which face the page is set in. */
|
|
51
56
|
font?: Face;
|
|
@@ -81,6 +86,45 @@ export const TYPE_MAX = 1.4;
|
|
|
81
86
|
export const RATIO_MIN = 0.75;
|
|
82
87
|
export const RATIO_MAX = 1.5;
|
|
83
88
|
|
|
89
|
+
/**
|
|
90
|
+
* A MODULAR scale — the classical one, where each display rung is the one below
|
|
91
|
+
* it times a fixed ratio. Golden is 1.618; the musical intervals designers name
|
|
92
|
+
* are 1.2 (minor third), 1.25 (major third), 1.333 (perfect fourth) and 1.5
|
|
93
|
+
* (perfect fifth).
|
|
94
|
+
*
|
|
95
|
+
* This is a different RULE from `ratio`, not another dial on it. `ratio` tunes
|
|
96
|
+
* the contrast of the ramp `tokens/typography.css` authored; this REPLACES that
|
|
97
|
+
* ramp's display half with a geometric one. Naming a golden-ratio preset as a
|
|
98
|
+
* contrast value would have been the dishonest version of this feature.
|
|
99
|
+
*
|
|
100
|
+
* Bounded below 1.05 because a ratio at 1 is not a scale — every display rung
|
|
101
|
+
* collapses onto the one before it — and above 2 because doubling every step
|
|
102
|
+
* puts the fourth rung past a phone's whole width.
|
|
103
|
+
*
|
|
104
|
+
* Golden is exactly 1.618 here and is NOT clamped down to something tamer,
|
|
105
|
+
* because a scale that quietly gives you not-golden when you asked for golden is
|
|
106
|
+
* worse than one that refuses. What makes that safe is the ceiling below: this
|
|
107
|
+
* ramp has EIGHT display rungs and a classical modular scale is used with about
|
|
108
|
+
* four, so at 1.618 the eighth would be 799px. Measured, --text-8xl and
|
|
109
|
+
* --text-9xl are referenced in 15 files across the fleet, so that is a broken
|
|
110
|
+
* page and not a hypothetical.
|
|
111
|
+
*/
|
|
112
|
+
export const MODULAR_MIN = 1.05;
|
|
113
|
+
export const MODULAR_MAX = 2;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The rungs a modular scale REGENERATES, in order, and the one it starts from.
|
|
117
|
+
*
|
|
118
|
+
* It deliberately stops at the display register. A geometric scale through the
|
|
119
|
+
* interface rungs is unusable at any real ratio: at 1.25 from a 14px base the
|
|
120
|
+
* next rungs are 17.5 and 21.9, so the 13px nav label and the 15px lead — the
|
|
121
|
+
* near-linear steps a dense interface is built on — do not exist. `xl` is the
|
|
122
|
+
* anchor because it is the last interface rung, so the display half continues
|
|
123
|
+
* from where the interface ends rather than restarting under it.
|
|
124
|
+
*/
|
|
125
|
+
const DISPLAY_RUNGS = ["2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"];
|
|
126
|
+
const MODULAR_ANCHOR_REM = 1.0625; // --text-xl, 17px
|
|
127
|
+
|
|
84
128
|
/**
|
|
85
129
|
* Density moves SPACING only, and its range is much tighter than type's.
|
|
86
130
|
*
|
|
@@ -169,6 +213,27 @@ export function vars(p: Preference): Record<string, string> {
|
|
|
169
213
|
out["--type-ratio"] = round(clamp(p.ratio, RATIO_MIN, RATIO_MAX));
|
|
170
214
|
}
|
|
171
215
|
|
|
216
|
+
if (typeof p.modular === "number" && Number.isFinite(p.modular)) {
|
|
217
|
+
// Each display rung is the anchor times the ratio to its step, emitted as an
|
|
218
|
+
// explicit property. An INLINE custom property on :root outranks the
|
|
219
|
+
// stylesheet, so these simply replace the authored rungs — nothing has to be
|
|
220
|
+
// unset first, and the interface rungs the sheet declares are untouched
|
|
221
|
+
// because none is named here. It multiplies out with `--type-scale` for free,
|
|
222
|
+
// since every rung is still read through that ramp's own calc.
|
|
223
|
+
const r = clamp(p.modular, MODULAR_MIN, MODULAR_MAX);
|
|
224
|
+
DISPLAY_RUNGS.forEach((rung, i) => {
|
|
225
|
+
const rem = MODULAR_ANCHOR_REM * Math.pow(r, i + 1);
|
|
226
|
+
// THE SAME clamp the authored ramp carries, read from the same two names.
|
|
227
|
+
// A regenerated rung and an authored one must be bounded identically or
|
|
228
|
+
// the bound is a property of which code path produced the value, which is
|
|
229
|
+
// exactly the kind of "it depends" a design system exists to delete. The
|
|
230
|
+
// bounds are declared once, in tokens/typography.css, and referenced here
|
|
231
|
+
// — never restated, so moving one moves both.
|
|
232
|
+
out[`--text-${rung}`] =
|
|
233
|
+
`clamp(var(--text-floor), calc(${round(rem)}rem * var(--type-scale, 1)), var(--text-ceiling))`;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
172
237
|
if (p.density && p.density in DENSITY) {
|
|
173
238
|
out["--density"] = round(DENSITY[p.density]);
|
|
174
239
|
}
|
package/src/tokens.gen.ts
CHANGED
|
@@ -19,20 +19,25 @@ export const colors = {
|
|
|
19
19
|
'pure-white': '#FFFFFF',
|
|
20
20
|
'hanzo-black': '#0A0A0B',
|
|
21
21
|
'hanzo-white': '#FFFFFF',
|
|
22
|
+
'white-03': 'rgb(255 255 255 / .03)',
|
|
22
23
|
'white-05': 'rgb(255 255 255 / .05)',
|
|
23
24
|
'white-06': 'rgb(255 255 255 / .06)',
|
|
24
25
|
'white-08': 'rgb(255 255 255 / .08)',
|
|
25
26
|
'white-10': 'rgb(255 255 255 / .10)',
|
|
27
|
+
'white-14': 'rgb(255 255 255 / .14)',
|
|
26
28
|
'white-15': 'rgb(255 255 255 / .15)',
|
|
27
29
|
'white-16': 'rgb(255 255 255 / .16)',
|
|
30
|
+
'white-18': 'rgb(255 255 255 / .18)',
|
|
28
31
|
'white-20': 'rgb(255 255 255 / .20)',
|
|
29
32
|
'white-22': 'rgb(255 255 255 / .22)',
|
|
30
33
|
'white-30': 'rgb(255 255 255 / .30)',
|
|
31
34
|
'white-40': 'rgb(255 255 255 / .40)',
|
|
35
|
+
'white-45': 'rgb(255 255 255 / .45)',
|
|
32
36
|
'white-55': 'rgb(255 255 255 / .55)',
|
|
33
37
|
'white-60': 'rgb(255 255 255 / .60)',
|
|
34
38
|
'white-78': 'rgb(255 255 255 / .78)',
|
|
35
39
|
'white-80': 'rgb(255 255 255 / .80)',
|
|
40
|
+
'white-92': 'rgb(255 255 255 / .92)',
|
|
36
41
|
'background': '#0a0a0a',
|
|
37
42
|
'foreground': '#fafafa',
|
|
38
43
|
'card': '#0f0f0f',
|
|
@@ -98,6 +103,8 @@ export const colors = {
|
|
|
98
103
|
export const typography = {
|
|
99
104
|
'type-scale': '1',
|
|
100
105
|
'type-ratio': '1',
|
|
106
|
+
'text-floor': '0.625rem',
|
|
107
|
+
'text-ceiling': '30vw',
|
|
101
108
|
'text-xs': '0.6875rem',
|
|
102
109
|
'leading-xs': '1rem',
|
|
103
110
|
'text-sm': '0.8125rem',
|
|
@@ -327,20 +334,25 @@ export const cssVars = {
|
|
|
327
334
|
'--pure-white': '#FFFFFF',
|
|
328
335
|
'--hanzo-black': '#0A0A0B',
|
|
329
336
|
'--hanzo-white': '#FFFFFF',
|
|
337
|
+
'--white-03': 'rgb(255 255 255 / .03)',
|
|
330
338
|
'--white-05': 'rgb(255 255 255 / .05)',
|
|
331
339
|
'--white-06': 'rgb(255 255 255 / .06)',
|
|
332
340
|
'--white-08': 'rgb(255 255 255 / .08)',
|
|
333
341
|
'--white-10': 'rgb(255 255 255 / .10)',
|
|
342
|
+
'--white-14': 'rgb(255 255 255 / .14)',
|
|
334
343
|
'--white-15': 'rgb(255 255 255 / .15)',
|
|
335
344
|
'--white-16': 'rgb(255 255 255 / .16)',
|
|
345
|
+
'--white-18': 'rgb(255 255 255 / .18)',
|
|
336
346
|
'--white-20': 'rgb(255 255 255 / .20)',
|
|
337
347
|
'--white-22': 'rgb(255 255 255 / .22)',
|
|
338
348
|
'--white-30': 'rgb(255 255 255 / .30)',
|
|
339
349
|
'--white-40': 'rgb(255 255 255 / .40)',
|
|
350
|
+
'--white-45': 'rgb(255 255 255 / .45)',
|
|
340
351
|
'--white-55': 'rgb(255 255 255 / .55)',
|
|
341
352
|
'--white-60': 'rgb(255 255 255 / .60)',
|
|
342
353
|
'--white-78': 'rgb(255 255 255 / .78)',
|
|
343
354
|
'--white-80': 'rgb(255 255 255 / .80)',
|
|
355
|
+
'--white-92': 'rgb(255 255 255 / .92)',
|
|
344
356
|
'--background': '#0a0a0a',
|
|
345
357
|
'--foreground': '#fafafa',
|
|
346
358
|
'--card': '#0f0f0f',
|
|
@@ -402,6 +414,8 @@ export const cssVars = {
|
|
|
402
414
|
'--chrome-dot-green': 'rgb(34 197 94 / .6)',
|
|
403
415
|
'--type-scale': '1',
|
|
404
416
|
'--type-ratio': '1',
|
|
417
|
+
'--text-floor': '0.625rem',
|
|
418
|
+
'--text-ceiling': '30vw',
|
|
405
419
|
'--text-xs': '0.6875rem',
|
|
406
420
|
'--leading-xs': '1rem',
|
|
407
421
|
'--text-sm': '0.8125rem',
|
package/styles.css
CHANGED
|
@@ -56,20 +56,39 @@
|
|
|
56
56
|
/* ——— the opacity ladder: the real palette ——— */
|
|
57
57
|
/* Every rung below .30 is a HAIRLINE or a LIFT — the two things this system
|
|
58
58
|
draws with. The rungs are the reference's own values, not a rounded ramp. */
|
|
59
|
+
/* The five rungs marked (chrome) below were being retyped as raw rgba in
|
|
60
|
+
@hanzogui/shell's theme.ts, which is the shared bar every Hanzo property
|
|
61
|
+
mounts. That is the same defect this ladder exists to end — a value in two
|
|
62
|
+
places drifts, and this pair already had: the shell's resting hairline sat
|
|
63
|
+
at .06 against this file's .10 for long enough that the bar and the page
|
|
64
|
+
under it drew different hairlines. They are rungs here now, and the shell
|
|
65
|
+
references them, so the chrome has no colour of its own left to drift.
|
|
66
|
+
|
|
67
|
+
They are the shell's OWN measured values, added at the alpha it already
|
|
68
|
+
ships. Snapping them to neighbouring rungs instead would have been a
|
|
69
|
+
silent redesign of the estate's chrome, and two of them carry decisions
|
|
70
|
+
that a round number would have destroyed: .92 is ink deliberately short of
|
|
71
|
+
the .98 hover so a hover still reads as a response, and .03 is the one
|
|
72
|
+
lift that must stay below the .05 hairline it sits inside. */
|
|
73
|
+
--white-03:rgb(255 255 255 / .03); /* (chrome) the raised fill */
|
|
59
74
|
--white-05:rgb(255 255 255 / .05);
|
|
60
75
|
--white-06:rgb(255 255 255 / .06);
|
|
61
76
|
--white-08:rgb(255 255 255 / .08);
|
|
62
77
|
--white-10:rgb(255 255 255 / .10);
|
|
78
|
+
--white-14:rgb(255 255 255 / .14); /* (chrome) selection wash */
|
|
63
79
|
--white-15:rgb(255 255 255 / .15);
|
|
64
80
|
--white-16:rgb(255 255 255 / .16);
|
|
81
|
+
--white-18:rgb(255 255 255 / .18); /* (chrome) selection tint */
|
|
65
82
|
--white-20:rgb(255 255 255 / .20);
|
|
66
83
|
--white-22:rgb(255 255 255 / .22);
|
|
67
84
|
--white-30:rgb(255 255 255 / .30);
|
|
68
85
|
--white-40:rgb(255 255 255 / .40);
|
|
86
|
+
--white-45:rgb(255 255 255 / .45); /* (chrome) the dimmest ink */
|
|
69
87
|
--white-55:rgb(255 255 255 / .55);
|
|
70
88
|
--white-60:rgb(255 255 255 / .60);
|
|
71
89
|
--white-78:rgb(255 255 255 / .78);
|
|
72
90
|
--white-80:rgb(255 255 255 / .80);
|
|
91
|
+
--white-92:rgb(255 255 255 / .92); /* (chrome) body ink */
|
|
73
92
|
|
|
74
93
|
/* ——— semantic aliases (dark, the default) ——— */
|
|
75
94
|
--background:#0a0a0a;
|
|
@@ -316,24 +335,36 @@
|
|
|
316
335
|
A rung is one place, so a rung added later needs a delta and nothing else. */
|
|
317
336
|
--type-ratio:1;
|
|
318
337
|
|
|
319
|
-
/*
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
--text-
|
|
335
|
-
--text-
|
|
336
|
-
--text-
|
|
338
|
+
/* EVERY rung is bounded at BOTH ends, by one rule, because the knobs COMPOUND
|
|
339
|
+
and they compound in both directions. Clamping each knob's range separately
|
|
340
|
+
cannot fix either end — 0.85 x 0.9 is inside both bounds and lands at 8.5px
|
|
341
|
+
— so the RESULT is what carries the bound:
|
|
342
|
+
|
|
343
|
+
--text-floor 10px below this a label is not small, it is unreadable
|
|
344
|
+
--text-ceiling 30vw above this a heading is not type, it is a texture
|
|
345
|
+
|
|
346
|
+
The ceiling is in the VIEWPORT's units because that is what "too big" means:
|
|
347
|
+
measured, the tallest rung (--text-9xl, 112px) is 28.7vw on a 390px phone
|
|
348
|
+
and 7.8vw at 1440, so 30vw binds no published value at any real screen and
|
|
349
|
+
catches only a scale that has run away. Both bounds are stated once here and
|
|
350
|
+
`vars()` emits the same clamp for a modular scale, so a regenerated rung and
|
|
351
|
+
an authored one are bounded identically — the rule does not depend on which
|
|
352
|
+
produced the value. */
|
|
353
|
+
--text-floor:0.625rem;
|
|
354
|
+
--text-ceiling:30vw;
|
|
355
|
+
--text-xs:clamp(var(--text-floor), calc((0.875rem - 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xs:calc((1.35rem - 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 11px — eyebrows / section labels */
|
|
356
|
+
--text-sm:clamp(var(--text-floor), calc((0.875rem - 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-sm:calc((1.35rem - 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 13px — nav labels, dense body */
|
|
357
|
+
--text-base:clamp(var(--text-floor), calc(0.875rem * var(--type-scale, 1)), var(--text-ceiling)); --leading-base:calc(1.35rem * var(--type-scale, 1)); /* 14px — the ANCHOR: the rung the ratio pivots on, so it carries no ratio term */
|
|
358
|
+
--text-lg:clamp(var(--text-floor), calc((0.875rem + 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-lg:calc((1.35rem + 0.05rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 15px */
|
|
359
|
+
--text-xl:clamp(var(--text-floor), calc((0.875rem + 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xl:calc((1.35rem + 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 17px */
|
|
360
|
+
--text-2xl:clamp(var(--text-floor), calc((0.875rem + 0.4375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-2xl:calc((1.35rem + 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 21px */
|
|
361
|
+
--text-3xl:clamp(var(--text-floor), calc((0.875rem + 0.75rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-3xl:calc((1.35rem + 0.6rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 26px */
|
|
362
|
+
--text-4xl:clamp(var(--text-floor), calc((0.875rem + 1.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-4xl:calc((1.35rem + 0.9rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 32px */
|
|
363
|
+
--text-5xl:clamp(var(--text-floor), calc((0.875rem + 1.625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-5xl:1.05; /* 40px — display leading is unitless, so it tracks its own size */
|
|
364
|
+
--text-6xl:clamp(var(--text-floor), calc((0.875rem + 2.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-6xl:1; /* 52px */
|
|
365
|
+
--text-7xl:clamp(var(--text-floor), calc((0.875rem + 3.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-7xl:1; /* 64px */
|
|
366
|
+
--text-8xl:clamp(var(--text-floor), calc((0.875rem + 4.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-8xl:1; /* 84px */
|
|
367
|
+
--text-9xl:clamp(var(--text-floor), calc((0.875rem + 6.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-9xl:1; /* 112px */
|
|
337
368
|
|
|
338
369
|
/* The SAME scale under @hanzo/brand's spelling. @hanzo/gui's shell theme and
|
|
339
370
|
Hanzo Studio address the ramp as --font-size-*; both names are one value, so
|
package/tailwind.css
CHANGED
|
@@ -79,20 +79,39 @@
|
|
|
79
79
|
/* ——— the opacity ladder: the real palette ——— */
|
|
80
80
|
/* Every rung below .30 is a HAIRLINE or a LIFT — the two things this system
|
|
81
81
|
draws with. The rungs are the reference's own values, not a rounded ramp. */
|
|
82
|
+
/* The five rungs marked (chrome) below were being retyped as raw rgba in
|
|
83
|
+
@hanzogui/shell's theme.ts, which is the shared bar every Hanzo property
|
|
84
|
+
mounts. That is the same defect this ladder exists to end — a value in two
|
|
85
|
+
places drifts, and this pair already had: the shell's resting hairline sat
|
|
86
|
+
at .06 against this file's .10 for long enough that the bar and the page
|
|
87
|
+
under it drew different hairlines. They are rungs here now, and the shell
|
|
88
|
+
references them, so the chrome has no colour of its own left to drift.
|
|
89
|
+
|
|
90
|
+
They are the shell's OWN measured values, added at the alpha it already
|
|
91
|
+
ships. Snapping them to neighbouring rungs instead would have been a
|
|
92
|
+
silent redesign of the estate's chrome, and two of them carry decisions
|
|
93
|
+
that a round number would have destroyed: .92 is ink deliberately short of
|
|
94
|
+
the .98 hover so a hover still reads as a response, and .03 is the one
|
|
95
|
+
lift that must stay below the .05 hairline it sits inside. */
|
|
96
|
+
--white-03:rgb(255 255 255 / .03); /* (chrome) the raised fill */
|
|
82
97
|
--white-05:rgb(255 255 255 / .05);
|
|
83
98
|
--white-06:rgb(255 255 255 / .06);
|
|
84
99
|
--white-08:rgb(255 255 255 / .08);
|
|
85
100
|
--white-10:rgb(255 255 255 / .10);
|
|
101
|
+
--white-14:rgb(255 255 255 / .14); /* (chrome) selection wash */
|
|
86
102
|
--white-15:rgb(255 255 255 / .15);
|
|
87
103
|
--white-16:rgb(255 255 255 / .16);
|
|
104
|
+
--white-18:rgb(255 255 255 / .18); /* (chrome) selection tint */
|
|
88
105
|
--white-20:rgb(255 255 255 / .20);
|
|
89
106
|
--white-22:rgb(255 255 255 / .22);
|
|
90
107
|
--white-30:rgb(255 255 255 / .30);
|
|
91
108
|
--white-40:rgb(255 255 255 / .40);
|
|
109
|
+
--white-45:rgb(255 255 255 / .45); /* (chrome) the dimmest ink */
|
|
92
110
|
--white-55:rgb(255 255 255 / .55);
|
|
93
111
|
--white-60:rgb(255 255 255 / .60);
|
|
94
112
|
--white-78:rgb(255 255 255 / .78);
|
|
95
113
|
--white-80:rgb(255 255 255 / .80);
|
|
114
|
+
--white-92:rgb(255 255 255 / .92); /* (chrome) body ink */
|
|
96
115
|
|
|
97
116
|
/* ——— semantic aliases (dark, the default) ——— */
|
|
98
117
|
--background:#0a0a0a;
|
|
@@ -339,24 +358,36 @@
|
|
|
339
358
|
A rung is one place, so a rung added later needs a delta and nothing else. */
|
|
340
359
|
--type-ratio:1;
|
|
341
360
|
|
|
342
|
-
/*
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
--text-
|
|
358
|
-
--text-
|
|
359
|
-
--text-
|
|
361
|
+
/* EVERY rung is bounded at BOTH ends, by one rule, because the knobs COMPOUND
|
|
362
|
+
and they compound in both directions. Clamping each knob's range separately
|
|
363
|
+
cannot fix either end — 0.85 x 0.9 is inside both bounds and lands at 8.5px
|
|
364
|
+
— so the RESULT is what carries the bound:
|
|
365
|
+
|
|
366
|
+
--text-floor 10px below this a label is not small, it is unreadable
|
|
367
|
+
--text-ceiling 30vw above this a heading is not type, it is a texture
|
|
368
|
+
|
|
369
|
+
The ceiling is in the VIEWPORT's units because that is what "too big" means:
|
|
370
|
+
measured, the tallest rung (--text-9xl, 112px) is 28.7vw on a 390px phone
|
|
371
|
+
and 7.8vw at 1440, so 30vw binds no published value at any real screen and
|
|
372
|
+
catches only a scale that has run away. Both bounds are stated once here and
|
|
373
|
+
`vars()` emits the same clamp for a modular scale, so a regenerated rung and
|
|
374
|
+
an authored one are bounded identically — the rule does not depend on which
|
|
375
|
+
produced the value. */
|
|
376
|
+
--text-floor:0.625rem;
|
|
377
|
+
--text-ceiling:30vw;
|
|
378
|
+
--text-xs:clamp(var(--text-floor), calc((0.875rem - 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xs:calc((1.35rem - 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 11px — eyebrows / section labels */
|
|
379
|
+
--text-sm:clamp(var(--text-floor), calc((0.875rem - 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-sm:calc((1.35rem - 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 13px — nav labels, dense body */
|
|
380
|
+
--text-base:clamp(var(--text-floor), calc(0.875rem * var(--type-scale, 1)), var(--text-ceiling)); --leading-base:calc(1.35rem * var(--type-scale, 1)); /* 14px — the ANCHOR: the rung the ratio pivots on, so it carries no ratio term */
|
|
381
|
+
--text-lg:clamp(var(--text-floor), calc((0.875rem + 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-lg:calc((1.35rem + 0.05rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 15px */
|
|
382
|
+
--text-xl:clamp(var(--text-floor), calc((0.875rem + 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xl:calc((1.35rem + 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 17px */
|
|
383
|
+
--text-2xl:clamp(var(--text-floor), calc((0.875rem + 0.4375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-2xl:calc((1.35rem + 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 21px */
|
|
384
|
+
--text-3xl:clamp(var(--text-floor), calc((0.875rem + 0.75rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-3xl:calc((1.35rem + 0.6rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 26px */
|
|
385
|
+
--text-4xl:clamp(var(--text-floor), calc((0.875rem + 1.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-4xl:calc((1.35rem + 0.9rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 32px */
|
|
386
|
+
--text-5xl:clamp(var(--text-floor), calc((0.875rem + 1.625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-5xl:1.05; /* 40px — display leading is unitless, so it tracks its own size */
|
|
387
|
+
--text-6xl:clamp(var(--text-floor), calc((0.875rem + 2.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-6xl:1; /* 52px */
|
|
388
|
+
--text-7xl:clamp(var(--text-floor), calc((0.875rem + 3.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-7xl:1; /* 64px */
|
|
389
|
+
--text-8xl:clamp(var(--text-floor), calc((0.875rem + 4.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-8xl:1; /* 84px */
|
|
390
|
+
--text-9xl:clamp(var(--text-floor), calc((0.875rem + 6.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-9xl:1; /* 112px */
|
|
360
391
|
|
|
361
392
|
/* The SAME scale under @hanzo/brand's spelling. @hanzo/gui's shell theme and
|
|
362
393
|
Hanzo Studio address the ramp as --font-size-*; both names are one value, so
|
package/tokens/colors.css
CHANGED
|
@@ -41,20 +41,39 @@
|
|
|
41
41
|
/* ——— the opacity ladder: the real palette ——— */
|
|
42
42
|
/* Every rung below .30 is a HAIRLINE or a LIFT — the two things this system
|
|
43
43
|
draws with. The rungs are the reference's own values, not a rounded ramp. */
|
|
44
|
+
/* The five rungs marked (chrome) below were being retyped as raw rgba in
|
|
45
|
+
@hanzogui/shell's theme.ts, which is the shared bar every Hanzo property
|
|
46
|
+
mounts. That is the same defect this ladder exists to end — a value in two
|
|
47
|
+
places drifts, and this pair already had: the shell's resting hairline sat
|
|
48
|
+
at .06 against this file's .10 for long enough that the bar and the page
|
|
49
|
+
under it drew different hairlines. They are rungs here now, and the shell
|
|
50
|
+
references them, so the chrome has no colour of its own left to drift.
|
|
51
|
+
|
|
52
|
+
They are the shell's OWN measured values, added at the alpha it already
|
|
53
|
+
ships. Snapping them to neighbouring rungs instead would have been a
|
|
54
|
+
silent redesign of the estate's chrome, and two of them carry decisions
|
|
55
|
+
that a round number would have destroyed: .92 is ink deliberately short of
|
|
56
|
+
the .98 hover so a hover still reads as a response, and .03 is the one
|
|
57
|
+
lift that must stay below the .05 hairline it sits inside. */
|
|
58
|
+
--white-03:rgb(255 255 255 / .03); /* (chrome) the raised fill */
|
|
44
59
|
--white-05:rgb(255 255 255 / .05);
|
|
45
60
|
--white-06:rgb(255 255 255 / .06);
|
|
46
61
|
--white-08:rgb(255 255 255 / .08);
|
|
47
62
|
--white-10:rgb(255 255 255 / .10);
|
|
63
|
+
--white-14:rgb(255 255 255 / .14); /* (chrome) selection wash */
|
|
48
64
|
--white-15:rgb(255 255 255 / .15);
|
|
49
65
|
--white-16:rgb(255 255 255 / .16);
|
|
66
|
+
--white-18:rgb(255 255 255 / .18); /* (chrome) selection tint */
|
|
50
67
|
--white-20:rgb(255 255 255 / .20);
|
|
51
68
|
--white-22:rgb(255 255 255 / .22);
|
|
52
69
|
--white-30:rgb(255 255 255 / .30);
|
|
53
70
|
--white-40:rgb(255 255 255 / .40);
|
|
71
|
+
--white-45:rgb(255 255 255 / .45); /* (chrome) the dimmest ink */
|
|
54
72
|
--white-55:rgb(255 255 255 / .55);
|
|
55
73
|
--white-60:rgb(255 255 255 / .60);
|
|
56
74
|
--white-78:rgb(255 255 255 / .78);
|
|
57
75
|
--white-80:rgb(255 255 255 / .80);
|
|
76
|
+
--white-92:rgb(255 255 255 / .92); /* (chrome) body ink */
|
|
58
77
|
|
|
59
78
|
/* ——— semantic aliases (dark, the default) ——— */
|
|
60
79
|
--background:#0a0a0a;
|
package/tokens/typography.css
CHANGED
|
@@ -31,24 +31,36 @@
|
|
|
31
31
|
A rung is one place, so a rung added later needs a delta and nothing else. */
|
|
32
32
|
--type-ratio:1;
|
|
33
33
|
|
|
34
|
-
/*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
--text-
|
|
50
|
-
--text-
|
|
51
|
-
--text-
|
|
34
|
+
/* EVERY rung is bounded at BOTH ends, by one rule, because the knobs COMPOUND
|
|
35
|
+
and they compound in both directions. Clamping each knob's range separately
|
|
36
|
+
cannot fix either end — 0.85 x 0.9 is inside both bounds and lands at 8.5px
|
|
37
|
+
— so the RESULT is what carries the bound:
|
|
38
|
+
|
|
39
|
+
--text-floor 10px below this a label is not small, it is unreadable
|
|
40
|
+
--text-ceiling 30vw above this a heading is not type, it is a texture
|
|
41
|
+
|
|
42
|
+
The ceiling is in the VIEWPORT's units because that is what "too big" means:
|
|
43
|
+
measured, the tallest rung (--text-9xl, 112px) is 28.7vw on a 390px phone
|
|
44
|
+
and 7.8vw at 1440, so 30vw binds no published value at any real screen and
|
|
45
|
+
catches only a scale that has run away. Both bounds are stated once here and
|
|
46
|
+
`vars()` emits the same clamp for a modular scale, so a regenerated rung and
|
|
47
|
+
an authored one are bounded identically — the rule does not depend on which
|
|
48
|
+
produced the value. */
|
|
49
|
+
--text-floor:0.625rem;
|
|
50
|
+
--text-ceiling:30vw;
|
|
51
|
+
--text-xs:clamp(var(--text-floor), calc((0.875rem - 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xs:calc((1.35rem - 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 11px — eyebrows / section labels */
|
|
52
|
+
--text-sm:clamp(var(--text-floor), calc((0.875rem - 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-sm:calc((1.35rem - 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 13px — nav labels, dense body */
|
|
53
|
+
--text-base:clamp(var(--text-floor), calc(0.875rem * var(--type-scale, 1)), var(--text-ceiling)); --leading-base:calc(1.35rem * var(--type-scale, 1)); /* 14px — the ANCHOR: the rung the ratio pivots on, so it carries no ratio term */
|
|
54
|
+
--text-lg:clamp(var(--text-floor), calc((0.875rem + 0.0625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-lg:calc((1.35rem + 0.05rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 15px */
|
|
55
|
+
--text-xl:clamp(var(--text-floor), calc((0.875rem + 0.1875rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-xl:calc((1.35rem + 0.2rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 17px */
|
|
56
|
+
--text-2xl:clamp(var(--text-floor), calc((0.875rem + 0.4375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-2xl:calc((1.35rem + 0.35rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 21px */
|
|
57
|
+
--text-3xl:clamp(var(--text-floor), calc((0.875rem + 0.75rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-3xl:calc((1.35rem + 0.6rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 26px */
|
|
58
|
+
--text-4xl:clamp(var(--text-floor), calc((0.875rem + 1.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-4xl:calc((1.35rem + 0.9rem * var(--type-ratio, 1)) * var(--type-scale, 1)); /* 32px */
|
|
59
|
+
--text-5xl:clamp(var(--text-floor), calc((0.875rem + 1.625rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-5xl:1.05; /* 40px — display leading is unitless, so it tracks its own size */
|
|
60
|
+
--text-6xl:clamp(var(--text-floor), calc((0.875rem + 2.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-6xl:1; /* 52px */
|
|
61
|
+
--text-7xl:clamp(var(--text-floor), calc((0.875rem + 3.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-7xl:1; /* 64px */
|
|
62
|
+
--text-8xl:clamp(var(--text-floor), calc((0.875rem + 4.375rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-8xl:1; /* 84px */
|
|
63
|
+
--text-9xl:clamp(var(--text-floor), calc((0.875rem + 6.125rem * var(--type-ratio, 1)) * var(--type-scale, 1)), var(--text-ceiling)); --leading-9xl:1; /* 112px */
|
|
52
64
|
|
|
53
65
|
/* The SAME scale under @hanzo/brand's spelling. @hanzo/gui's shell theme and
|
|
54
66
|
Hanzo Studio address the ramp as --font-size-*; both names are one value, so
|