picocrank 1.25.2 → 1.27.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.
Files changed (51) hide show
  1. package/eslint.config.js +75 -0
  2. package/package.json +17 -4
  3. package/router.js +74 -0
  4. package/styles/dark-theme.css +20 -11
  5. package/styles/picocrank-extensions.css +123 -30
  6. package/supplemental-themes/catppuccin-latte-frappe/theme.css +10 -24
  7. package/supplemental-themes/dracula-alucard/theme.css +10 -24
  8. package/supplemental-themes/gruvbox-dark-light/theme.css +10 -24
  9. package/supplemental-themes/waffles/theme.css +2 -16
  10. package/vite.config.js +5 -0
  11. package/vue/components/Breadcrumbs.vue +192 -45
  12. package/vue/components/Calendar.vue +162 -145
  13. package/vue/components/DangerZone.vue +186 -0
  14. package/vue/components/FormField.spec.js +350 -0
  15. package/vue/components/FormField.vue +236 -32
  16. package/vue/components/FormLayout.spec.js +56 -0
  17. package/vue/components/Header.vue +22 -6
  18. package/vue/components/Login.vue +152 -41
  19. package/vue/components/NavigationGrid.vue +26 -180
  20. package/vue/components/NotificationBlock.vue +120 -0
  21. package/vue/components/NotificationPopup.vue +44 -41
  22. package/vue/components/Pagination.vue +5 -4
  23. package/vue/components/ReadOnlyTextArea.vue +1 -1
  24. package/vue/components/SidebarNavLink.vue +3 -3
  25. package/vue/components/Table.vue +107 -79
  26. package/vue/components/TableColumnOptionsPopover.vue +9 -0
  27. package/vue/components/Tabs.spec.js +101 -0
  28. package/vue/components/Tabs.vue +455 -81
  29. package/vue/components/TopBar.vue +2 -2
  30. package/vue/components/form-validation.spec.js +126 -0
  31. package/vue/composables/tableColumnPriorities.js +33 -0
  32. package/vue/composables/tableFilters.js +1 -1
  33. package/vue/data/navSectionHubs.js +196 -0
  34. package/vue/data/routeBreadcrumbs.js +90 -0
  35. package/vue/examples/Admin.vue +12 -12
  36. package/vue/examples/App.vue +27 -36
  37. package/vue/examples/CalendarExample.vue +32 -22
  38. package/vue/examples/ExampleHeaderThemeSwitcher.vue +1 -1
  39. package/vue/examples/FormExample.vue +76 -48
  40. package/vue/examples/Login.vue +5 -3
  41. package/vue/examples/LoginExample.vue +99 -15
  42. package/vue/examples/NavSectionHub.vue +36 -0
  43. package/vue/examples/PageStructure.vue +15 -12
  44. package/vue/examples/StatusExample.vue +248 -129
  45. package/vue/examples/TableExample.vue +72 -71
  46. package/vue/examples/TabsExample.vue +236 -257
  47. package/vue/examples/ThemePreview.vue +21 -23
  48. package/vue/examples/ViewItem.vue +32 -5
  49. package/vue/examples/Welcome.vue +3 -40
  50. package/vue/test/formTestUtils.js +279 -0
  51. package/vue/test/setup.js +5 -0
