@aortl/admin-css 0.0.1 → 0.2.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.
- package/README.md +0 -22
- package/dist/admin.css +2918 -248
- package/dist/admin.min.css +1 -1
- package/dist/admin.scoped.css +3383 -0
- package/dist/admin.scoped.min.css +46 -0
- package/package.json +15 -3
- package/src/base.css +13 -7
- package/src/components/accordion.css +79 -0
- package/src/components/alert.css +83 -0
- package/src/components/app-shell.css +59 -0
- package/src/components/badge.css +44 -0
- package/src/components/brand-tile.css +9 -0
- package/src/components/breadcrumbs.css +38 -0
- package/src/components/button-group.css +73 -0
- package/src/components/button.css +50 -1
- package/src/components/card.css +1 -1
- package/src/components/checkbox.css +38 -0
- package/src/components/dialog.css +91 -0
- package/src/components/field.css +29 -2
- package/src/components/file-input.css +36 -0
- package/src/components/footer.css +26 -0
- package/src/components/index.css +24 -0
- package/src/components/input-group.css +38 -0
- package/src/components/input.css +7 -0
- package/src/components/menu.css +88 -0
- package/src/components/navbar.css +66 -0
- package/src/components/pagination.css +43 -0
- package/src/components/progress.css +97 -0
- package/src/components/radio.css +45 -0
- package/src/components/select.css +114 -0
- package/src/components/sidebar.css +225 -0
- package/src/components/spinner.css +40 -0
- package/src/components/switch.css +62 -0
- package/src/components/table.css +124 -0
- package/src/components/tabs.css +172 -0
- package/src/components/textarea.css +33 -0
- package/src/fonts.css +88 -0
- package/src/index.css +1 -0
- package/src/theme.css +122 -29
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.tabs {
|
|
3
|
+
@apply flex flex-col;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/* List + tab buttons. Same classes are produced by Base UI (React) and the
|
|
7
|
+
vanilla radio-input markup, so styling is shared. All selectors are
|
|
8
|
+
scoped under `.tabs` so generic `class="tab"` markup elsewhere on the
|
|
9
|
+
page (e.g. Starlight's own <Tabs> component) doesn't pick them up. */
|
|
10
|
+
.tabs .tab-list {
|
|
11
|
+
@apply inline-flex items-center gap-1 border-b border-border;
|
|
12
|
+
/* Anchor for the optional .tab-indicator */
|
|
13
|
+
position: relative;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.tabs .tab {
|
|
17
|
+
@apply inline-flex items-center gap-1.5
|
|
18
|
+
px-3 h-9
|
|
19
|
+
text-sm leading-none font-medium
|
|
20
|
+
text-text-muted bg-transparent
|
|
21
|
+
border-0 cursor-pointer select-none
|
|
22
|
+
transition-colors duration-150
|
|
23
|
+
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary
|
|
24
|
+
hover:text-text
|
|
25
|
+
disabled:opacity-50 disabled:cursor-not-allowed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.tabs .tab[data-selected],
|
|
29
|
+
.tabs .tab[aria-selected="true"] {
|
|
30
|
+
@apply text-text;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Vanilla radio-input pattern: hide the inputs visually, treat the following
|
|
34
|
+
<label class="tab"> as the selected tab when the radio is :checked.
|
|
35
|
+
Pairs with `:has(input:checked)` below to show the right panel. */
|
|
36
|
+
.tabs .tab-input {
|
|
37
|
+
position: absolute;
|
|
38
|
+
width: 1px;
|
|
39
|
+
height: 1px;
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
border: 0;
|
|
43
|
+
opacity: 0;
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.tabs .tab-input:checked + .tab {
|
|
48
|
+
@apply text-text;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tabs .tab-input:focus-visible + .tab {
|
|
52
|
+
@apply outline-2 outline-offset-2 outline-primary;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Bordered (default) — underline marker on the active tab. The pseudo sits
|
|
56
|
+
below the .tab, overlapping the .tab-list bottom border. */
|
|
57
|
+
.tabs-bordered .tab,
|
|
58
|
+
.tabs:not(.tabs-boxed) .tab {
|
|
59
|
+
position: relative;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tabs-bordered .tab::after,
|
|
63
|
+
.tabs:not(.tabs-boxed) .tab::after {
|
|
64
|
+
content: "";
|
|
65
|
+
position: absolute;
|
|
66
|
+
inset-inline: 0;
|
|
67
|
+
inset-block-end: -1px;
|
|
68
|
+
block-size: 2px;
|
|
69
|
+
background-color: var(--color-primary);
|
|
70
|
+
transform: scaleX(0);
|
|
71
|
+
transition: transform 150ms ease;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.tabs-bordered .tab[data-selected]::after,
|
|
75
|
+
.tabs-bordered .tab[aria-selected="true"]::after,
|
|
76
|
+
.tabs-bordered .tab-input:checked + .tab::after,
|
|
77
|
+
.tabs:not(.tabs-boxed) .tab[data-selected]::after,
|
|
78
|
+
.tabs:not(.tabs-boxed) .tab[aria-selected="true"]::after,
|
|
79
|
+
.tabs:not(.tabs-boxed) .tab-input:checked + .tab::after {
|
|
80
|
+
transform: scaleX(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Boxed (segmented control) — adjacent tabs share borders. */
|
|
84
|
+
.tabs-boxed .tab-list {
|
|
85
|
+
@apply gap-0 p-0.5 border border-border rounded-md bg-surface-muted;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.tabs-boxed .tab {
|
|
89
|
+
@apply rounded;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.tabs-boxed .tab[data-selected],
|
|
93
|
+
.tabs-boxed .tab[aria-selected="true"],
|
|
94
|
+
.tabs-boxed .tab-input:checked + .tab {
|
|
95
|
+
@apply bg-surface text-text shadow-sm;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Full width — list stretches across the container, tabs share space evenly. */
|
|
99
|
+
.tabs-full-width:not([data-orientation="vertical"]) .tab-list {
|
|
100
|
+
@apply flex w-full;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.tabs-full-width:not([data-orientation="vertical"]) .tab {
|
|
104
|
+
@apply flex-1 justify-center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Sizes — cascade to nested tabs. */
|
|
108
|
+
.tabs-sm .tab {
|
|
109
|
+
@apply px-2 h-7 text-xs;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.tabs-lg .tab {
|
|
113
|
+
@apply px-4 h-11 text-base;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Panels — Base UI handles hidden state via data-hidden / hidden attr. */
|
|
117
|
+
.tabs .tab-panel {
|
|
118
|
+
@apply pt-3 outline-none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Vanilla radio-input pattern: only the panel whose data-for matches the
|
|
122
|
+
checked input is shown. Each .tabs root scopes its own selectors. */
|
|
123
|
+
.tabs .tab-panel {
|
|
124
|
+
display: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.tabs:has(.tab-input[value="1"]:checked) .tab-panel[data-value="1"],
|
|
128
|
+
.tabs:has(.tab-input[value="2"]:checked) .tab-panel[data-value="2"],
|
|
129
|
+
.tabs:has(.tab-input[value="3"]:checked) .tab-panel[data-value="3"],
|
|
130
|
+
.tabs:has(.tab-input[value="4"]:checked) .tab-panel[data-value="4"],
|
|
131
|
+
.tabs:has(.tab-input[value="5"]:checked) .tab-panel[data-value="5"],
|
|
132
|
+
.tabs:has(.tab-input[value="6"]:checked) .tab-panel[data-value="6"] {
|
|
133
|
+
display: block;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Base UI path: it renders the panel and applies `hidden`, so the rule
|
|
137
|
+
above is a no-op there. Reinstate display when the panel is shown by
|
|
138
|
+
Base UI. */
|
|
139
|
+
.tabs .tab-panel:not([hidden]):not([data-value]) {
|
|
140
|
+
display: block;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Vertical orientation. */
|
|
144
|
+
.tabs[data-orientation="vertical"] {
|
|
145
|
+
@apply flex-row gap-3;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.tabs[data-orientation="vertical"] .tab-list {
|
|
149
|
+
@apply flex-col items-stretch border-b-0 border-r border-border;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.tabs[data-orientation="vertical"] .tab {
|
|
153
|
+
@apply w-full justify-start;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.tabs[data-orientation="vertical"].tabs-bordered .tab::after,
|
|
157
|
+
.tabs[data-orientation="vertical"]:not(.tabs-boxed) .tab::after {
|
|
158
|
+
inset-inline: auto;
|
|
159
|
+
inset-inline-end: -1px;
|
|
160
|
+
inset-block: 0;
|
|
161
|
+
inline-size: 2px;
|
|
162
|
+
block-size: auto;
|
|
163
|
+
transform: scaleY(0);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.tabs[data-orientation="vertical"].tabs-bordered .tab[data-selected]::after,
|
|
167
|
+
.tabs[data-orientation="vertical"].tabs-bordered .tab[aria-selected="true"]::after,
|
|
168
|
+
.tabs[data-orientation="vertical"]:not(.tabs-boxed) .tab[data-selected]::after,
|
|
169
|
+
.tabs[data-orientation="vertical"]:not(.tabs-boxed) .tab[aria-selected="true"]::after {
|
|
170
|
+
transform: scaleY(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.textarea {
|
|
3
|
+
@apply block w-full px-3 py-2 min-h-20 resize-y
|
|
4
|
+
rounded-lg text-sm
|
|
5
|
+
bg-surface text-text
|
|
6
|
+
border border-transparent
|
|
7
|
+
transition-colors duration-150
|
|
8
|
+
placeholder:text-text-muted
|
|
9
|
+
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary
|
|
10
|
+
disabled:opacity-50 disabled:cursor-not-allowed;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.textarea-bordered {
|
|
14
|
+
@apply border-border hover:border-border-strong;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.textarea-ghost {
|
|
18
|
+
@apply bg-transparent hover:bg-surface-muted;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.textarea-danger {
|
|
22
|
+
@apply border-danger focus-visible:outline-danger;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Sizes */
|
|
26
|
+
.textarea-sm {
|
|
27
|
+
@apply text-xs px-2.5 py-1.5 min-h-16;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.textarea-lg {
|
|
31
|
+
@apply text-base px-4 py-2.5 min-h-24;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/fonts.css
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* IBM Plex Sans + Mono — the default UI typeface for this design system.
|
|
3
|
+
*
|
|
4
|
+
* Hosted on Google's CDN (fonts.gstatic.com), latin + latin-ext subsets
|
|
5
|
+
* only. Plex Sans is served as a variable font (one file covers weights
|
|
6
|
+
* 400–600 via the wght axis); Plex Mono ships as discrete weight files.
|
|
7
|
+
*
|
|
8
|
+
* `font-display: optional` — the browser uses the fallback stack from
|
|
9
|
+
* `--font-sans` / `--font-mono` if Plex isn't ready in ~100ms, then
|
|
10
|
+
* caches it for the next page load. No FOUT, no layout shift, and on
|
|
11
|
+
* fast networks the typeface still wins on first paint.
|
|
12
|
+
*
|
|
13
|
+
* Opt out by overriding `--font-sans` / `--font-mono`, or by importing
|
|
14
|
+
* admin-css's source files individually and skipping this one.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/* IBM Plex Sans — variable, weights 400–600 */
|
|
18
|
+
@font-face {
|
|
19
|
+
font-family: "IBM Plex Sans";
|
|
20
|
+
font-style: normal;
|
|
21
|
+
font-weight: 400 600;
|
|
22
|
+
font-display: optional;
|
|
23
|
+
src: url(https://fonts.gstatic.com/s/ibmplexsans/v23/zYXzKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1syxQKYbABA.woff2)
|
|
24
|
+
format("woff2");
|
|
25
|
+
unicode-range:
|
|
26
|
+
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
|
|
27
|
+
U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
|
|
28
|
+
U+A720-A7FF;
|
|
29
|
+
}
|
|
30
|
+
@font-face {
|
|
31
|
+
font-family: "IBM Plex Sans";
|
|
32
|
+
font-style: normal;
|
|
33
|
+
font-weight: 400 600;
|
|
34
|
+
font-display: optional;
|
|
35
|
+
src: url(https://fonts.gstatic.com/s/ibmplexsans/v23/zYXzKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1syxeKYY.woff2)
|
|
36
|
+
format("woff2");
|
|
37
|
+
unicode-range:
|
|
38
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
|
|
39
|
+
U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* IBM Plex Mono — discrete weights 400, 500 */
|
|
43
|
+
@font-face {
|
|
44
|
+
font-family: "IBM Plex Mono";
|
|
45
|
+
font-style: normal;
|
|
46
|
+
font-weight: 400;
|
|
47
|
+
font-display: optional;
|
|
48
|
+
src: url(https://fonts.gstatic.com/s/ibmplexmono/v20/-F63fjptAgt5VM-kVkqdyU8n1iEq129k.woff2)
|
|
49
|
+
format("woff2");
|
|
50
|
+
unicode-range:
|
|
51
|
+
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
|
|
52
|
+
U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
|
|
53
|
+
U+A720-A7FF;
|
|
54
|
+
}
|
|
55
|
+
@font-face {
|
|
56
|
+
font-family: "IBM Plex Mono";
|
|
57
|
+
font-style: normal;
|
|
58
|
+
font-weight: 400;
|
|
59
|
+
font-display: optional;
|
|
60
|
+
src: url(https://fonts.gstatic.com/s/ibmplexmono/v20/-F63fjptAgt5VM-kVkqdyU8n1i8q1w.woff2)
|
|
61
|
+
format("woff2");
|
|
62
|
+
unicode-range:
|
|
63
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
|
|
64
|
+
U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
65
|
+
}
|
|
66
|
+
@font-face {
|
|
67
|
+
font-family: "IBM Plex Mono";
|
|
68
|
+
font-style: normal;
|
|
69
|
+
font-weight: 500;
|
|
70
|
+
font-display: optional;
|
|
71
|
+
src: url(https://fonts.gstatic.com/s/ibmplexmono/v20/-F6qfjptAgt5VM-kVkqdyU8n3twJwl5FgtIU.woff2)
|
|
72
|
+
format("woff2");
|
|
73
|
+
unicode-range:
|
|
74
|
+
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
|
|
75
|
+
U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
|
|
76
|
+
U+A720-A7FF;
|
|
77
|
+
}
|
|
78
|
+
@font-face {
|
|
79
|
+
font-family: "IBM Plex Mono";
|
|
80
|
+
font-style: normal;
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
font-display: optional;
|
|
83
|
+
src: url(https://fonts.gstatic.com/s/ibmplexmono/v20/-F6qfjptAgt5VM-kVkqdyU8n3twJwlBFgg.woff2)
|
|
84
|
+
format("woff2");
|
|
85
|
+
unicode-range:
|
|
86
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
|
|
87
|
+
U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
88
|
+
}
|
package/src/index.css
CHANGED
package/src/theme.css
CHANGED
|
@@ -7,11 +7,19 @@
|
|
|
7
7
|
*
|
|
8
8
|
* 1. Palette — the Flexoki ramps (paper, black, base, red, orange,
|
|
9
9
|
* yellow, green, cyan, blue, purple, magenta). Replaces Tailwind's
|
|
10
|
-
* default colors entirely.
|
|
10
|
+
* default colors entirely. Tones are absolute and identical in
|
|
11
|
+
* light/dark mode — Flexoki's inverted ramp pairs (paper↔black,
|
|
12
|
+
* base-50↔base-950, blue-600↔blue-400, …) live in the semantic
|
|
13
|
+
* layer below.
|
|
11
14
|
*
|
|
12
15
|
* 2. Semantic — purpose-named aliases (primary, surface, danger, ...)
|
|
13
|
-
* pointing at palette tones
|
|
14
|
-
*
|
|
16
|
+
* pointing at palette tones via `light-dark()`. The active value
|
|
17
|
+
* tracks the cascaded `color-scheme` declared on :root: auto by
|
|
18
|
+
* default (system preference), forced via `[data-theme="dark"]` or
|
|
19
|
+
* `[data-theme="light"]`. Components only reference these aliases,
|
|
20
|
+
* so they pick up dark mode for free.
|
|
21
|
+
*
|
|
22
|
+
* Reskin by remapping the alias:
|
|
15
23
|
*
|
|
16
24
|
* :root { --color-primary: var(--color-green-600); }
|
|
17
25
|
*
|
|
@@ -163,46 +171,131 @@
|
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
@theme static {
|
|
174
|
+
/*
|
|
175
|
+
* Typography — only the font stack is tokenized. Sizes, weights, and
|
|
176
|
+
* line-heights compose from Tailwind's default scale at the call site
|
|
177
|
+
* (`text-sm`, `font-semibold`, `leading-tight`, …) — the system is
|
|
178
|
+
* dense and small enough that an extra semantic layer would just be
|
|
179
|
+
* indirection. Override `--font-sans` to swap the entire UI font.
|
|
180
|
+
*/
|
|
181
|
+
--font-sans:
|
|
182
|
+
"IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
183
|
+
--font-mono:
|
|
184
|
+
"IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
|
|
185
|
+
monospace;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@theme static {
|
|
189
|
+
/*
|
|
190
|
+
* Semantic tokens — each declared once via `light-dark()`. The two
|
|
191
|
+
* branches are Flexoki's symmetric ramp pairs:
|
|
192
|
+
* - paper ↔ black, base-50 ↔ base-950, base-150 ↔ base-850, …
|
|
193
|
+
* - accent-600 ↔ accent-400, accent-50 ↔ accent-950
|
|
194
|
+
*
|
|
195
|
+
* On accent buttons in dark mode the base shifts to the lighter
|
|
196
|
+
* accent-400 tone, so `content` (text on top) flips to black for
|
|
197
|
+
* legibility — the same trade-off `warning` already makes in both
|
|
198
|
+
* modes against bright yellow.
|
|
199
|
+
*/
|
|
200
|
+
|
|
166
201
|
/* Surfaces */
|
|
167
|
-
--color-surface: var(--color-paper);
|
|
168
|
-
--color-surface-muted: var(--color-base-50);
|
|
169
|
-
--color-surface-strong: var(--color-base-100);
|
|
202
|
+
--color-surface: light-dark(var(--color-paper), var(--color-black));
|
|
203
|
+
--color-surface-muted: light-dark(var(--color-base-50), var(--color-base-950));
|
|
204
|
+
--color-surface-strong: light-dark(var(--color-base-100), var(--color-base-900));
|
|
170
205
|
|
|
171
206
|
/* Text */
|
|
172
|
-
--color-text: var(--color-black);
|
|
173
|
-
--color-text-muted: var(--color-base-600);
|
|
207
|
+
--color-text: light-dark(var(--color-black), var(--color-base-200));
|
|
208
|
+
--color-text-muted: light-dark(var(--color-base-600), var(--color-base-500));
|
|
174
209
|
|
|
175
210
|
/* Borders */
|
|
176
|
-
--color-border: var(--color-base-150);
|
|
177
|
-
--color-border-strong: var(--color-base-300);
|
|
211
|
+
--color-border: light-dark(var(--color-base-150), var(--color-base-850));
|
|
212
|
+
--color-border-strong: light-dark(var(--color-base-300), var(--color-base-700));
|
|
178
213
|
|
|
179
214
|
/* Primary — Flexoki blue */
|
|
180
|
-
--color-primary: var(--color-blue-600);
|
|
181
|
-
--color-primary-hover: var(--color-blue-700);
|
|
182
|
-
--color-primary-muted: var(--color-blue-50);
|
|
183
|
-
--color-primary-content: var(--color-paper);
|
|
215
|
+
--color-primary: light-dark(var(--color-blue-600), var(--color-blue-400));
|
|
216
|
+
--color-primary-hover: light-dark(var(--color-blue-700), var(--color-blue-300));
|
|
217
|
+
--color-primary-muted: light-dark(var(--color-blue-50), var(--color-blue-950));
|
|
218
|
+
--color-primary-content: light-dark(var(--color-paper), var(--color-black));
|
|
219
|
+
|
|
220
|
+
/* System accent — per-app brand signal. Drives the navbar's 2px bottom
|
|
221
|
+
stripe and the footer's matching top stripe (both always on), plus
|
|
222
|
+
`.brand-tile` backgrounds. Defaults to a neutral gray so an un-branded
|
|
223
|
+
shell reads as chrome rather than a brand mark; override at :root (or
|
|
224
|
+
via inline style on .app-shell) to brand-shift a whole app. The -hover,
|
|
225
|
+
-muted, and -content siblings derive from the base via `color-mix`,
|
|
226
|
+
so a single override propagates. Mixing toward `--color-text` and
|
|
227
|
+
`--color-surface` (themselves `light-dark()` pairs) keeps the
|
|
228
|
+
derivations in step with light/dark mode without nesting light-dark()
|
|
229
|
+
inside color-mix(). Bright accents (e.g. yellow) may want a manual
|
|
230
|
+
-content override for contrast. */
|
|
231
|
+
--color-system-accent: light-dark(var(--color-base-600), var(--color-base-400));
|
|
232
|
+
--color-system-accent-hover: color-mix(
|
|
233
|
+
in oklch,
|
|
234
|
+
var(--color-system-accent),
|
|
235
|
+
var(--color-text) 12%
|
|
236
|
+
);
|
|
237
|
+
--color-system-accent-muted: color-mix(
|
|
238
|
+
in oklch,
|
|
239
|
+
var(--color-system-accent) 12%,
|
|
240
|
+
var(--color-surface)
|
|
241
|
+
);
|
|
242
|
+
--color-system-accent-content: light-dark(var(--color-paper), var(--color-black));
|
|
184
243
|
|
|
185
244
|
/* Danger — red */
|
|
186
|
-
--color-danger: var(--color-red-600);
|
|
187
|
-
--color-danger-hover: var(--color-red-700);
|
|
188
|
-
--color-danger-muted: var(--color-red-50);
|
|
189
|
-
--color-danger-content: var(--color-paper);
|
|
245
|
+
--color-danger: light-dark(var(--color-red-600), var(--color-red-400));
|
|
246
|
+
--color-danger-hover: light-dark(var(--color-red-700), var(--color-red-300));
|
|
247
|
+
--color-danger-muted: light-dark(var(--color-red-50), var(--color-red-950));
|
|
248
|
+
--color-danger-content: light-dark(var(--color-paper), var(--color-black));
|
|
190
249
|
|
|
191
250
|
/* Success — green */
|
|
192
|
-
--color-success: var(--color-green-600);
|
|
193
|
-
--color-success-hover: var(--color-green-700);
|
|
194
|
-
--color-success-muted: var(--color-green-50);
|
|
195
|
-
--color-success-content: var(--color-paper);
|
|
251
|
+
--color-success: light-dark(var(--color-green-600), var(--color-green-400));
|
|
252
|
+
--color-success-hover: light-dark(var(--color-green-700), var(--color-green-300));
|
|
253
|
+
--color-success-muted: light-dark(var(--color-green-50), var(--color-green-950));
|
|
254
|
+
--color-success-content: light-dark(var(--color-paper), var(--color-black));
|
|
196
255
|
|
|
197
|
-
/* Warning — yellow (
|
|
256
|
+
/* Warning — yellow (stays bright in both modes; dark text either way) */
|
|
198
257
|
--color-warning: var(--color-yellow-400);
|
|
199
|
-
--color-warning-hover: var(--color-yellow-500);
|
|
200
|
-
--color-warning-muted: var(--color-yellow-50);
|
|
258
|
+
--color-warning-hover: light-dark(var(--color-yellow-500), var(--color-yellow-300));
|
|
259
|
+
--color-warning-muted: light-dark(var(--color-yellow-50), var(--color-yellow-950));
|
|
201
260
|
--color-warning-content: var(--color-black);
|
|
202
261
|
|
|
203
262
|
/* Info — cyan */
|
|
204
|
-
--color-info: var(--color-cyan-600);
|
|
205
|
-
--color-info-hover: var(--color-cyan-700);
|
|
206
|
-
--color-info-muted: var(--color-cyan-50);
|
|
207
|
-
--color-info-content: var(--color-paper);
|
|
263
|
+
--color-info: light-dark(var(--color-cyan-600), var(--color-cyan-400));
|
|
264
|
+
--color-info-hover: light-dark(var(--color-cyan-700), var(--color-cyan-300));
|
|
265
|
+
--color-info-muted: light-dark(var(--color-cyan-50), var(--color-cyan-950));
|
|
266
|
+
--color-info-content: light-dark(var(--color-paper), var(--color-black));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/*
|
|
270
|
+
* Activate `light-dark()` resolution. `light dark` follows the OS
|
|
271
|
+
* preference; the attribute overrides force a specific mode and also
|
|
272
|
+
* flip native form controls, scrollbars, etc. The attribute selector
|
|
273
|
+
* isn't scoped to :root so subtrees can opt into a different mode (e.g.
|
|
274
|
+
* a dark hero section on an otherwise light page).
|
|
275
|
+
*/
|
|
276
|
+
:root {
|
|
277
|
+
color-scheme: light dark;
|
|
278
|
+
}
|
|
279
|
+
[data-theme="dark"] {
|
|
280
|
+
color-scheme: dark;
|
|
281
|
+
}
|
|
282
|
+
[data-theme="light"] {
|
|
283
|
+
color-scheme: light;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/*
|
|
287
|
+
* Align Tailwind's `dark:` variant with the same resolution rules so
|
|
288
|
+
* authored utilities (`dark:shadow-lg`, …) match what the tokens do.
|
|
289
|
+
* Default v4 uses prefers-color-scheme alone, which would ignore the
|
|
290
|
+
* [data-theme] override.
|
|
291
|
+
*/
|
|
292
|
+
@custom-variant dark {
|
|
293
|
+
&:where([data-theme="dark"], [data-theme="dark"] *) {
|
|
294
|
+
@slot;
|
|
295
|
+
}
|
|
296
|
+
@media (prefers-color-scheme: dark) {
|
|
297
|
+
&:where(:not([data-theme="light"], [data-theme="light"] *)) {
|
|
298
|
+
@slot;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
208
301
|
}
|