@leftium/nimble.css 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.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/nimble-base.css +286 -0
- package/dist/nimble-base.min.css +1 -0
- package/dist/nimble-reset.css +120 -0
- package/dist/nimble-reset.min.css +1 -0
- package/dist/nimble-utilities.css +40 -0
- package/dist/nimble-utilities.min.css +1 -0
- package/dist/nimble.css +618 -0
- package/dist/nimble.min.css +1 -0
- package/package.json +40 -0
- package/src/_buttons.scss +123 -0
- package/src/_code.scss +37 -0
- package/src/_colors.scss +124 -0
- package/src/_config.scss +53 -0
- package/src/_details.scss +29 -0
- package/src/_dialog.scss +26 -0
- package/src/_document.scss +41 -0
- package/src/_forms.scss +130 -0
- package/src/_layers-base.scss +1 -0
- package/src/_layers-reset.scss +1 -0
- package/src/_layers-utilities.scss +1 -0
- package/src/_layers.scss +6 -0
- package/src/_links.scss +29 -0
- package/src/_media.scss +26 -0
- package/src/_print.scss +41 -0
- package/src/_reset.scss +183 -0
- package/src/_tables.scss +34 -0
- package/src/_typography.scss +135 -0
- package/src/_utilities.scss +73 -0
- package/src/nimble-base.scss +11 -0
- package/src/nimble-reset.scss +8 -0
- package/src/nimble-utilities.scss +8 -0
- package/src/nimble.scss +30 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Buttons
|
|
3
|
+
// Spec §9.2: button base, .secondary, .outline, button groups, disabled
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@layer nimble.base {
|
|
9
|
+
|
|
10
|
+
// ----- Base button -----
|
|
11
|
+
|
|
12
|
+
:where(button, [type="submit"], [type="reset"], [type="button"], [role="button"]) {
|
|
13
|
+
--_btn-padding-v: 0.5em;
|
|
14
|
+
--_btn-padding-h: 1em;
|
|
15
|
+
|
|
16
|
+
padding: var(--_btn-padding-v) var(--_btn-padding-h);
|
|
17
|
+
background-color: var(#{$prefix}primary);
|
|
18
|
+
color: var(#{$prefix}primary-contrast);
|
|
19
|
+
border: 1px solid var(#{$prefix}primary);
|
|
20
|
+
border-radius: var(#{$prefix}radius);
|
|
21
|
+
font: inherit;
|
|
22
|
+
font-size: 1rem;
|
|
23
|
+
line-height: 1.5;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
text-decoration: none;
|
|
26
|
+
display: inline-block;
|
|
27
|
+
text-align: center;
|
|
28
|
+
margin: 0 0.25em 0.25em 0;
|
|
29
|
+
transition: background-color 0.2s, border-color 0.2s;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:where(button, [type="submit"], [type="reset"], [type="button"], [role="button"]):hover {
|
|
33
|
+
background-color: var(#{$prefix}primary-hover);
|
|
34
|
+
border-color: var(#{$prefix}primary-hover);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:where(button, [type="submit"], [type="reset"], [type="button"], [role="button"]):focus-visible {
|
|
38
|
+
box-shadow: 0 0 0 2px var(#{$prefix}primary-focus);
|
|
39
|
+
outline: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ----- Disabled -----
|
|
43
|
+
|
|
44
|
+
:where(button, [type="submit"], [type="reset"], [type="button"], [role="button"]):disabled {
|
|
45
|
+
opacity: 0.5;
|
|
46
|
+
cursor: not-allowed;
|
|
47
|
+
pointer-events: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ----- Button groups -----
|
|
51
|
+
// Note: children use [role="group"] without :where() so they beat
|
|
52
|
+
// the zero-specificity form input rules for border-radius.
|
|
53
|
+
|
|
54
|
+
:where([role="group"]) {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[role="group"] > * {
|
|
59
|
+
border-radius: 0;
|
|
60
|
+
margin: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
[role="group"] > * + * {
|
|
64
|
+
box-shadow: -1px 0 0 rgb(255 255 255 / 0.3);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[role="group"] > :first-child {
|
|
68
|
+
border-start-start-radius: var(#{$prefix}radius);
|
|
69
|
+
border-end-start-radius: var(#{$prefix}radius);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
[role="group"] > :last-child {
|
|
73
|
+
border-start-end-radius: var(#{$prefix}radius);
|
|
74
|
+
border-end-end-radius: var(#{$prefix}radius);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ----- Search groups (pill shape) -----
|
|
78
|
+
|
|
79
|
+
[role="search"] [role="group"] > :first-child {
|
|
80
|
+
border-start-start-radius: 5rem;
|
|
81
|
+
border-end-start-radius: 5rem;
|
|
82
|
+
padding-inline-start: 1.25em;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
[role="search"] [role="group"] > :last-child {
|
|
86
|
+
border-start-end-radius: 5rem;
|
|
87
|
+
border-end-end-radius: 5rem;
|
|
88
|
+
padding-inline-end: 1.25em;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ----- Variants (utility classes) -----
|
|
94
|
+
|
|
95
|
+
@layer nimble.utilities {
|
|
96
|
+
|
|
97
|
+
.secondary {
|
|
98
|
+
background-color: var(#{$prefix}secondary);
|
|
99
|
+
border-color: var(#{$prefix}secondary);
|
|
100
|
+
color: var(#{$prefix}secondary-contrast);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.secondary:hover {
|
|
104
|
+
background-color: var(#{$prefix}secondary-hover);
|
|
105
|
+
border-color: var(#{$prefix}secondary-hover);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.secondary:focus-visible {
|
|
109
|
+
box-shadow: 0 0 0 2px var(#{$prefix}secondary-focus);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.outline {
|
|
113
|
+
background-color: transparent;
|
|
114
|
+
color: var(#{$prefix}primary);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.outline:hover {
|
|
118
|
+
background-color: var(#{$prefix}primary-focus);
|
|
119
|
+
color: var(#{$prefix}primary-hover);
|
|
120
|
+
border-color: var(#{$prefix}primary-hover);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
}
|
package/src/_code.scss
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Code
|
|
3
|
+
// Spec §9.5: pre, code, kbd, samp
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@layer nimble.base {
|
|
9
|
+
|
|
10
|
+
:where(code, kbd, samp) {
|
|
11
|
+
font-family: var(#{$prefix}font-mono);
|
|
12
|
+
font-size: 0.875em;
|
|
13
|
+
background-color: var(#{$prefix}surface-2);
|
|
14
|
+
border-radius: var(#{$prefix}radius);
|
|
15
|
+
padding: 0.15em 0.35em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:where(pre) {
|
|
19
|
+
background-color: var(#{$prefix}surface-2);
|
|
20
|
+
border-radius: var(#{$prefix}radius);
|
|
21
|
+
padding: var(#{$prefix}spacing);
|
|
22
|
+
overflow-x: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Reset nested code inside pre
|
|
26
|
+
:where(pre code) {
|
|
27
|
+
background: none;
|
|
28
|
+
padding: 0;
|
|
29
|
+
font-size: inherit;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:where(kbd) {
|
|
33
|
+
border: 1px solid var(#{$prefix}border);
|
|
34
|
+
border-bottom-width: 2px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
package/src/_colors.scss
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Color System
|
|
3
|
+
// oklch surfaces + primary/secondary/feedback via light-dark()
|
|
4
|
+
// All public properties use $prefix; internals use --_
|
|
5
|
+
//
|
|
6
|
+
// Note: oklch() values are emitted as raw CSS strings to prevent Sass from
|
|
7
|
+
// interpreting them as Sass color functions. We use unquote() wrappers.
|
|
8
|
+
// ==========================================================================
|
|
9
|
+
|
|
10
|
+
@use 'sass:math';
|
|
11
|
+
@use 'sass:string';
|
|
12
|
+
@use 'config' as *;
|
|
13
|
+
|
|
14
|
+
// Helper: build an oklch() string that Sass passes through as-is
|
|
15
|
+
@function _oklch($l, $c, $h, $alpha: null) {
|
|
16
|
+
@if $alpha {
|
|
17
|
+
@return string.unquote('oklch(#{$l} #{$c} #{$h} / #{$alpha})');
|
|
18
|
+
}
|
|
19
|
+
@return string.unquote('oklch(#{$l} #{$c} #{$h})');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Helper: build a light-dark() string
|
|
23
|
+
@function _light-dark($light, $dark) {
|
|
24
|
+
@return string.unquote('light-dark(#{$light}, #{$dark})');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@layer nimble.base {
|
|
28
|
+
|
|
29
|
+
:root {
|
|
30
|
+
color-scheme: light dark;
|
|
31
|
+
|
|
32
|
+
// ----- Surfaces -----
|
|
33
|
+
// Surface 1: page background (base lightness)
|
|
34
|
+
#{$prefix}surface-1: #{_light-dark(
|
|
35
|
+
_oklch($surface-light-base, $surface-chroma, $surface-hue),
|
|
36
|
+
_oklch($surface-dark-base, $surface-chroma + $surface-dark-chroma-boost, $surface-hue + $surface-dark-hue-shift)
|
|
37
|
+
)};
|
|
38
|
+
|
|
39
|
+
// Surface 2-4: generated from offsets
|
|
40
|
+
@each $level, $offset in $surface-offsets {
|
|
41
|
+
#{$prefix}surface-#{$level}: #{_light-dark(
|
|
42
|
+
_oklch($surface-light-base - $offset, $surface-chroma, $surface-hue),
|
|
43
|
+
_oklch($surface-dark-base + $offset, $surface-chroma + $surface-dark-chroma-boost, $surface-hue + $surface-dark-hue-shift)
|
|
44
|
+
)};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ----- Text -----
|
|
48
|
+
#{$prefix}text-1: #{_light-dark(
|
|
49
|
+
_oklch(0.280, 0.005, $surface-hue),
|
|
50
|
+
_oklch(0.860, 0.005, $surface-hue)
|
|
51
|
+
)};
|
|
52
|
+
#{$prefix}text-2: #{_light-dark(
|
|
53
|
+
_oklch(0.580, 0.005, $surface-hue),
|
|
54
|
+
_oklch(0.650, 0.005, $surface-hue)
|
|
55
|
+
)};
|
|
56
|
+
|
|
57
|
+
// ----- Border -----
|
|
58
|
+
#{$prefix}border: #{_light-dark(
|
|
59
|
+
_oklch(0.830, 0.005, $surface-hue),
|
|
60
|
+
_oklch(0.280, 0.005, $surface-hue + $surface-dark-hue-shift)
|
|
61
|
+
)};
|
|
62
|
+
|
|
63
|
+
// ----- Primary (main accent) -----
|
|
64
|
+
#{$prefix}primary: #{_light-dark(
|
|
65
|
+
_oklch($primary-lightness, $primary-chroma, $primary-hue),
|
|
66
|
+
_oklch($primary-lightness + 0.1, $primary-chroma, $primary-hue)
|
|
67
|
+
)};
|
|
68
|
+
#{$prefix}primary-hover: #{_light-dark(
|
|
69
|
+
_oklch($primary-lightness - 0.1, $primary-chroma, $primary-hue),
|
|
70
|
+
_oklch($primary-lightness + 0.2, $primary-chroma, $primary-hue)
|
|
71
|
+
)};
|
|
72
|
+
#{$prefix}primary-focus: #{_oklch($primary-lightness, $primary-chroma, $primary-hue, 0.4)};
|
|
73
|
+
#{$prefix}primary-contrast: #{_light-dark(
|
|
74
|
+
'#fff',
|
|
75
|
+
_oklch(0.15, 0.005, $surface-hue)
|
|
76
|
+
)};
|
|
77
|
+
|
|
78
|
+
// ----- Secondary (neutral accent) -----
|
|
79
|
+
#{$prefix}secondary: #{_light-dark(
|
|
80
|
+
_oklch($secondary-lightness, $secondary-chroma, $secondary-hue),
|
|
81
|
+
_oklch($secondary-lightness + 0.15, $secondary-chroma, $secondary-hue)
|
|
82
|
+
)};
|
|
83
|
+
#{$prefix}secondary-hover: #{_light-dark(
|
|
84
|
+
_oklch($secondary-lightness - 0.1, $secondary-chroma, $secondary-hue),
|
|
85
|
+
_oklch($secondary-lightness + 0.25, $secondary-chroma, $secondary-hue)
|
|
86
|
+
)};
|
|
87
|
+
#{$prefix}secondary-focus: #{_oklch($secondary-lightness, $secondary-chroma, $secondary-hue, 0.3)};
|
|
88
|
+
#{$prefix}secondary-contrast: #{_light-dark(
|
|
89
|
+
'#fff',
|
|
90
|
+
_oklch(0.15, 0.005, $surface-hue)
|
|
91
|
+
)};
|
|
92
|
+
|
|
93
|
+
// ----- Feedback -----
|
|
94
|
+
#{$prefix}valid: #{_light-dark(
|
|
95
|
+
_oklch(0.52, 0.17, 145),
|
|
96
|
+
_oklch(0.65, 0.2, 145)
|
|
97
|
+
)};
|
|
98
|
+
#{$prefix}invalid: #{_light-dark(
|
|
99
|
+
_oklch(0.55, 0.22, 25),
|
|
100
|
+
_oklch(0.65, 0.22, 25)
|
|
101
|
+
)};
|
|
102
|
+
|
|
103
|
+
// ----- Typography -----
|
|
104
|
+
#{$prefix}font-sans: #{$font-sans};
|
|
105
|
+
#{$prefix}font-mono: #{$font-mono};
|
|
106
|
+
|
|
107
|
+
// ----- Spacing & Layout -----
|
|
108
|
+
#{$prefix}spacing: #{$spacing};
|
|
109
|
+
#{$prefix}radius: #{$radius};
|
|
110
|
+
#{$prefix}content-width: #{$content-width};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ----- Manual theme override -----
|
|
114
|
+
// Setting color-scheme forces light-dark() to resolve to the chosen mode
|
|
115
|
+
|
|
116
|
+
[data-theme="dark"] {
|
|
117
|
+
color-scheme: dark;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
[data-theme="light"] {
|
|
121
|
+
color-scheme: light;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
package/src/_config.scss
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Configuration
|
|
3
|
+
// All values use !default so they can be overridden via @use ... with (...)
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
// --- Prefix ---
|
|
7
|
+
// Must include leading `--` and trailing `-` (e.g., '--nc-', '--my-')
|
|
8
|
+
$prefix: '--nc-' !default;
|
|
9
|
+
|
|
10
|
+
// --- Feature flags ---
|
|
11
|
+
$enable-utilities: true !default;
|
|
12
|
+
$enable-dialog: true !default;
|
|
13
|
+
$enable-switch: true !default;
|
|
14
|
+
$enable-details: true !default;
|
|
15
|
+
|
|
16
|
+
// --- Colors (oklch parameters) ---
|
|
17
|
+
|
|
18
|
+
// Primary (main accent: links, primary buttons, focus rings, checkboxes)
|
|
19
|
+
$primary-hue: 250 !default;
|
|
20
|
+
$primary-chroma: 0.2 !default;
|
|
21
|
+
$primary-lightness: 0.50 !default;
|
|
22
|
+
|
|
23
|
+
// Secondary (neutral accent: secondary buttons, reset buttons)
|
|
24
|
+
$secondary-hue: 250 !default;
|
|
25
|
+
$secondary-chroma: 0.05 !default;
|
|
26
|
+
$secondary-lightness: 0.45 !default;
|
|
27
|
+
|
|
28
|
+
// Surface (background hierarchy)
|
|
29
|
+
$surface-hue: 250 !default;
|
|
30
|
+
$surface-chroma: 0.002 !default;
|
|
31
|
+
$surface-light-base: 0.985 !default;
|
|
32
|
+
$surface-dark-base: 0.170 !default;
|
|
33
|
+
|
|
34
|
+
// Lightness offsets for each surface level (relative to base)
|
|
35
|
+
$surface-offsets: (2: 0.03, 3: 0.06, 4: 0.10) !default;
|
|
36
|
+
|
|
37
|
+
// Dark mode chroma/hue adjustments for surfaces
|
|
38
|
+
$surface-dark-chroma-boost: 0.003 !default;
|
|
39
|
+
$surface-dark-hue-shift: 10 !default;
|
|
40
|
+
|
|
41
|
+
// --- Typography ---
|
|
42
|
+
$font-sans: system-ui, sans-serif !default;
|
|
43
|
+
$font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro',
|
|
44
|
+
Menlo, Consolas, 'DejaVu Sans Mono', monospace !default;
|
|
45
|
+
|
|
46
|
+
// --- Spacing & Layout ---
|
|
47
|
+
$spacing: 1rem !default;
|
|
48
|
+
$radius: 0.25rem !default;
|
|
49
|
+
$content-width: 720px !default;
|
|
50
|
+
$wide-width: 1200px !default;
|
|
51
|
+
|
|
52
|
+
// --- Breakpoints ---
|
|
53
|
+
$breakpoint-phone: 720px !default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Details / Summary
|
|
3
|
+
// Spec §9.7 — behind $enable-details flag
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@if $enable-details {
|
|
9
|
+
|
|
10
|
+
@layer nimble.base {
|
|
11
|
+
|
|
12
|
+
:where(details) {
|
|
13
|
+
border: 1px solid var(#{$prefix}border);
|
|
14
|
+
border-radius: var(#{$prefix}radius);
|
|
15
|
+
padding: 0.75em 1em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:where(summary) {
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:where(details[open] > summary) {
|
|
24
|
+
margin-bottom: 0.5em;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
package/src/_dialog.scss
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Dialog
|
|
3
|
+
// Spec §9.11 — behind $enable-dialog flag
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@if $enable-dialog {
|
|
9
|
+
|
|
10
|
+
@layer nimble.base {
|
|
11
|
+
|
|
12
|
+
:where(dialog) {
|
|
13
|
+
background-color: var(#{$prefix}surface-4);
|
|
14
|
+
border: 1px solid var(#{$prefix}border);
|
|
15
|
+
border-radius: var(#{$prefix}radius);
|
|
16
|
+
max-width: min(90vw, 40rem);
|
|
17
|
+
padding: var(#{$prefix}spacing);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:where(dialog::backdrop) {
|
|
21
|
+
background: rgb(0 0 0 / 0.5);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Document
|
|
3
|
+
// html, body (grid centering), ::selection
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'sass:string';
|
|
7
|
+
@use 'config' as *;
|
|
8
|
+
|
|
9
|
+
@layer nimble.base {
|
|
10
|
+
|
|
11
|
+
html {
|
|
12
|
+
font-family: var(#{$prefix}font-sans);
|
|
13
|
+
font-size: 100%; // = 16px in most browsers
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
color: var(#{$prefix}text-1);
|
|
16
|
+
background-color: var(#{$prefix}surface-1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Grid centering: content sits in the middle column,
|
|
20
|
+
// full-bleed elements can span 1 / -1.
|
|
21
|
+
// See spec §7.1
|
|
22
|
+
body {
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns:
|
|
25
|
+
1fr
|
|
26
|
+
min(var(#{$prefix}content-width), #{string.unquote('calc(100% - 2 * var(#{$prefix}spacing))')})
|
|
27
|
+
1fr;
|
|
28
|
+
min-height: 100dvh;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
body > * {
|
|
32
|
+
grid-column: 2;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Selection styling using primary accent
|
|
36
|
+
::selection {
|
|
37
|
+
background-color: var(#{$prefix}primary-focus);
|
|
38
|
+
color: var(#{$prefix}text-1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
package/src/_forms.scss
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Forms
|
|
3
|
+
// Spec §9.3: inputs, select, textarea, labels, fieldset, validation, switch
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@layer nimble.base {
|
|
9
|
+
|
|
10
|
+
// ----- Text inputs, select, textarea -----
|
|
11
|
+
|
|
12
|
+
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"]),
|
|
13
|
+
select, textarea) {
|
|
14
|
+
--_input-bg: color-mix(in oklch, var(#{$prefix}surface-1), var(#{$prefix}surface-2) 20%);
|
|
15
|
+
|
|
16
|
+
padding: 0.5em 0.75em;
|
|
17
|
+
background-color: var(--_input-bg);
|
|
18
|
+
border: 1px solid var(#{$prefix}border);
|
|
19
|
+
border-radius: var(#{$prefix}radius);
|
|
20
|
+
color: var(#{$prefix}text-1);
|
|
21
|
+
font: inherit;
|
|
22
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Make text inputs and select full-width by default (PicoCSS pattern)
|
|
26
|
+
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="reset"]),
|
|
27
|
+
select, textarea) {
|
|
28
|
+
width: 100%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ----- Focus -----
|
|
32
|
+
|
|
33
|
+
:where(input, select, textarea):focus-visible {
|
|
34
|
+
border-color: var(#{$prefix}primary);
|
|
35
|
+
box-shadow: 0 0 0 2px var(#{$prefix}primary-focus);
|
|
36
|
+
outline: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ----- Validation states (aria-invalid) -----
|
|
40
|
+
|
|
41
|
+
:where(input, select, textarea)[aria-invalid="false"] {
|
|
42
|
+
border-color: var(#{$prefix}valid);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
:where(input, select, textarea)[aria-invalid="true"] {
|
|
46
|
+
border-color: var(#{$prefix}invalid);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ----- Labels -----
|
|
50
|
+
|
|
51
|
+
:where(label) {
|
|
52
|
+
display: block;
|
|
53
|
+
margin-bottom: 0.25em;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:where(label:has(+ input, + select, + textarea)) {
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ----- Fieldset -----
|
|
61
|
+
|
|
62
|
+
:where(fieldset) {
|
|
63
|
+
border: 1px solid var(#{$prefix}border);
|
|
64
|
+
border-radius: var(#{$prefix}radius);
|
|
65
|
+
padding: var(#{$prefix}spacing);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:where(legend) {
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
padding-inline: 0.25em;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ----- Checkbox & Radio -----
|
|
74
|
+
// Use accent-color to tint native controls to match the primary color
|
|
75
|
+
|
|
76
|
+
:where([type="checkbox"], [type="radio"]) {
|
|
77
|
+
accent-color: var(#{$prefix}primary);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ----- Range -----
|
|
81
|
+
|
|
82
|
+
:where([type="range"]) {
|
|
83
|
+
accent-color: var(#{$prefix}primary);
|
|
84
|
+
width: 100%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ----- Color -----
|
|
88
|
+
|
|
89
|
+
:where([type="color"]) {
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ----- Switch (checkbox with role="switch") -----
|
|
94
|
+
|
|
95
|
+
@if $enable-switch {
|
|
96
|
+
// Minimal switch styling — relies on native checkbox with role="switch"
|
|
97
|
+
// Browsers with :has() support get enhanced label alignment
|
|
98
|
+
:where([type="checkbox"][role="switch"]) {
|
|
99
|
+
appearance: none;
|
|
100
|
+
width: 2.5em;
|
|
101
|
+
height: 1.25em;
|
|
102
|
+
border-radius: 1em;
|
|
103
|
+
background-color: var(#{$prefix}border);
|
|
104
|
+
position: relative;
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
transition: background-color 0.2s;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:where([type="checkbox"][role="switch"])::before {
|
|
110
|
+
content: '';
|
|
111
|
+
position: absolute;
|
|
112
|
+
top: 2px;
|
|
113
|
+
left: 2px;
|
|
114
|
+
width: calc(1.25em - 4px);
|
|
115
|
+
height: calc(1.25em - 4px);
|
|
116
|
+
border-radius: 50%;
|
|
117
|
+
background-color: #fff;
|
|
118
|
+
transition: transform 0.2s;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
:where([type="checkbox"][role="switch"]):checked {
|
|
122
|
+
background-color: var(#{$prefix}primary);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
:where([type="checkbox"][role="switch"]):checked::before {
|
|
126
|
+
transform: translateX(1.25em);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer nimble.reset, nimble.base;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer nimble.reset;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer nimble.utilities;
|
package/src/_layers.scss
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Layer Order Declaration
|
|
3
|
+
// Must be the first CSS output to establish cascade priority
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@layer nimble.reset, nimble.base, nimble.utilities;
|
package/src/_links.scss
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Links
|
|
3
|
+
// Spec §9.1
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'sass:string';
|
|
7
|
+
@use 'config' as *;
|
|
8
|
+
|
|
9
|
+
@layer nimble.base {
|
|
10
|
+
|
|
11
|
+
:where(a:not([role="button"])) {
|
|
12
|
+
color: var(#{$prefix}primary);
|
|
13
|
+
text-decoration: underline;
|
|
14
|
+
text-underline-offset: 0.15em;
|
|
15
|
+
text-decoration-color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary), transparent 50%)')};
|
|
16
|
+
transition: color 0.2s, text-decoration-color 0.2s;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
:where(a:not([role="button"])):visited {
|
|
20
|
+
color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.5 0.2 310))')};
|
|
21
|
+
text-decoration-color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.5 0.2 310) 30%)')};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:where(a:not([role="button"])):hover {
|
|
25
|
+
color: var(#{$prefix}primary-hover);
|
|
26
|
+
text-decoration-color: var(#{$prefix}primary-hover);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
package/src/_media.scss
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Media
|
|
3
|
+
// Spec §9.8: img, video, canvas, svg, figure, figcaption
|
|
4
|
+
// Note: No dark-mode opacity reduction (ruins images)
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
|
|
7
|
+
@use 'config' as *;
|
|
8
|
+
|
|
9
|
+
@layer nimble.base {
|
|
10
|
+
|
|
11
|
+
:where(img, video, canvas, svg) {
|
|
12
|
+
max-width: 100%;
|
|
13
|
+
height: auto;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:where(figure) {
|
|
17
|
+
margin: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:where(figcaption) {
|
|
21
|
+
font-size: 0.9em;
|
|
22
|
+
color: var(#{$prefix}text-2);
|
|
23
|
+
margin-top: 0.5em;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
package/src/_print.scss
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Print Styles
|
|
3
|
+
// Spec §9.12
|
|
4
|
+
// Not inside any layer — print overrides everything
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
|
|
7
|
+
@media print {
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
background: #fff;
|
|
11
|
+
color: #000;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
a[href]::after {
|
|
15
|
+
content: " (" attr(href) ")";
|
|
16
|
+
font-size: 0.85em;
|
|
17
|
+
color: #555;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
a[href^="#"]::after,
|
|
21
|
+
a[href^="javascript:"]::after {
|
|
22
|
+
content: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pre, blockquote {
|
|
26
|
+
page-break-inside: avoid;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
h2, h3, h4 {
|
|
30
|
+
page-break-after: avoid;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
img {
|
|
34
|
+
max-width: 100% !important;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@page {
|
|
38
|
+
margin: 2cm;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|