@@ -0,0 +1,75 @@
1
+ import js from '@eslint/js'
2
+ import pluginVue from 'eslint-plugin-vue'
3
+ import globals from 'globals'
4
+ import vueParser from 'vue-eslint-parser'
5
+
6
+ export default [
7
+ {
8
+ ignores: ['dist/**', 'node_modules/**'],
9
+ },
10
+ js.configs.recommended,
11
+ ...pluginVue.configs['flat/recommended'],
12
+ {
13
+ files: ['**/*.{js,vue}'],
14
+ languageOptions: {
15
+ ecmaVersion: 'latest',
16
+ sourceType: 'module',
17
+ globals: {
18
+ ...globals.browser,
19
+ ...globals.node,
20
+ },
21
+ },
22
+ rules: {
23
+ 'no-unused-vars': ['error', {
24
+ argsIgnorePattern: '^_',
25
+ caughtErrorsIgnorePattern: '^_',
26
+ varsIgnorePattern: '^_',
27
+ }],
28
+ 'vue/multi-word-component-names': 'off',
29
+ 'vue/no-v-html': 'off',
30
+ 'vue/html-indent': 'off',
31
+ 'vue/max-attributes-per-line': 'off',
32
+ 'vue/singleline-html-element-content-newline': 'off',
33
+ 'vue/html-self-closing': 'off',
34
+ 'vue/multiline-html-element-content-newline': 'off',
35
+ 'vue/first-attribute-linebreak': 'off',
36
+ 'vue/html-closing-bracket-newline': 'off',
37
+ 'vue/attributes-order': 'off',
38
+ 'vue/attribute-hyphenation': 'off',
39
+ 'vue/v-on-event-hyphenation': 'off',
40
+ 'vue/no-spaces-around-equal-signs-in-attribute': 'off',
41
+ 'vue/require-default-prop': 'off',
42
+ 'vue/block-order': 'off',
43
+ 'vue/v-slot-style': 'off',
44
+ 'vue/html-closing-bracket-spacing': 'off',
45
+ },
46
+ },
47
+ {
48
+ files: ['**/*.vue'],
49
+ languageOptions: {
50
+ parser: vueParser,
51
+ parserOptions: {
52
+ sourceType: 'module',
53
+ extraFileExtensions: ['.vue'],
54
+ },
55
+ },
56
+ },
57
+ {
58
+ files: ['**/*.spec.js', 'vue/test/**'],
59
+ languageOptions: {
60
+ globals: {
61
+ ...globals.browser,
62
+ ...globals.node,
63
+ },
64
+ },
65
+ rules: {
66
+ 'vue/one-component-per-file': 'off',
67
+ },
68
+ },
69
+ {
70
+ files: ['**/*.vue'],
71
+ rules: {
72
+ 'no-undef': 'off',
73
+ },
74
+ },
75
+ ]
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "picocrank",
3
- "version": "1.25.2",
3
+ "version": "1.27.0",
4
+ "type": "module",
4
5
  "description": "A set of zero dependency Vue components built on the Femtocrank global CSS theme.",
5
6
  "main": "vite.config.js",
6
7
  "scripts": {
@@ -8,7 +9,10 @@
8
9
  "build": "vite build --base './'",
9
10
  "build:minimal": "VITE_INCLUDE_SUPPLEMENTAL_THEMES=false vite build --base './'",
10
11
  "preview": "vite preview",
11
- "test": "echo \"Error: no test specified\" && exit 1"
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest"
12
16
  },
13
17
  "repository": {
14
18
  "type": "git",
@@ -23,14 +27,23 @@
23
27
  "@hugeicons/core-free-icons": "^4.3.0",
24
28
  "@hugeicons/vue": "^1.0.8",
25
29
  "@vitejs/plugin-vue": "^6.0.8",
26
- "femtocrank": "^2.6.1",
30
+ "femtocrank": "^2.7.1",
27
31
  "unplugin-vue-components": "^32.1.0",
28
32
  "vite": "^8.2.2",
29
33
  "vue": "^3.5.41",
30
34
  "vue-router": "^5.2.0"
31
35
  },
32
36
  "devDependencies": {
33
- "semantic-release": "^25.0.9"
37
+ "@eslint/js": "^10.0.1",
38
+ "@vitest/coverage-v8": "^4.1.11",
39
+ "@vue/test-utils": "^2.4.11",
40
+ "eslint": "^10.9.1",
41
+ "eslint-plugin-vue": "^10.10.0",
42
+ "globals": "^17.11.0",
43
+ "happy-dom": "^20.11.8",
44
+ "semantic-release": "^25.0.9",
45
+ "vitest": "^4.1.11",
46
+ "vue-eslint-parser": "^10.4.1"
34
47
  },
35
48
  "homepage": "https://github.com/jamesread/picocrank#readme"
36
49
  }
package/router.js CHANGED
@@ -16,6 +16,13 @@ import { PaintBoardIcon } from '@hugeicons/core-free-icons';
16
16
  import { UserIcon } from '@hugeicons/core-free-icons';
17
17
  import { InformationCircleIcon } from '@hugeicons/core-free-icons';
18
18
 
