jig-ui 0.1.0

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.
@@ -0,0 +1,152 @@
1
+ /* brand.default.css — unbranded default.
2
+ TRANSPARENT foreground palette over SOLID elevation backgrounds.
3
+
4
+ Foregrounds are opacities of black (light) / white (dark). They mix with whatever
5
+ surface they sit on, so a tag keeps the same prominence on base, raised or overlay.
6
+ Solid foregrounds cannot do this: they look right on one background and wrong on
7
+ the next, and dark mode has three.
8
+
9
+ Copy to brand.<client>.css and override. Never edit this file per project. */
10
+
11
+ :root {
12
+ color-scheme: light dark;
13
+
14
+ /* ================= BRAND =================
15
+ One brand colour. It marks interactive elements (I-56).
16
+ Intentionally near-black here: A-01, no invented colour.
17
+ Requirements when you set it:
18
+ - ≥ 4.5:1 against --color-bg-raised AND against --color-fill
19
+ - If the brand colour is red, amber or green, DO NOT use it for interactive
20
+ elements (E-64) — it will collide with the system colours below. */
21
+ --brand-h: 264;
22
+ --brand-s: 0%;
23
+ --brand-l: 15%;
24
+ --brand-base: hsl(var(--brand-h) var(--brand-s) var(--brand-l));
25
+
26
+ /* ================= ELEVATION BACKGROUNDS (solid) =================
27
+ Light comes from above: higher elevation is lighter.
28
+ Keep the three levels visually consistent across light and dark. */
29
+ --color-bg-base: oklch(0.980 0.004 95); /* page. Off-white, not #fff (C-18). */
30
+ --color-bg-raised: oklch(1 0 0); /* cards, panels, sticky bars */
31
+ --color-bg-overlay: oklch(1 0 0); /* dialogs, popovers, dropdowns */
32
+
33
+ /* ================= NEUTRAL FOREGROUNDS (transparent) =================
34
+ Light mode: opacities of black. Never pure black at 100% (C-18). */
35
+ --color-text-strong: rgb(0 0 0 / 90%); /* headings, body, labels — ≥ 4.5:1 */
36
+ --color-text-weak: rgb(0 0 0 / 60%); /* supporting text — ≥ 4.5:1 */
37
+ --color-stroke-strong: rgb(0 0 0 / 45%); /* input/checkbox borders, icons — ≥ 3:1 */
38
+ --color-stroke-weak: rgb(0 0 0 / 10%); /* dividers. Decorative, no floor. */
39
+ --color-fill: rgb(0 0 0 / 4%); /* tags, badges, secondary surfaces */
40
+
41
+ --color-icon: var(--color-stroke-strong);
42
+ --color-icon-weak: var(--color-stroke-weak);
43
+
44
+ /* ================= BRAND FOREGROUNDS (4 variations) ================= */
45
+ --color-text-brand: hsl(var(--brand-h) var(--brand-s) var(--brand-l) / 100%);
46
+ --color-stroke-brand-strong: hsl(var(--brand-h) var(--brand-s) var(--brand-l) / 80%);
47
+ --color-stroke-brand-weak: hsl(var(--brand-h) var(--brand-s) var(--brand-l) / 20%);
48
+ --color-fill-brand: hsl(var(--brand-h) var(--brand-s) var(--brand-l) / 5%);
49
+ --color-on-brand: oklch(1 0 0); /* text on a solid brand fill */
50
+
51
+ /* ================= SYSTEM COLOURS =================
52
+ Three, with familiar traffic-light meanings. Four variations each.
53
+ Never the only signal — pair with an icon and text (C-20). */
54
+ --error-base: hsl(0 71% 44%);
55
+ --warning-base: hsl(42 82% 36%);
56
+ --success-base: hsl(162 95% 26%);
57
+ /* info is NOT in the book's set of three. Kept as an optional fourth. */
58
+ --info-base: hsl(220 70% 42%);
59
+
60
+ --color-text-error: hsl(0 71% 44% / 100%);
61
+ --color-stroke-error-strong: hsl(0 71% 44% / 80%);
62
+ --color-stroke-error-weak: hsl(0 71% 44% / 20%);
63
+ --color-fill-error: hsl(0 71% 44% / 5%);
64
+
65
+ --color-text-warning: hsl(42 82% 36% / 100%);
66
+ --color-stroke-warning-strong: hsl(42 82% 36% / 80%);
67
+ --color-stroke-warning-weak: hsl(42 82% 36% / 20%);
68
+ --color-fill-warning: hsl(42 82% 36% / 5%);
69
+
70
+ --color-text-success: hsl(162 95% 26% / 100%);
71
+ --color-stroke-success-strong: hsl(162 95% 26% / 80%);
72
+ --color-stroke-success-weak: hsl(162 95% 26% / 20%);
73
+ --color-fill-success: hsl(162 95% 26% / 5%);
74
+
75
+ --color-text-info: hsl(220 70% 42% / 100%);
76
+ --color-stroke-info-strong: hsl(220 70% 42% / 80%);
77
+ --color-stroke-info-weak: hsl(220 70% 42% / 20%);
78
+ --color-fill-info: hsl(220 70% 42% / 5%);
79
+
80
+ /* ================= STATE LAYERS =================
81
+ Transparent overlays, so hover and press need no new colours and work on
82
+ every surface and in both modes. Layer these OVER the element. */
83
+ --color-state-hover: var(--color-fill); /* 4% light / 6% dark */
84
+ --color-state-press: var(--color-stroke-weak); /* 10% light / 12% dark */
85
+ --opacity-disabled: 0.38;
86
+
87
+ --color-focus: var(--color-text-strong);
88
+
89
+ /* ================= TYPE ================= */
90
+ --font-text: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
91
+ --font-display: var(--font-text);
92
+ --font-mono: ui-monospace, "SF Mono", "Cascadia Code", monospace;
93
+ --font-numeric-features: "tnum" 1, "lnum" 1;
94
+
95
+ /* ================= RADIUS — three, by element size ================= */
96
+ --radius-sm: 8px; /* buttons, inputs, badges, checkboxes */
97
+ --radius-md: 16px; /* cards, panels */
98
+ --radius-lg: 32px; /* large surfaces, hero media */
99
+ --radius-full: 9999px;
100
+
101
+ /* ================= ELEVATION — two shadows =================
102
+ Shadow colour is derived from the text colour, not pure black, so it sits in
103
+ the palette. Light from above: y-offset positive, blur grows with elevation. */
104
+ --shadow-none: none;
105
+ --shadow-raised: 0 1px 2px rgb(0 0 0 / 6%), 0 2px 4px -2px rgb(0 0 0 / 8%);
106
+ --shadow-overlay: 0 4px 16px -4px rgb(0 0 0 / 14%), 0 1px 3px rgb(0 0 0 / 8%);
107
+ }
108
+
109
+ @media (prefers-color-scheme: dark) {
110
+ :root:not([data-theme="light"]) {
111
+ /* Three solid levels. In dark, DEPTH COMES FROM BACKGROUND, NOT SHADOW —
112
+ shadows are nearly invisible on a dark surface. Never pure black. */
113
+ --color-bg-base: hsl(var(--brand-h) 6% 10%);
114
+ --color-bg-raised: hsl(var(--brand-h) 6% 15%);
115
+ --color-bg-overlay: hsl(var(--brand-h) 6% 20%);
116
+
117
+ /* Foregrounds become opacities of white. Higher than the light-mode values,
118
+ because dark interfaces lose detail faster. */
119
+ --color-text-strong: rgb(255 255 255 / 100%);
120
+ --color-text-weak: rgb(255 255 255 / 78%);
121
+ --color-stroke-strong: rgb(255 255 255 / 60%);
122
+ --color-stroke-weak: rgb(255 255 255 / 12%);
123
+ --color-fill: rgb(255 255 255 / 6%);
124
+
125
+ --brand-l: 88%; /* lighten and desaturate the brand for dark surfaces */
126
+ --color-on-brand: hsl(var(--brand-h) 6% 10%);
127
+
128
+ /* System colours lighten and desaturate in dark mode. */
129
+ --color-text-error: hsl(0 60% 72% / 100%);
130
+ --color-stroke-error-strong: hsl(0 60% 72% / 80%);
131
+ --color-stroke-error-weak: hsl(0 60% 72% / 20%);
132
+ --color-fill-error: hsl(0 60% 72% / 8%);
133
+
134
+ --color-text-warning: hsl(42 70% 70% / 100%);
135
+ --color-stroke-warning-strong: hsl(42 70% 70% / 80%);
136
+ --color-stroke-warning-weak: hsl(42 70% 70% / 20%);
137
+ --color-fill-warning: hsl(42 70% 70% / 8%);
138
+
139
+ --color-text-success: hsl(162 45% 66% / 100%);
140
+ --color-stroke-success-strong: hsl(162 45% 66% / 80%);
141
+ --color-stroke-success-weak: hsl(162 45% 66% / 20%);
142
+ --color-fill-success: hsl(162 45% 66% / 8%);
143
+
144
+ --color-text-info: hsl(220 55% 74% / 100%);
145
+ --color-stroke-info-strong: hsl(220 55% 74% / 80%);
146
+ --color-stroke-info-weak: hsl(220 55% 74% / 20%);
147
+ --color-fill-info: hsl(220 55% 74% / 8%);
148
+
149
+ --shadow-raised: none;
150
+ --shadow-overlay: 0 8px 24px -8px rgb(0 0 0 / 60%);
151
+ }
152
+ }
@@ -0,0 +1,72 @@
1
+ /* mode.editorial.css — marketing, blog, docs, landing.
2
+ Optimises for FIRST use. Legibility over density.
3
+ Spacing uses the shared 8pt option set; modes SELECT options, they do not invent values.
4
+ Load with exactly one brand file. */
5
+
6
+ :root {
7
+ --mode: "editorial";
8
+
9
+ /* ---- Shared spacing options (8pt base). Identical in every mode. ---- */
10
+ /* 2xs is a deliberate half-step off the 8pt grid. It exists ONLY for gaps
11
+ inside a single component — label→input, icon→label — where 8px reads as
12
+ a separation rather than a pairing. Never for layout. */
13
+ --spacing-2xs: 4px;
14
+ --spacing-xs: 8px;
15
+ --spacing-s: 16px;
16
+ --spacing-m: 24px;
17
+ --spacing-l: 32px;
18
+ --spacing-xl: 48px;
19
+ --spacing-xxl: 80px;
20
+
21
+
22
+ /* ---- This mode's selections ---- */
23
+ /* ---- Type scale — 1.250 Major Third. ----
24
+ Large scale: bigger steps, suited to less complex, content-led interfaces.
25
+ Line heights UNITLESS (they must scale with user text size, WCAG 1.4.12).
26
+ FLOOR: 1.5 for anything used as body or long-form text. */
27
+ --text-caption: 14px; --leading-caption: 1.5;
28
+ --text-body: 16px; --leading-body: 1.5; /* UI text: labels, controls */
29
+ --text-prose: 18px; --leading-prose: 1.6; /* LONG-FORM text. Never below 18. */
30
+ --text-lead: 20px; --leading-lead: 1.5;
31
+ --text-h3: 24px; --leading-h3: 1.333;
32
+ --text-h2: 32px; --leading-h2: 1.25;
33
+ --text-h1: 48px; --leading-h1: 1.1;
34
+
35
+ /* Two weights only. More adds noise and is hard to apply consistently. */
36
+ --font-weight-regular: 400;
37
+ --font-weight-bold: 600;
38
+
39
+ /* Letter spacing tightens as size grows; text typefaces are spaced for small sizes. */
40
+ --tracking-body: 0; --tracking-h2: -0.015em; --tracking-h1: -0.025em;
41
+ --tracking-caps: 0.06em;
42
+
43
+ --measure-prose: 68ch; /* 40–80 characters */
44
+
45
+ --spacing-section: var(--spacing-xxl); /* 80 */
46
+ --spacing-section-sm: var(--spacing-xl); /* 48 */
47
+ --spacing-card: var(--spacing-m); /* 24 — card padding is M (D-69) */
48
+ --spacing-stack: var(--spacing-m); /* 24 */
49
+ --spacing-group: var(--spacing-xs); /* 8 */
50
+ --spacing-label: var(--spacing-2xs); /* 4 — label to its input */
51
+ --spacing-inline: var(--spacing-xs); /* 8 */
52
+ --spacing-heading-before: var(--spacing-xl); /* 48 */
53
+ --spacing-heading-after: var(--spacing-s); /* 16 */
54
+
55
+ --grid-columns: 12; --grid-columns-sm: 4;
56
+ --grid-gutter: var(--spacing-l); --grid-gutter-sm: var(--spacing-s); /* 32 → 16 */
57
+ --grid-margin: var(--spacing-xxl); --grid-margin-sm: var(--spacing-s); /* 80 → 16 */
58
+
59
+ --size-control: 48px; --size-control-sm: 40px;
60
+ --size-touch-target: 48px; --size-icon: 20px;
61
+
62
+ --radius-control: var(--radius-sm); --radius-surface: var(--radius-md);
63
+ --shadow-surface: var(--shadow-none);
64
+
65
+ --duration-fast: 150ms; --duration-base: 250ms; --duration-slow: 300ms;
66
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
67
+ --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
68
+ }
69
+
70
+ @media (prefers-reduced-motion: reduce) {
71
+ :root { --duration-fast: 1ms; --duration-base: 1ms; --duration-slow: 1ms; }
72
+ }
@@ -0,0 +1,74 @@
1
+ /* mode.operator.css — internal tools, admin, back-office, monitoring.
2
+ Optimises for the THOUSANDTH use. Density is the feature.
3
+ Accessibility floors are UNCHANGED: touch target, contrast and the 1.5 line-height floor do not shrink.
4
+ Spacing uses the shared 8pt option set; modes SELECT options, they do not invent values.
5
+ Load with exactly one brand file. */
6
+
7
+ :root {
8
+ --mode: "operator";
9
+
10
+ /* ---- Shared spacing options (8pt base). Identical in every mode. ---- */
11
+ /* 2xs is a deliberate half-step off the 8pt grid. It exists ONLY for gaps
12
+ inside a single component — label→input, icon→label — where 8px reads as
13
+ a separation rather than a pairing. Never for layout. */
14
+ --spacing-2xs: 4px;
15
+ --spacing-xs: 8px;
16
+ --spacing-s: 16px;
17
+ --spacing-m: 24px;
18
+ --spacing-l: 32px;
19
+ --spacing-xl: 48px;
20
+ --spacing-xxl: 80px;
21
+
22
+
23
+ /* ---- This mode's selections ---- */
24
+ /* ---- Type scale — 1.125 Major Second. ----
25
+ Small scale: little difference between steps, suited to dense tools and
26
+ dashboards where more levels of detail are needed in less space.
27
+ Line heights UNITLESS. FLOOR: 1.5 holds even here. */
28
+ --text-caption: 12px; --leading-caption: 1.5;
29
+ --text-body: 14px; --leading-body: 1.5;
30
+ --text-prose: 16px; --leading-prose: 1.6; /* LONG-FORM text only */
31
+ --text-lead: 16px; --leading-lead: 1.5;
32
+ --text-h3: 16px; --leading-h3: 1.5;
33
+ --text-h2: 18px; --leading-h2: 1.4;
34
+ --text-h1: 22px; --leading-h1: 1.333;
35
+
36
+ --font-weight-regular: 400;
37
+ --font-weight-bold: 600;
38
+
39
+ --tracking-body: 0; --tracking-h2: 0; --tracking-h1: 0;
40
+ --tracking-caps: 0.07em;
41
+
42
+ --measure-prose: 72ch; /* prose only. Data columns are not prose. */
43
+
44
+ --spacing-section: var(--spacing-m); /* 24 */
45
+ --spacing-section-sm: var(--spacing-m); /* 24 */
46
+ --spacing-card: var(--spacing-s); /* 16 */
47
+ --spacing-stack: var(--spacing-s); /* 16 */
48
+ --spacing-group: var(--spacing-xs); /* 8 */
49
+ --spacing-label: var(--spacing-2xs); /* 4 — label to its input */
50
+ --spacing-inline: var(--spacing-xs); /* 8 */
51
+ --spacing-heading-before: var(--spacing-m); /* 24 */
52
+ --spacing-heading-after: var(--spacing-xs); /* 8 */
53
+
54
+ --grid-columns: 12; --grid-columns-sm: 4;
55
+ --grid-gutter: var(--spacing-s); --grid-gutter-sm: var(--spacing-s); /* 16 */
56
+ --grid-margin: var(--spacing-m); --grid-margin-sm: var(--spacing-s); /* 24 → 16 */
57
+
58
+ --size-control: 32px; --size-control-sm: 28px;
59
+ --size-row: 36px; --size-row-compact: 32px;
60
+ --size-touch-target: 48px; --size-icon: 16px;
61
+
62
+ --radius-control: var(--radius-sm); --radius-surface: var(--radius-sm);
63
+ --shadow-surface: var(--shadow-none);
64
+
65
+ --duration-fast: 75ms; --duration-base: 100ms; --duration-slow: 120ms;
66
+ --ease-out: cubic-bezier(0.2, 0, 0, 1);
67
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
68
+
69
+ --font-numeric: var(--font-numeric-features);
70
+ }
71
+
72
+ @media (prefers-reduced-motion: reduce) {
73
+ :root { --duration-fast: 1ms; --duration-base: 1ms; --duration-slow: 1ms; }
74
+ }
@@ -0,0 +1,69 @@
1
+ /* mode.product.css — authenticated app UI, dashboards, settings.
2
+ Serves BOTH first and repeat use. Predictability over novelty.
3
+ Spacing uses the shared 8pt option set; modes SELECT options, they do not invent values.
4
+ Load with exactly one brand file. */
5
+
6
+ :root {
7
+ --mode: "product";
8
+
9
+ /* ---- Shared spacing options (8pt base). Identical in every mode. ---- */
10
+ /* 2xs is a deliberate half-step off the 8pt grid. It exists ONLY for gaps
11
+ inside a single component — label→input, icon→label — where 8px reads as
12
+ a separation rather than a pairing. Never for layout. */
13
+ --spacing-2xs: 4px;
14
+ --spacing-xs: 8px;
15
+ --spacing-s: 16px;
16
+ --spacing-m: 24px;
17
+ --spacing-l: 32px;
18
+ --spacing-xl: 48px;
19
+ --spacing-xxl: 80px;
20
+
21
+
22
+ /* ---- This mode's selections ---- */
23
+ /* ---- Type scale — 1.200 Minor Third. ----
24
+ Mid scale: the general-purpose default.
25
+ Line heights UNITLESS. FLOOR: 1.5 for body and long-form text. */
26
+ --text-caption: 14px; --leading-caption: 1.5;
27
+ --text-body: 16px; --leading-body: 1.5;
28
+ --text-prose: 18px; --leading-prose: 1.6; /* LONG-FORM text only */
29
+ --text-lead: 20px; --leading-lead: 1.5;
30
+ --text-h3: 20px; --leading-h3: 1.4;
31
+ --text-h2: 24px; --leading-h2: 1.333;
32
+ --text-h1: 32px; --leading-h1: 1.25;
33
+
34
+ --font-weight-regular: 400;
35
+ --font-weight-bold: 600;
36
+
37
+ --tracking-body: 0; --tracking-h2: -0.01em; --tracking-h1: -0.015em;
38
+ --tracking-caps: 0.06em;
39
+
40
+ --measure-prose: 60ch;
41
+
42
+ --spacing-section: var(--spacing-xl); /* 48 */
43
+ --spacing-section-sm: var(--spacing-l); /* 32 */
44
+ --spacing-card: var(--spacing-m); /* 24 */
45
+ --spacing-stack: var(--spacing-s); /* 16 */
46
+ --spacing-group: var(--spacing-xs); /* 8 */
47
+ --spacing-label: var(--spacing-2xs); /* 4 — label to its input */
48
+ --spacing-inline: var(--spacing-xs); /* 8 */
49
+ --spacing-heading-before: var(--spacing-l); /* 32 */
50
+ --spacing-heading-after: var(--spacing-xs); /* 8 */
51
+
52
+ --grid-columns: 12; --grid-columns-sm: 4;
53
+ --grid-gutter: var(--spacing-m); --grid-gutter-sm: var(--spacing-s); /* 24 → 16 */
54
+ --grid-margin: var(--spacing-l); --grid-margin-sm: var(--spacing-s); /* 32 → 16 */
55
+
56
+ --size-control: 40px; --size-control-sm: 32px; --size-row: 48px;
57
+ --size-touch-target: 48px; --size-icon: 18px;
58
+
59
+ --radius-control: var(--radius-sm); --radius-surface: var(--radius-md);
60
+ --shadow-surface: var(--shadow-none);
61
+
62
+ --duration-fast: 100ms; --duration-base: 150ms; --duration-slow: 200ms;
63
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
64
+ --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
65
+ }
66
+
67
+ @media (prefers-reduced-motion: reduce) {
68
+ :root { --duration-fast: 1ms; --duration-base: 1ms; --duration-slow: 1ms; }
69
+ }