19
+ import {
20
+ hubChildBreadcrumbs,
21
+ hubSectionBreadcrumbs,
22
+ standaloneBreadcrumbs,
23
+ viewItemBreadcrumbs,
24
+ } from './vue/data/routeBreadcrumbs.js';
25
+
19
26
  const routes = [
20
27
  {
21
28
  name: 'Welcome',
@@ -33,6 +40,7 @@ const routes = [
33
40
  meta: {
34
41
  title: 'Page structure',
35
42
  icon: LayoutGridIcon,
43
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'PageStructure', 'Page structure'),
36
44
  }
37
45
  },
38
46
  {
@@ -42,6 +50,7 @@ const routes = [
42
50
  meta: {
43
51
  title: 'Theme Switcher',
44
52
  icon: PaintBoardIcon,
53
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'ThemePreview', 'Theme Switcher'),
45
54
  }
46
55
  },
47
56
  {
@@ -51,6 +60,7 @@ const routes = [
51
60
  meta: {
52
61
  title: 'User details',
53
62
  icon: UserIcon,
63
+ breadcrumbs: standaloneBreadcrumbs('UserDetails', 'User details'),
54
64
  }
55
65
  },
56
66
  {
@@ -61,6 +71,7 @@ const routes = [
61
71
  meta: {
62
72
  title: 'Table',
63
73
  icon: TableIcon,
74
+ breadcrumbs: hubChildBreadcrumbs('NavDataDisplayHub', 'TableExample', 'Table'),
64
75
  }
65
76
  },
66
77
  {
@@ -70,6 +81,7 @@ const routes = [
70
81
  meta: {
71
82
  title: 'Remote table',
72
83
  icon: TableIcon,
84
+ breadcrumbs: hubChildBreadcrumbs('NavDataDisplayHub', 'TableRemoteExample', 'Remote table'),
73
85
  }
74
86
  },
75
87
  {
@@ -80,6 +92,7 @@ const routes = [
80
92
  meta: {
81
93
  title: 'View item',
82
94
  icon: ViewIcon,
95
+ breadcrumbs: viewItemBreadcrumbs,
83
96
  }
84
97
  },
85
98
  {
@@ -89,6 +102,7 @@ const routes = [
89
102
  meta: {
90
103
  title: 'Admin',
91
104
  icon: SecurityValidationIcon,
105
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'Admin', 'Admin'),
92
106
  }
93
107
  },
94
108
  {
@@ -99,6 +113,7 @@ const routes = [
99
113
  meta: {
100
114
  title: 'Calendar',
101
115
  icon: CalendarIcon,
116
+ breadcrumbs: hubChildBreadcrumbs('NavDataDisplayHub', 'CalendarExample', 'Calendar'),
102
117
  }
103
118
  },
104
119
  {
@@ -108,6 +123,7 @@ const routes = [
108
123
  meta: {
109
124
  title: 'Login',
110
125
  icon: SecurityValidationIcon,
126
+ breadcrumbs: standaloneBreadcrumbs('Login', 'Login'),
111
127
  }
112
128
  },
113
129
  {
@@ -117,6 +133,7 @@ const routes = [
117
133
  meta: {
118
134
  title: 'Buttons',
119
135
  icon: CursorPointer01Icon,
136
+ breadcrumbs: hubChildBreadcrumbs('NavFormsInputHub', 'ButtonsExample', 'Buttons'),
120
137
  }
121
138
  },
122
139
  {
@@ -126,6 +143,7 @@ const routes = [
126
143
  meta: {
127
144
  title: 'Forms',
128
145
  icon: EditIcon,
146
+ breadcrumbs: hubChildBreadcrumbs('NavFormsInputHub', 'FormExample', 'Forms'),
129
147
  }
130
148
  },
131
149
  {
@@ -135,6 +153,7 @@ const routes = [
135
153
  meta: {
136
154
  title: 'Read-only output',
137
155
  icon: ClipboardCopyIcon,
156
+ breadcrumbs: hubChildBreadcrumbs('NavDataDisplayHub', 'ReadOnlyTextAreaExample', 'Read-only output'),
138
157
  }
139
158
  },
140
159
  {
@@ -144,6 +163,7 @@ const routes = [
144
163
  meta: {
145
164
  title: 'Status & notifications',
146
165
  icon: StatusIcon,
166
+ breadcrumbs: hubChildBreadcrumbs('NavFeedbackStatusHub', 'StatusExample', 'Status & notifications'),
147
167
  }
148
168
  },
149
169
  {
@@ -153,6 +173,7 @@ const routes = [
153
173
  meta: {
154
174
  title: 'Dialog',
155
175
  icon: InformationCircleIcon,
176
+ breadcrumbs: hubChildBreadcrumbs('NavFeedbackStatusHub', 'DialogExample', 'Dialog'),
156
177
  }
157
178
  },
158
179
  {
@@ -162,6 +183,7 @@ const routes = [
162
183
  meta: {
163
184
  title: 'Tabs',
164
185
  icon: Menu01Icon,
186
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'TabsExample', 'Tabs'),
165
187
  }
166
188
  },
167
189
  {
@@ -171,6 +193,57 @@ const routes = [
171
193
  meta: {
172
194
  title: 'Navigation Grid',
173
195
  icon: Navigation01Icon,
196
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'NavigationGridExample', 'Navigation Grid'),
197
+ }
198
+ },
199
+ {
200
+ name: 'NavLayoutsHub',
201
+ path: '/nav/layouts',
202
+ component: () => import('./vue/examples/NavSectionHub.vue'),
203
+ meta: {
204
+ title: 'Layouts',
205
+ icon: LayoutGridIcon,
206
+ breadcrumbs: hubSectionBreadcrumbs('NavLayoutsHub'),
207
+ }
208
+ },
209
+ {
210
+ name: 'NavDataDisplayHub',
211
+ path: '/nav/data-display',
212
+ component: () => import('./vue/examples/NavSectionHub.vue'),
213
+ meta: {
214
+ title: 'Data display',
215
+ icon: TableIcon,
216
+ breadcrumbs: hubSectionBreadcrumbs('NavDataDisplayHub'),
217
+ }
218
+ },
219
+ {
220
+ name: 'NavFormsInputHub',
221
+ path: '/nav/forms-input',
222
+ component: () => import('./vue/examples/NavSectionHub.vue'),
223
+ meta: {
224
+ title: 'Forms & input',
225
+ icon: EditIcon,
226
+ breadcrumbs: hubSectionBreadcrumbs('NavFormsInputHub'),
227
+ }
228
+ },
229
+ {
230
+ name: 'NavFeedbackStatusHub',
231
+ path: '/nav/feedback-status',
232
+ component: () => import('./vue/examples/NavSectionHub.vue'),
233
+ meta: {
234
+ title: 'Feedback & status',
235
+ icon: StatusIcon,
236
+ breadcrumbs: hubSectionBreadcrumbs('NavFeedbackStatusHub'),
237
+ }
238
+ },
239
+ {
240
+ name: 'NavPatternsHub',
241
+ path: '/nav/patterns',
242
+ component: () => import('./vue/examples/NavSectionHub.vue'),
243
+ meta: {
244
+ title: 'Patterns',
245
+ icon: CursorPointer01Icon,
246
+ breadcrumbs: hubSectionBreadcrumbs('NavPatternsHub'),
174
247
  }
175
248
  },
176
249
  {
@@ -180,6 +253,7 @@ const routes = [
180
253
  meta: {
181
254
  title: 'Login',
182
255
  icon: SecurityValidationIcon,
256
+ breadcrumbs: hubChildBreadcrumbs('NavFormsInputHub', 'LoginExample', 'Login'),
183
257
  }
184
258
  }
185
259
  ];
@@ -4,9 +4,9 @@ html[data-theme="dark"] {
4
4
  color-scheme: dark;
5
5
 
6
6
  --body-bg-color: #262626;
7
- --surface-bg-color: #343434;
7
+ --section-bg-color: #343434;
8
8
  --standout-bg-color: #1f1f1f;
9
- --section-header-bg-color: var(--surface-bg-color);
9
+ --section-header-bg-color: var(--section-bg-color);
10
10
 
11
11
  --header-bg-color: #000;
12
12
  --header-border-color: #222;
@@ -18,16 +18,18 @@ html[data-theme="dark"] {
18
18
  --sidebar-hover-bg-color: var(--hover-background-color);
19
19
 
20
20
  --footer-chip-bg-color: #444;
21
+ --footer-link-color: lightblue;
21
22
 
22
23
  --text-color: #ddd;
24
+ --muted-text-color: color-mix(in srgb, var(--text-color) 87%, #121619);
23
25
  --link-color: lightblue;
24
26
  --annotation-key-color: #aaa;
25
27
  --focus-outline-color: #fff;
26
28
 
27
29
  --border-color: #595959;
28
- --shadow-color: #121212;
30
+ --shadow-color: color-mix(in srgb, var(--body-bg-color) 48%, #121619);
29
31
 
30
- --hover-background-color: #1d345c;
32
+ --hover-background-color: color-mix(in srgb, var(--header-hover-background-color) 45%, var(--section-bg-color));
31
33
  --hover-text-color: var(--on-accent-fg);
32
34
 
33
35
  --disabled-background-color: #333;
@@ -35,26 +37,33 @@ html[data-theme="dark"] {
35
37
 
36
38
  --input-bg-color: #4e4e4e;
37
39
  --input-fg-color: var(--text-color);
38
- --control-option-bg-color: #555;
40
+ --control-option-bg-color: var(--section-bg-color);
39
41
  --control-hover-bg-color: var(--hover-background-color);
42
+ --control-checked-bg: color-mix(in srgb, #8fb59a 45%, var(--section-bg-color));
43
+ --control-checked-hover-bg: color-mix(in srgb, #8fb59a 55%, var(--section-bg-color));
44
+ --control-checked-fg: var(--text-color);
40
45
 
41
46
  --menu-item-hover-background-color: var(--hover-background-color);
42
- --menu-dropdown-background-color: var(--surface-bg-color);
43
- --menu-dropdown-shadow: 0 0 .5em var(--shadow-color);
47
+ --menu-dropdown-background-color: var(--section-bg-color);
48
+ --menu-dropdown-shadow: 0 .4em 1.1em color-mix(in srgb, black 55%, transparent), 0 0 0 1px var(--menu-dropdown-border-color);
44
49
  --menu-dropdown-link-hover-background-color: var(--hover-background-color);
45
50
  --header-menu-dropdown-link-hover-background-color: var(--header-hover-background-color);
46
51
 
47
- --table-sticky-bg: var(--surface-bg-color);
52
+ --table-sticky-bg: var(--section-bg-color);
48
53
  --table-row-hover-bg: var(--hover-background-color);
49
54
  --table-row-hover-fg: var(--on-accent-fg);
50
55
  --table-sticky-hover-bg: var(--table-row-hover-bg);
51
- --table-uneditable-bg: #555;
56
+ --table-uneditable-bg: color-mix(in srgb, var(--header-hover-background-color) 18%, var(--section-bg-color));
52
57
  --table-sticky-uneditable-bg: var(--table-uneditable-bg);
53
58
 
54
59
  --progress-track-bg-color: var(--table-uneditable-bg);
60
+ --progress-fill-bg-color: #8fb59a;
55
61
 
56
- --nav-grid-accent-fg: var(--link-color);
57
- --nav-grid-accent-bg: var(--link-color);
62
+ --karma-info-tint: color-mix(in srgb, var(--karma-info) 30%, var(--standout-bg-color));
63
+ --karma-info-wash: color-mix(in srgb, var(--karma-info) 22%, var(--standout-bg-color));
64
+
65
+ --karma-warning: #ffeb3b;
66
+ --karma-warning-tint: color-mix(in srgb, var(--karma-warning) 30%, var(--standout-bg-color));
58
67
  }
59
68
 
60
69
  html[data-theme="light"] {
@@ -5,22 +5,13 @@
5
5
  --table-header-active-fg: var(--link-color);
6
6
  --table-header-active-bg: var(--hover-background-color);
7
7
  --tab-fg: var(--muted-text-color);
8
- --tab-active-fg: var(--link-color);
9
- --tab-focus-outline-color: var(--tab-active-fg);
10
-
11
- /* Default light: bright bold blues for icons and active fill. */
12
- --nav-grid-accent-fg: #007dff;
13
- --nav-grid-accent-bg: #0066cc;
14
- --nav-grid-active-fg: var(--button-on-accent-fg);
15
- --nav-grid-muted-fg: var(--muted-text-color);
16
- --nav-grid-border: var(--border-color);
17
- --nav-grid-hover-bg: var(--hover-background-color);
18
- --nav-grid-indicator-bg: var(--button-bad-bg);
19
- --nav-grid-indicator-fg: var(--button-on-accent-fg);
20
- --nav-grid-ring-bg: var(--surface-bg-color);
21
- --nav-grid-disabled-fg: var(--disabled-text-color);
22
- --nav-grid-shadow: var(--shadow-color);
23
- --nav-grid-hover-shadow: color-mix(in srgb, var(--nav-grid-shadow) 50%, transparent);
8
+ --tab-active-fg: var(--control-checked-fg);
9
+ --tab-active-bg: var(--control-checked-bg);
10
+ --tab-active-hover-bg: var(--control-checked-hover-bg);
11
+
12
+ --hover-background-color: color-mix(in srgb, var(--body-bg-color) 45%, var(--section-bg-color));
13
+ --control-hover-bg-color: var(--hover-background-color);
14
+ --sidebar-hover-bg-color: var(--hover-background-color);
24
15
 
25
16
  --quick-search-dialog-bg: var(--standout-bg-color);
26
17
  --quick-search-dialog-fg: var(--text-color);
@@ -31,25 +22,29 @@
31
22
  --quick-search-muted-fg: var(--muted-text-color);
32
23
  --quick-search-subtle-fg: var(--annotation-key-color);
33
24
  --quick-search-focus-outline: var(--focus-outline-color);
34
- --quick-search-highlight-bg: var(--karma-important);
25
+ --quick-search-highlight-bg: var(--karma-warning-tint);
35
26
  --quick-search-hover-bg: var(--hover-background-color);
36
27
  --quick-search-hover-fg: var(--hover-text-color);
37
28
 
38
- --breadcrumbs-separator-fg: var(--muted-text-color);
39
- --breadcrumbs-link-hover-bg: var(--hover-background-color);
40
-
41
29
  --radio-group-focus-outline: var(--focus-outline-color);
42
30
  --radio-group-checked-hover-bg: var(--control-checked-hover-bg);
43
31
  --radio-group-checked-hover-fg: var(--control-checked-fg);
44
32
 
45
33
  --login-input-focus-outline: var(--focus-outline-color);
46
34
  --login-error-bg: var(--karma-bad);
47
- --login-error-fg: var(--karma-bad-fg);
35
+ --login-error-fg: var(--karma-on-bg-fg);
48
36
  --login-muted-fg: var(--muted-text-color);
49
37
 
38
+ --login-spinner-fg: var(--link-color);
39
+ --login-spinner-track: var(--border-color);
40
+
41
+ --form-field-required-fg: var(--karma-bad);
42
+
50
43
  --table-muted-fg: var(--muted-text-color);
51
44
 
52
- --table-popover-bg: var(--surface-bg-color);
45
+ --button-transparent-disabled-fg: color-mix(in srgb, var(--text-color) 45%, var(--section-bg-color));
46
+
47
+ --table-popover-bg: var(--section-bg-color);
53
48
  --table-popover-border: var(--border-color);
54
49
  --table-popover-shadow: 0 8px 24px color-mix(in srgb, var(--shadow-color) 60%, transparent);
55
50
  --table-popover-muted-fg: var(--muted-text-color);
@@ -57,17 +52,17 @@
57
52
  --table-popover-item-bg: var(--standout-bg-color);
58
53
  --table-popover-item-drag-border: var(--text-color);
59
54
  --table-popover-divider: var(--border-color);
60
- --table-popover-error-fg: var(--karma-bad-fg);
61
- --table-popover-success-fg: var(--karma-good-fg);
55
+ --table-popover-error-fg: var(--karma-bad);
56
+ --table-popover-success-fg: var(--karma-good);
62
57
 
63
58
  --tab-border: var(--border-color);
64
59
  --tab-hover-fg: var(--text-color);
65
60
  --tab-hover-bg: var(--hover-background-color);
66
61
 
67
62
  --calendar-chrome-bg: var(--standout-bg-color);
68
- --calendar-surface-bg: var(--surface-bg-color);
63
+ --calendar-surface-bg: var(--section-bg-color);
69
64
  --calendar-border: var(--border-color);
70
- --calendar-error-fg: var(--karma-bad-fg);
65
+ --calendar-error-fg: var(--karma-bad);
71
66
  --calendar-loading-overlay-bg: color-mix(in srgb, var(--calendar-surface-bg) 60%, transparent);
72
67
  --calendar-day-fg: var(--text-color);
73
68
  --calendar-muted-fg: var(--muted-text-color);
@@ -75,23 +70,121 @@
75
70
  --calendar-day-hover-bg: color-mix(in srgb, var(--link-color) 8%, var(--calendar-surface-bg));
76
71
  --calendar-day-muted-bg: var(--standout-bg-color);
77
72
  --calendar-day-muted-hover-bg: var(--table-uneditable-bg);
78
- --calendar-today-bg: var(--karma-important);
79
- --calendar-today-hover-bg: var(--karma-note);
73
+ --calendar-today-bg: var(--karma-warning-tint);
74
+ --calendar-today-hover-bg: var(--karma-note-tint);
80
75
  --calendar-range-accent: var(--link-color);
81
76
  --calendar-range-bg-strong: color-mix(in srgb, var(--link-color) 22%, transparent);
82
77
  --calendar-range-bg: color-mix(in srgb, var(--link-color) 14%, transparent);
83
78
  --calendar-range-bg-subtle: color-mix(in srgb, var(--link-color) 10%, transparent);
84
79
  --calendar-event-bg: var(--karma-good);
85
- --calendar-event-border: color-mix(in srgb, var(--karma-good-fg) 35%, var(--karma-good));
86
- --calendar-event-hover-bg: color-mix(in srgb, var(--karma-good) 80%, var(--karma-good-fg));
80
+ --calendar-event-border: color-mix(in srgb, var(--karma-on-bg-fg) 35%, var(--karma-good));
81
+ --calendar-event-hover-bg: color-mix(in srgb, var(--karma-good) 80%, var(--karma-on-bg-fg));
87
82
  --calendar-event-title-fg: var(--text-color);
88
83
  --calendar-event-shadow: 0 1px 2px color-mix(in srgb, var(--shadow-color) 50%, transparent);
89
84
  --calendar-event-hover-shadow: 0 2px 4px color-mix(in srgb, var(--shadow-color) 60%, transparent);
90
85
  --calendar-more-bg: var(--standout-bg-color);
91
86
  --calendar-event-custom-border-mix: var(--karma-on-bg-fg);
87
+
88
+ --danger-zone-border: color-mix(in srgb, var(--karma-bad) 35%, var(--border-color));
89
+ --danger-zone-bg: var(--standout-bg-color);
90
+ --danger-zone-summary-hover-bg: var(--karma-bad-tint);
91
+ --danger-zone-warning-fg: var(--muted-text-color);
92
+ --danger-zone-focus-outline: var(--karma-bad-border);
92
93
  }
93
94
 
94
95
  table thead th {
95
96
  color: var(--table-header-fg);
96
97
  }
98
+
99
+ /* Flex children default to min-width: auto, which lets wide tables expand the page. */
100
+ #content,
101
+ #content main,
102
+ section .section-content {
103
+ min-width: 0;
104
+ }
105
+
106
+ /* Femtocrank 2.7 compacts section toolbars; keep pre-upgrade default button padding. */
107
+ section .section-header [role="toolbar"] button,
108
+ section .section-header [role="toolbar"] .button {
109
+ padding-top: .4em;
110
+ padding-bottom: .4em;
111
+ padding-left: 1em;
112
+ padding-right: 1em;
113
+ min-width: 0;
114
+ line-height: normal;
115
+ }
116
+
117
+ section.narrow {
118
+ max-width: 480px;
119
+ margin-left: auto;
120
+ margin-right: auto;
121
+ border-radius: .8em;
122
+ }
123
+
124
+ section.narrow form {
125
+ grid-template-columns: 1fr;
126
+ }
127
+
128
+ section.narrow fieldset {
129
+ grid-column: span 1;
130
+ }
131
+
132
+ form > .form-field-label-skip {
133
+ grid-column: 1 / -1;
134
+ }
135
+
136
+ /*
137
+ * FormField applies .field-invalid when an error is set programmatically.
138
+ * Mirrors femtocrank :user-invalid (which only applies after user interaction).
139
+ */
140
+ input.field-invalid,
141
+ textarea.field-invalid,
142
+ select.field-invalid {
143
+ border-color: var(--karma-bad-border);
144
+ background-color: var(--karma-bad-wash);
145
+ color: var(--text-color);
146
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--karma-bad) 35%, transparent);
147
+ }
148
+
149
+ input.field-invalid:focus-visible,
150
+ textarea.field-invalid:focus-visible,
151
+ select.field-invalid:focus-visible {
152
+ outline: 2px solid var(--karma-bad-border);
153
+ outline-offset: 2px;
154
+ }
155
+ }
156
+
157
+ /*
158
+ * Responsive column priorities: classes col-priority-1 … col-priority-5 on th/td only
159
+ * take effect inside a .responsive-cols wrapper via container queries (not standalone
160
+ * class rules). Mirrored here (outside @layer) so they win the cascade and are easy to find.
161
+ * See also node_modules/femtocrank/style.css (.responsive-cols / @container responsive-cols).
162
+ */
163
+ .responsive-cols {
164
+ container-type: inline-size;
165
+ container-name: responsive-cols;
166
+ display: block;
167
+ width: 100%;
168
+ min-width: 0;
169
+ max-width: 100%;
170
+ }
171
+
172
+ @container responsive-cols (max-width: 38rem) {
173
+ :is(th, td).col-priority-1 { display: none; }
174
+ }
175
+
176
+ @container responsive-cols (max-width: 34rem) {
177
+ :is(th, td).col-priority-2 { display: none; }
178
+ }
179
+
180
+ @container responsive-cols (max-width: 30rem) {
181
+ :is(th, td).col-priority-3 { display: none; }
182
+ }
183
+
184
+ @container responsive-cols (max-width: 26rem) {
185
+ :is(th, td).col-priority-4 { display: none; }
186
+ }
187
+
188
+ @container responsive-cols (max-width: 22rem) {
189
+ :is(th, td).col-priority-5 { display: none; }
97
190
  }
@@ -41,7 +41,7 @@ html[data-theme="dark"] {
41
41
  --ctp-good-fg: var(--ctp-crust);
42
42
 
43
43
  --body-bg-color: var(--ctp-base);
44
- --surface-bg-color: var(--ctp-mantle);
44
+ --section-bg-color: var(--ctp-mantle);
45
45
  --standout-bg-color: var(--ctp-mantle);
46
46
  --section-header-bg-color: var(--ctp-mantle);
47
47
  --shadow-color: var(--ctp-shadow-strong);
@@ -50,8 +50,6 @@ html[data-theme="dark"] {
50
50
  --muted-text-color: var(--ctp-subtext0);
51
51
  --annotation-key-color: var(--ctp-subtext0);
52
52
  --link-color: var(--ctp-blue);
53
- --nav-grid-accent-fg: var(--link-color);
54
- --nav-grid-accent-bg: var(--link-color);
55
53
  --border-color: var(--ctp-surface1);
56
54
 
57
55
  --hover-background-color: var(--ctp-surface0);
@@ -74,6 +72,9 @@ html[data-theme="dark"] {
74
72
  --input-fg-color: var(--ctp-text);
75
73
  --control-option-bg-color: var(--ctp-surface0);
76
74
  --control-hover-bg-color: var(--ctp-surface1);
75
+ --control-checked-bg: color-mix(in srgb, var(--ctp-green) 28%, var(--standout-bg-color));
76
+ --control-checked-hover-bg: color-mix(in srgb, var(--ctp-green) 36%, var(--standout-bg-color));
77
+ --control-checked-fg: var(--ctp-text);
77
78
  --menu-hover-bg-color: var(--ctp-surface0);
78
79
 
79
80
  --table-row-hover-bg: var(--ctp-surface0);
@@ -96,19 +97,11 @@ html[data-theme="dark"] {
96
97
  --karma-bad: var(--ctp-red);
97
98
  --karma-warning: var(--ctp-yellow);
98
99
  --karma-severe: var(--ctp-maroon);
99
- --karma-important: var(--ctp-peach);
100
100
  --karma-note: var(--ctp-sapphire);
101
101
  --karma-info: var(--ctp-surface1);
102
102
  --karma-old: var(--ctp-overlay0);
103
103
 
104
- --karma-good-fg: var(--ctp-green);
105
- --karma-bad-fg: var(--ctp-red);
106
- --karma-warning-fg: var(--ctp-yellow);
107
- --karma-severe-fg: var(--ctp-maroon);
108
- --karma-important-fg: var(--ctp-peach);
109
- --karma-note-fg: var(--ctp-sapphire);
110
- --karma-info-fg: var(--ctp-subtext0);
111
- --karma-old-fg: var(--ctp-overlay1);
104
+ --karma-on-bg-fg: var(--ctp-good-fg);
112
105
  }
113
106
 
114
107
  html[data-theme="light"] {
@@ -144,7 +137,7 @@ html[data-theme="light"] {
144
137
  --ctp-good-fg: var(--ctp-base);
145
138
 
146
139
  --body-bg-color: var(--ctp-base);
147
- --surface-bg-color: var(--ctp-mantle);
140
+ --section-bg-color: var(--ctp-mantle);
148
141
  --standout-bg-color: var(--ctp-mantle);
149
142
  --section-header-bg-color: var(--ctp-mantle);
150
143
  --shadow-color: var(--ctp-shadow-strong);
@@ -153,8 +146,6 @@ html[data-theme="light"] {
153
146
  --muted-text-color: var(--ctp-subtext0);
154
147
  --annotation-key-color: var(--ctp-subtext0);
155
148
  --link-color: var(--ctp-blue);
156
- --nav-grid-accent-fg: var(--link-color);
157
- --nav-grid-accent-bg: var(--link-color);
158
149
  --border-color: var(--ctp-surface1);
159
150
 
160
151
  --hover-background-color: var(--ctp-surface0);
@@ -177,6 +168,9 @@ html[data-theme="light"] {
177
168
  --input-fg-color: var(--ctp-text);
178
169
  --control-option-bg-color: var(--ctp-surface0);
179
170
  --control-hover-bg-color: var(--ctp-surface1);
171
+ --control-checked-bg: color-mix(in srgb, var(--ctp-green) 20%, var(--standout-bg-color));
172
+ --control-checked-hover-bg: color-mix(in srgb, var(--ctp-green) 28%, var(--standout-bg-color));
173
+ --control-checked-fg: var(--ctp-text);
180
174
  --menu-hover-bg-color: var(--ctp-surface0);
181
175
 
182
176
  --table-row-hover-bg: var(--ctp-surface0);
@@ -199,17 +193,9 @@ html[data-theme="light"] {
199
193
  --karma-bad: var(--ctp-red);
200
194
  --karma-warning: var(--ctp-yellow);
201
195
  --karma-severe: var(--ctp-maroon);
202
- --karma-important: var(--ctp-peach);
203
196
  --karma-note: var(--ctp-sapphire);
204
197
  --karma-info: var(--ctp-surface1);
205
198
  --karma-old: var(--ctp-overlay0);
206
199
 
207
- --karma-good-fg: var(--ctp-green);
208
- --karma-bad-fg: var(--ctp-red);
209
- --karma-warning-fg: var(--ctp-yellow);
210
- --karma-severe-fg: var(--ctp-maroon);
211
- --karma-important-fg: var(--ctp-peach);
212
- --karma-note-fg: var(--ctp-sapphire);
213
- --karma-info-fg: var(--ctp-subtext0);
214
- --karma-old-fg: var(--ctp-overlay1);
200
+ --karma-on-bg-fg: var(--ctp-good-fg);
215
201
  }