basalt-ui 1.37.1 → 1.38.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## [1.38.1](https://github.com/jkrumm/basalt-ui/compare/v1.38.0...v1.38.1) (2026-10-04)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * take the page content inset one step down, 20/12 to 16/8 from sm up ([cf61c05](https://github.com/jkrumm/basalt-ui/commit/cf61c05410df114d5c6182ed4a8c5ed38b308a56))
7
+
8
+ # [1.38.0](https://github.com/jkrumm/basalt-ui/compare/v1.37.1...v1.38.0) (2026-10-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * inset the sidebar footer and seat the rail first icon like the expanded row ([7d9e980](https://github.com/jkrumm/basalt-ui/commit/7d9e980b9c1d6cd062e0d8f43a4800f7002b174d))
14
+ * re-date the forms layout deprecations to 1.39.0 ([fe9e785](https://github.com/jkrumm/basalt-ui/commit/fe9e785439c8404dfe09bdcecb774db758123026))
15
+
16
+
17
+ ### Features
18
+
19
+ * add --basalt-shell-lead-inset for a native title bar over the header lead ([980c2ff](https://github.com/jkrumm/basalt-ui/commit/980c2ff707a39ec150b64d27780b3ceecb98b922))
20
+
1
21
  ## [1.37.1](https://github.com/jkrumm/basalt-ui/compare/v1.37.0...v1.37.1) (2026-10-02)
2
22
 
3
23
 
package/MIGRATING.md CHANGED
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
66
66
  shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
67
67
  consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
68
68
 
69
- | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | Unreleased |
70
- | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ---------- |
71
- | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — |
72
- | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — |
73
- | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — |
74
- | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — |
75
- | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — |
76
- | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — |
77
- | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
78
- | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
79
- | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
80
- | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — |
69
+ | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | Unreleased |
70
+ | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | --- |
71
+ | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — |
72
+ | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — |
73
+ | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — |
74
+ | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — |
75
+ | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — |
76
+ | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — |
77
+ | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
78
+ | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
79
+ | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
80
+ | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — |
81
81
 
82
82
  ---
83
83
 
@@ -86,6 +86,27 @@ consumer read this index, found nothing, and diffed a KPI row that had silently
86
86
  _Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
87
87
  release renames it and opens a new one here._
88
88
 
89
+ ## 1.38.1 — the content inset
90
+
91
+ No export changed. Two default numbers moved, both from `sm` up (the phone gutter is untouched):
92
+
93
+ | Measured, 1440px desktop | Before | After |
94
+ | --------------------------------------------------------- | -------- | -------- |
95
+ | Main's inner box, from the sidebar seam (`appShellInset`) | 20px | 16px |
96
+ | Main's inner box, under the header / page-bar band | 12px | 8px |
97
+ | Header breadcrumb x, expanded / rail | 269 / 61 | 272 / 64 |
98
+ | Brand mark x (the sidebar's nav-icon column) | 20px | 20px |
99
+
100
+ The block inset is `stack-sm` from `sm` up and stays `stack-md` (12) on a phone. The breadcrumb
101
+ now sits exactly on Main's content edge (it was 7px short of it); the brand mark no longer borrows
102
+ the page gutter for its x — it is the nav-icon column (`row-inset-x` twice) on its own, so it stays
103
+ at 20 while the gutter is 16. A consumer that wants the old numbers has no knob for them: the gutter
104
+ is a `SPACE_STEP` entry, so retune it through the density level or accept the new default.
105
+
106
+ ## 1.38.0
107
+
108
+ _Nothing to migrate in this release._
109
+
89
110
  ## 1.37.1
90
111
 
91
112
  _Nothing to migrate in this release._
@@ -133,15 +154,15 @@ import. `FormRow`/`FormGroup` stay law C1's form-row home from either subpath.
133
154
 
134
155
  | Was (`basalt-ui/forms`) | Now | Removed in |
135
156
  | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------- |
136
- | `FormSection`, `FormRow`, `FormGroup`, `FormActions` (+ their `*Props`/`*Slot` types) | the same names from `basalt-ui/controls` | 1.38.0 |
137
- | `useForm`, `schemaResolver`, `UseFormReturnType`, `UseFormInput` | `@mantine/form` directly (zero consumers imported them from basalt) | 1.38.0 |
157
+ | `FormSection`, `FormRow`, `FormGroup`, `FormActions` (+ their `*Props`/`*Slot` types) | the same names from `basalt-ui/controls` | 1.39.0 |
158
+ | `useForm`, `schemaResolver`, `UseFormReturnType`, `UseFormInput` | `@mantine/form` directly (zero consumers imported them from basalt) | 1.39.0 |
138
159
 
139
- **Grace:** every old import still resolves in 1.36.x and 1.37.x (re-dated from 1.37.0: consumers still import them). `basalt/deprecated-export` warns on the six
160
+ **Grace:** every old import still resolves in 1.36.x–1.38.x (re-dated twice, from 1.37.0 and again from 1.38.0: consumers still import them). `basalt/deprecated-export` warns on the six
140
161
  values, but the rows are `fix: false` — the autofix rewrites a specifier inside its own import
141
162
  statement and cannot change the module — so move the import by hand
142
163
  (`import { FormRow } from 'basalt-ui/controls'`). Both subpaths are homes for
143
164
  `control-outside-home`/`raw-selection-control` throughout. The `public symbols` budget runs at 401
144
- during the grace minor; 1.38.0 removes six.
165
+ during the grace minor; 1.39.0 removes six.
145
166
 
146
167
  ### `useCoarsePointer()` — the pointer class in JS
147
168
 
@@ -2049,7 +2049,7 @@ const CONTROL_OWNER_NAMES = new Set([
2049
2049
  * `control-outside-home` treating it as a home is the whole of the enforcement a settings page
2050
2050
  * gets, and the two tier rules deliberately do not reach inside it (see {@link SLOT_ATTRS}).
2051
2051
  * `FormRow`/`FormGroup` (`basalt-ui/controls`, `src/controls/form-layout.tsx`; `basalt-ui/forms`
2052
- * re-exports them until 1.38.0 — the set is NAME-matched, so both subpaths are homes) are the SAME
2052
+ * re-exports them until 1.39.0 — the set is NAME-matched, so both subpaths are homes) are the SAME
2053
2053
  * home written for a `<form>` rather than a settings page — a `TextInput` bound to a field is read and typed
2054
2054
  * into at Mantine's own tier, not a 30px chrome affordance — so they are added here rather than
2055
2055
  * given a second walk.
@@ -3671,42 +3671,42 @@ export const DEPRECATED_EXPORTS = [
3671
3671
  subpath: 'basalt-ui/forms',
3672
3672
  name: 'FormSection',
3673
3673
  replacement: "FormSection from 'basalt-ui/controls'",
3674
- removeIn: '1.38.0',
3674
+ removeIn: '1.39.0',
3675
3675
  fix: false,
3676
3676
  },
3677
3677
  {
3678
3678
  subpath: 'basalt-ui/forms',
3679
3679
  name: 'FormRow',
3680
3680
  replacement: "FormRow from 'basalt-ui/controls'",
3681
- removeIn: '1.38.0',
3681
+ removeIn: '1.39.0',
3682
3682
  fix: false,
3683
3683
  },
3684
3684
  {
3685
3685
  subpath: 'basalt-ui/forms',
3686
3686
  name: 'FormGroup',
3687
3687
  replacement: "FormGroup from 'basalt-ui/controls'",
3688
- removeIn: '1.38.0',
3688
+ removeIn: '1.39.0',
3689
3689
  fix: false,
3690
3690
  },
3691
3691
  {
3692
3692
  subpath: 'basalt-ui/forms',
3693
3693
  name: 'FormActions',
3694
3694
  replacement: "FormActions from 'basalt-ui/controls'",
3695
- removeIn: '1.38.0',
3695
+ removeIn: '1.39.0',
3696
3696
  fix: false,
3697
3697
  },
3698
3698
  {
3699
3699
  subpath: 'basalt-ui/forms',
3700
3700
  name: 'useForm',
3701
3701
  replacement: "useForm from '@mantine/form'",
3702
- removeIn: '1.38.0',
3702
+ removeIn: '1.39.0',
3703
3703
  fix: false,
3704
3704
  },
3705
3705
  {
3706
3706
  subpath: 'basalt-ui/forms',
3707
3707
  name: 'schemaResolver',
3708
3708
  replacement: "schemaResolver from '@mantine/form'",
3709
- removeIn: '1.38.0',
3709
+ removeIn: '1.39.0',
3710
3710
  fix: false,
3711
3711
  },
3712
3712
  {
@@ -1923,7 +1923,7 @@ describe('basalt/control-outside-home', () => {
1923
1923
  },
1924
1924
  )
1925
1925
 
1926
- // FormRow/FormGroup (`basalt-ui/controls`, still re-exported from `basalt-ui/forms` until 1.38.0)
1926
+ // FormRow/FormGroup (`basalt-ui/controls`, still re-exported from `basalt-ui/forms` until 1.39.0)
1927
1927
  // are law C1's third home written for a `<form>` rather than a settings page — the same non-home
1928
1928
  // treatment SettingsRow gets, via the same CONTROL_HOST_TAGS ancestry walk, which matches by NAME
1929
1929
  // so either subpath is a home.
@@ -3393,7 +3393,7 @@ describe('basalt/deprecated-export — the form layout move', () => {
3393
3393
  )
3394
3394
  expect(rules).toContain('deprecated-export')
3395
3395
  expect(output).toContain(`'basalt-ui/controls'`)
3396
- expect(output).toContain('removed in 1.38.0')
3396
+ expect(output).toContain('removed in 1.39.0')
3397
3397
  },
3398
3398
  )
3399
3399
 
@@ -10,7 +10,7 @@
10
10
  * (`useFormSubmit` + `FormStateProvider`), the list field (`useFieldArray`) and the draft
11
11
  * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) moved to
12
12
  * `basalt-ui/controls` in 1.36.0 — it needs no `@mantine/form` — and stays here as deprecated
13
- * aliases until 1.38.0, as do the `useForm`/`schemaResolver` re-exports (import from
13
+ * aliases until 1.39.0, as do the `useForm`/`schemaResolver` re-exports (import from
14
14
  * `@mantine/form`).
15
15
  *
16
16
  * Optional peer: @mantine/form ^9.3.0 — install with: bun add @mantine/form
@@ -19,26 +19,26 @@ export { useBasaltForm } from './create-form.js';
19
19
  export type { UseBasaltFormOptions } from './create-form.js';
20
20
  export { inputProps, fieldKey } from './field.js';
21
21
  export {
22
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
22
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
23
23
  FormSection,
24
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
24
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
25
25
  FormRow,
26
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
26
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
27
27
  FormGroup,
28
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
28
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
29
29
  FormActions, } from '../controls/form-layout.js';
30
30
  export type {
31
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
31
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
32
32
  FormSectionProps,
33
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
33
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
34
34
  FormSectionSlot,
35
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
35
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
36
36
  FormRowProps,
37
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
37
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
38
38
  FormRowSlot,
39
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
39
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
40
40
  FormGroupProps,
41
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
41
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
42
42
  FormActionsProps, } from '../controls/form-layout.js';
43
43
  export { useFormSubmit, isFieldErrorEnvelope } from './use-form-submit.js';
44
44
  export type { FormFieldErrors, UseFormSubmitOptions, UseFormSubmitReturn } from './use-form-submit.js';
@@ -51,13 +51,13 @@ export type { FormErrorSummaryProps } from './FormErrorSummary.js';
51
51
  export { useFormDraft, DEFAULT_AUTOSAVE_DEBOUNCE_MS } from './use-form-draft.js';
52
52
  export type { UseFormDraftOptions, UseFormDraftReturn } from './use-form-draft.js';
53
53
  export {
54
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
54
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
55
55
  useForm,
56
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
56
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
57
57
  schemaResolver, } from '@mantine/form';
58
58
  export type {
59
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
59
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
60
60
  UseFormReturnType,
61
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
61
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
62
62
  UseFormInput, } from '@mantine/form';
63
63
  //# sourceMappingURL=index.d.ts.map
@@ -8,17 +8,38 @@
8
8
  *
9
9
  * The zone's WIDTH is `--app-shell-navbar-offset`, so it tracks the rail collapse with no React
10
10
  * state and lands its trailing edge exactly on the sidebar|main seam. The negative
11
- * `margin-inline-start` cancels `AppShell.Header`'s own `px` inset so the zone starts at the
12
- * viewport edge and re-applies that inset as padding — which is what puts the brand lead on the
13
- * same x as the sidebar's nav ICON column below it. The arithmetic, now that the page gutter is
14
- * `SPACE.appShellInset`: the zone re-applies `--app-shell-padding` = 20, and a nav icon sits at
15
- * 10px of `.root` frame inset plus 10px of NavLink inset (`rowInsetX`) = 20. One vertical line
16
- * across the seam — a claim this comment used to make while the gutter was 13, and that the
17
- * 13 -> 20 move made true.
11
+ * `margin-inline-start` cancels `AppShell.Header`'s own `px` inset (the page gutter,
12
+ * `--app-shell-padding`) so the zone starts at the viewport edge, and the zone's OWN inline padding
13
+ * is the sidebar's nav-icon column — 10px of `.root` frame inset plus 10px of NavLink inset, i.e.
14
+ * `row-inset-x` twice — which is what puts the brand lead on the same x as the nav ICON column below
15
+ * it. That padding used to BE the page gutter (`--app-shell-padding`, 20, the same number by
16
+ * coincidence); the gutter is 16 now, and the two are different claims, so each is stated on its
17
+ * own. The breadcrumb lands on Main's content edge: the zone's trailing margin is the gutter minus
18
+ * the header row's flex gap (`app-header.module.css`'s `--basalt-header-gap`), so zone end + margin
19
+ * + gap = seam + gutter.
20
+ *
21
+ * `--basalt-shell-lead-inset` (default 0px, set by the consumer on `:root`) is the opt-in native
22
+ * title-bar contract: a macOS overlay title bar paints its traffic lights ON TOP of this zone, so a
23
+ * consumer publishes their span (~70px) and the zone (a) grows its inline-start padding by it and
24
+ * (b) is never narrower than inset + the collapse toggle, so the 48px rail does not clip the toggle
25
+ * under `overflow: hidden` (the toggle lands right of the lights; the breadcrumb after a widened
26
+ * rail zone shifts right by the same amount — accepted). Unset, every value below resolves to
27
+ * exactly what it was before the property existed: `max(offset, 0px + toggle)` is the offset
28
+ * (256 / 48 are both above the 28px toggle) and the added padding is 0px.
18
29
  */
19
30
  .zone {
20
- flex: 0 0 var(--app-shell-navbar-offset, 0rem);
21
- width: var(--app-shell-navbar-offset, 0rem);
31
+ /* The collapse toggle's box — `app-brand.tsx`'s `size={28}`, which is Mantine's rem-scaled
32
+ * `--ai-size-md` (1.75rem). Mantine defines that var on the ActionIcon, not on `:root`, so the
33
+ * zone restates the same arithmetic; `app-brand.module.css.test.ts` pins the two together. */
34
+ --basalt-shell-toggle-size: calc(1.75rem * var(--mantine-scale, 1));
35
+ /* The sidebar's nav-icon column: `.root` inset + NavLink inset, both `row-inset-x`. */
36
+ --basalt-nav-icon-x: calc(2 * var(--vx-space-row-inset-x));
37
+ --basalt-shell-zone-width: max(
38
+ var(--app-shell-navbar-offset, 0rem),
39
+ calc(var(--basalt-shell-lead-inset, 0px) + var(--basalt-shell-toggle-size))
40
+ );
41
+ flex: 0 0 var(--basalt-shell-zone-width);
42
+ width: var(--basalt-shell-zone-width);
22
43
  min-width: 0;
23
44
  display: flex;
24
45
  align-items: center;
@@ -26,7 +47,9 @@
26
47
  * like, and the rail's centred toggle centres against the whole row. */
27
48
  align-self: stretch;
28
49
  margin-inline-start: calc(-1 * var(--app-shell-padding, 0px));
29
- padding-inline: var(--app-shell-padding, 0px);
50
+ margin-inline-end: calc(var(--app-shell-padding, 0px) - var(--basalt-header-gap, 0px));
51
+ padding-inline: var(--basalt-nav-icon-x);
52
+ padding-inline-start: calc(var(--basalt-nav-icon-x) + var(--basalt-shell-lead-inset, 0px));
30
53
  overflow: hidden;
31
54
  /* Mantine's own AppShell timing, so the zone and the navbar under it move as one box. */
32
55
  transition-property: flex-basis, width;
@@ -101,11 +124,12 @@
101
124
  /*
102
125
  * The rail form, mirroring exactly what the sidebar's own brand row did when collapsed: the lead
103
126
  * (logo + name) hides and the toggle centres. The zone drops its inset so the toggle's centre lands
104
- * on the rail's icon column rather than 13px right of it.
127
+ * on the rail's icon column rather than 13px right of it. The lead inset is the one padding the
128
+ * rail keeps: the toggle sits right of the native title-bar controls, not centred under them.
105
129
  */
106
130
  @media (min-width: 52.5em) {
107
131
  .zone[data-collapsed] {
108
- padding-inline: 0;
132
+ padding-inline: var(--basalt-shell-lead-inset, 0px) 0;
109
133
  }
110
134
 
111
135
  .zone[data-collapsed] .brand {
@@ -17,9 +17,12 @@
17
17
  * `alt` — never a border in this module.
18
18
  */
19
19
  .bar {
20
+ /* Named so the leading zone (`app-brand.module.css`) can offset its trailing margin by exactly
21
+ * this gap and land the breadcrumb on Main's content edge. */
22
+ --basalt-header-gap: var(--mantine-spacing-sm);
20
23
  display: flex;
21
24
  align-items: center;
22
- gap: var(--mantine-spacing-sm);
25
+ gap: var(--basalt-header-gap);
23
26
  width: 100%;
24
27
  height: 100%;
25
28
  }
@@ -97,13 +97,13 @@
97
97
  * value rather than an offset, because Mantine owns the responsive switch (`shell/index.tsx`
98
98
  * hands `AppShell` the `appShellInset`/`appShellInsetMobile` pair) and the header, the band and
99
99
  * Main all have to land on the SAME number — re-deriving it here would fork it. It is an
100
- * ALIGNMENT constraint: 20 at `sm`+ puts the page's first column on the sidebar nav icon
101
- * column's x across the seam (`app-brand.module.css` states that arithmetic).
100
+ * ALIGNMENT constraint: the header's breadcrumb and globals land on the same edges as the
101
+ * content (`app-brand.module.css` states the arithmetic).
102
102
  *
103
- * Block is `stack-md` and is only breathing room under the band's single `--vx-divider` line —
104
- * nothing aligns to it, so it has no business tracking a gutter that grew for an alignment
105
- * reason. Holding it at 12 keeps the total chrome above the first card at ~97px (44 header + 40
106
- * band + 1 seam + 12) — DOWN from 100 — even though the inline gutter grew 13 -> 20.
103
+ * Block is breathing room under the band's single `--vx-divider` line — nothing aligns to it.
104
+ * `stack-md` (12) on a phone, one rung down (`stack-sm`, 8) from `sm` up where the inline gutter
105
+ * is 16: the page then sits 16 from the seam and 8 under the header, rather than the 20/12 it
106
+ * used to.
107
107
  */
108
108
  padding: var(--vx-space-stack-md) var(--app-shell-padding);
109
109
  /* Without this a wide flex/grid child (a bare table, a nowrap control row) sizes Main to ITSELF. */
@@ -122,11 +122,17 @@
122
122
  transition-property: margin;
123
123
  }
124
124
 
125
+ @media (min-width: 52.5em) {
126
+ .main {
127
+ padding-block: var(--vx-space-stack-sm);
128
+ }
129
+ }
130
+
125
131
  /* Installed PWA (C5 consolidation, seeded from argo's `styles/native.css`): clear the landscape
126
132
  * notch on the side Main touches. `max()` is a FLOOR over the INLINE value of `.main`'s `padding`
127
133
  * shorthand above — same mechanism as `app-sidebar.module.css`'s left counterpart, and it still
128
134
  * floors correctly now that the shorthand is two axes and the inline one is responsive: this rule
129
- * reads the same `--app-shell-padding`, so the floor is against whichever of 20/8 is live, and on
135
+ * reads the same `--app-shell-padding`, so the floor is against whichever of 16/8 is live, and on
130
136
  * the phone half (8) it is doing MORE work than before, not less. It overrides only
131
137
  * `padding-right`; the block padding keeps coming from the shorthand. The bottom inset already
132
138
  * rides `margin-bottom` above (`env(safe-area-inset-bottom)`); the PWA's top inset needs no rule here
@@ -212,6 +212,11 @@
212
212
  .footer {
213
213
  flex-shrink: 0;
214
214
  padding-top: var(--vx-space-sidebar-region-gap);
215
+ /* The bottom inset equals the column's side inset (`.root`'s `row-inset-x`), so the last row —
216
+ * the settings link, the account row or a bottom progress block — does not sit FLUSH on the
217
+ * navbar's bottom edge against a 10px side gap. Rail and expanded alike: this is the footer's own
218
+ * edge, not a rail rule, so a collapsed sidebar cannot double it. */
219
+ padding-bottom: var(--vx-space-row-inset-x);
215
220
  }
216
221
 
217
222
  .footer > * + * {
@@ -697,6 +702,17 @@
697
702
  display: none;
698
703
  }
699
704
 
705
+ /* The FIRST section's band keeps its label gap in the rail. Expanded, that band's
706
+ * `margin-bottom` is what seats the first nav row `section-label-gap` below the navbar top (an
707
+ * unlabelled band is zero-height); zeroing it above left the rail's first icon flush at 0, a few
708
+ * px higher than the same row expanded. Only the first band: every later band's zeroed margin is
709
+ * what keeps the gap BETWEEN sections at `section-gap` in the rail, where the label it separated
710
+ * from the rows is gone. (A labelled first section expands to label + gap, which the rail cannot
711
+ * match — its label is `display: none`; the equal-offset contract is the unlabelled case.) */
712
+ .root[data-collapsed] .nav > div:first-child > .sectionBand {
713
+ margin-bottom: var(--vx-space-sidebar-section-label-gap);
714
+ }
715
+
700
716
  /* Collapse every nav row to its icon. Targets `.navItem` — the wrapper Box present on EVERY render
701
717
  * path — so it covers the shell's fallback NavLink AND a consumer's `SidebarItem.Anchor` (e.g. a router
702
718
  * <Link>), both of which render a Mantine NavLink inside. Keying off `.link` alone missed consumer
@@ -152,6 +152,13 @@ export type BasaltShellProps = BasaltProps & {
152
152
  * inside it: `PageBarProvider` owns the header portal and the single-kebab claim, `AsideProvider`
153
153
  * owns the aside portal, the region CLAIM and the claiming page's fold state — which `ShellFrame`
154
154
  * has to READ to size `AppShell.Aside`, so it cannot be the component that provides it.
155
+ *
156
+ * **Native title bar (opt-in CSS contract).** A desktop host with a macOS overlay title bar paints
157
+ * its traffic lights ON TOP of the header's leading zone. Set `--basalt-shell-lead-inset` on
158
+ * `:root` to their span (e.g. `html { --basalt-shell-lead-inset: 70px }`; default `0px`, which
159
+ * changes nothing): the zone's inline-start padding grows by it, and the zone is never narrower than
160
+ * the inset plus the collapse toggle, so the 48px rail pushes the toggle to the right of the lights
161
+ * instead of clipping it. The breadcrumb after a widened rail zone shifts right by the same amount.
155
162
  */
156
163
  export declare function BasaltShell(props: BasaltShellProps): import("react").JSX.Element;
157
164
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
@@ -541,13 +541,13 @@ declare const SPACE_STEP_BASE: {
541
541
  * `tokens/index.ts` for why), because it is the single most visible spacing number the framework
542
542
  * ships and a consumer retuning its identity has to be able to reach it.
543
543
  *
544
- * 20, up from the 13 (`SPACE_SCALE.sm`) the main column used to borrow. The sidebar's nav ICON
545
- * column already sits at x=20 — 10px of `.root` frame inset plus 10px of NavLink inset
546
- * (`rowInsetX`) — and the brand row claims to align with it while sitting at 13. 20 makes that
547
- * claim true across the seam: brand mark, nav icons and the page's first column all start on one
548
- * vertical line, and the content gets a seam-side gutter that reads deliberate instead of
549
- * incidental. */
550
- readonly appShellInset: 20;
544
+ * 16, down from 20 (and from the 13 `SPACE_SCALE.sm` the main column borrowed before that): at 20
545
+ * the content read as pushed away from the seam. 16 sits on the 4px grid. It is NOT the sidebar's
546
+ * nav-icon column any more (x=20: 10px of `.root` frame inset plus 10px of NavLink inset,
547
+ * `rowInsetX` twice) — the header's brand zone aligns to that column on its own
548
+ * (`shell/app-brand.module.css`), so the page gutter is free to be a gutter. The header's
549
+ * breadcrumb, the page-bar band and Main all land on this one number. */
550
+ readonly appShellInset: 16;
551
551
  /** The page gutter BELOW `sm` — the phone half of `appShellInset` above. A separate entry rather
552
552
  * than one responsive value for the same reason `appShellNavbarWidth` is one: there is no sidebar
553
553
  * seam to align to on a phone, so the number is answering a different question (how much of a
@@ -1 +1 @@
1
- {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/tokens/palette.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;CAgCL,CAAA;AAEV;;;;GAIG;AACH,eAAO,MAAM,CAAC,GAAI,KAAK,SAAS,MAAM,EAAE,EAAE,cAAS,EAAE,aAAQ,KAAG,SAG9D,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM;;;;;;;;;IASjB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;;;;;;;;;CAaK,CAAA;AAEV;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAOD;;;8DAG8D;AAC9D,eAAO,MAAM,kBAAkB;;;CAA+B,CAAA;AAE9D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAmBxD;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;IACjB,oFAAoF;;IAEpF;2BACuB;;CAEf,CAAA;AAEV;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;IACtB;gCAC4B;;IAE5B,0FAA0F;;IAE1F,4FAA4F;;IAE5F,4EAA4E;;IAE5E,4EAA4E;;IAE5E,4EAA4E;;IAE5E;uFACmF;;CAE3E,CAAA;AAWV;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,kBAAkB;IACtB,oEAAoE;;IAEpE,kEAAkE;;IAElE;yFACqF;;IAErF,kGAAkG;;IAElG;;qEAEiE;;IAEjE,gEAAgE;;IAEhE,oEAAoE;;IAEpE,gFAAgF;;IAEhF;;;mGAG+F;;IAE/F;;;mGAG+F;;IAE/F;2EACuE;;IAEvE;;;;;;;;;oFASgF;;CAExE,CAAA;AAEV;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,gBAAgB;;;;;;CAMZ,CAAA;AAEV;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,eAAe;IACnB,0CAA0C;;IAW1C;;;iDAG6C;;IAE7C;;;;;;;;yDAQqD;;IAIrD,4CAA4C;;IAE5C,4CAA4C;;IAE5C,uCAAuC;;IAEvC,yCAAyC;;IAEzC,iDAAiD;;IAEjD,mDAAmD;;IAEnD,4DAA4D;;IAE5D,iCAAiC;;IAEjC,mCAAmC;;IAEnC,6EAA6E;;IAE7E,gCAAgC;;IAEhC,8CAA8C;;IAE9C,gDAAgD;;IAEhD,uCAAuC;;IAEvC,0CAA0C;;IAE1C,+CAA+C;;IAE/C,uCAAuC;;IAEvC,0CAA0C;;IAE1C,mCAAmC;;IAEnC,uCAAuC;;IAEvC,0CAA0C;;IAE1C;iEAC6D;;IAE7D,kGAAkG;;IAElG,kDAAkD;;IAElD,+EAA+E;;IAI/E;;;;;;;qEAOiE;;IAEjE;;;;mEAI+D;;IAE/D,wEAAwE;;IAExE,wDAAwD;;IAExD,uDAAuD;;IAEvD,iCAAiC;;IAEjC,qCAAqC;;IAErC,yDAAyD;;IAEzD,0DAA0D;;IAE1D,6CAA6C;;IAI7C,sCAAsC;;IAEtC,+BAA+B;;IAE/B,sEAAsE;;IAEtE;8EAC0E;;IAE1E,8CAA8C;;IAE9C,6BAA6B;;IAE7B,0FAA0F;;IAI1F,4BAA4B;;IAE5B,8BAA8B;;IAE9B,oCAAoC;;IAIpC,sDAAsD;;IAEtD,iCAAiC;;IAEjC,kDAAkD;;IAElD,gDAAgD;;IAIhD,yBAAyB;;IAEzB,iCAAiC;;IAEjC,mCAAmC;;IAEnC,2BAA2B;;IAI3B,oDAAoD;;IAEpD,+CAA+C;;IAE/C,8CAA8C;;IAI9C,mCAAmC;;IAEnC;;yGAEqG;;IAIrG,4BAA4B;;IAE5B,gDAAgD;;IAIhD,6CAA6C;;IAI7C,oCAAoC;;IAEpC;;;+EAG2E;;IAE3E,+BAA+B;;IAE/B,sCAAsC;;IAEtC,kCAAkC;;IAElC,sEAAsE;;IAEtE;;gFAE4E;;IAE5E,mDAAmD;;IAEnD,sDAAsD;;IAEtD,oDAAoD;;IAEpD,0CAA0C;;IAE1C,mEAAmE;;IAYnE,mEAAmE;;IAEnE,4DAA4D;;IAI5D;;;;uCAImC;IACnC;;;;;;;;;6DASyD;;IAEzD;;;;;;;;;sBASkB;;IAElB;;+EAE2E;;IAE3E;;;;;;;oGAOgG;;IAEhG;;6FAEyF;;IAEzF;;;;;;;;;;;sBAWkB;;IAElB;;;;;;;8FAO0F;;IAE1F;;;;;;mDAM+C;;IAI/C,+BAA+B;;IAE/B;;oFAEgF;;IAEhF;iGAC6F;;IAE7F;6FACyF;;IAEzF,0DAA0D;;IAE1D;mFAC+E;;IAE/E;qDACiD;;IAOjD,uDAAuD;;IAEvD,qDAAqD;;IAErD,yDAAyD;;IAEzD;2GACuG;;IAEvG,2DAA2D;;IAE3D,uDAAuD;;IAEvD;;+FAE2F;;IAI3F;;6DAEyD;;IAKzD,qGAAqG;;IAErG,wFAAwF;;IAExF,oDAAoD;;IAEpD,6DAA6D;;IAE7D,+DAA+D;;IAE/D,qEAAqE;;IAErE,uEAAuE;;IAEvE,yEAAyE;;IAEzE,kGAAkG;;IAElG,wGAAwG;;IAExG,0GAA0G;;IAE1G,oEAAoE;;IAEpE,6DAA6D;;IAE7D,+DAA+D;;IAoB/D;;;2FAGuF;;IAEvF;mGAC+F;;IAE/F;;;sDAGkD;;IAIlD;;;;;;;;gBAQY;;IAEZ,gDAAgD;;IAEhD,+CAA+C;;IAE/C,0CAA0C;;IAE1C,kFAAkF;;IAElF;gFAC4E;;IAE5E;;;;;sFAKkF;;IAElF;iGAC6F;;CAErF,CAAA;AAEV;;;;GAIG;AACH,eAAO,MAAM,WAAW;IACtB,oEAAoE;;IAEpE;;sEAEkE;;IAElE;;;;;;;;;iDAS6C;;CAErC,CAAA;AAEV;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE;SAAG,CAAC,IAAI,MAAM,OAAO,kBAAkB,GAAG,MAAM;KAAE,CAAA;IAC3D,KAAK,EAAE;SAAG,CAAC,IAAI,MAAM,OAAO,gBAAgB,GAAG,MAAM;KAAE,CAAA;IACvD;;;;;sGAKkG;IAClG,IAAI,EAAE;SAAG,CAAC,IAAI,MAAM,OAAO,eAAe,GAAG,MAAM;KAAE,GAAG;QACtD,qBAAqB,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD;kEAC8D;IAC9D,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAInF;AAiCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6GG;AACH;;;;wEAIwE;AACxE,eAAO,MAAM,mBAAmB;;;CAA+B,CAAA;AAE/D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA+DxD;AAED;;;;;oFAKoF;AACpF,eAAO,MAAM,oBAAoB,aAAmB,CAAA;AAEpD;;2DAE2D;AAC3D,eAAO,MAAM,KAAK;;;;;;;;;;;;;CAA+B,CAAA;AAEjD;;+BAE+B;AAC/B,eAAO,MAAM,WAAW;;;;;;CAA6B,CAAA;AAErD;;;;iCAIiC;AACjC,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAhRI,MAAM;CAgRkB,CAAA;AAEnD;8EAC8E;AAC9E,eAAO,MAAM,eAAe,QAAqC,CAAA;AA0BjE,iBAAS,wBAAwB,CAAC,MAAM,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyLrD;AAaD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,YAAoC,GAAG,WAAW,CAe1F;AAED,oGAAoG;AACpG,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAMrE;+CAC+C;AAC/C,eAAO,MAAM,QAAQ;;;;CAA+B,CAAA;AAEpD;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;;CAA6B,CAAA;AAEhD;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAA8B,CAAA;AAElD,0FAA0F;AAC1F,eAAO,MAAM,GAAG;;;;;CAA0B,CAAA;AAE1C,mFAAmF;AACnF,eAAO,MAAM,MAAM;;;;;;CAA6B,CAAA;AAEhD;+BAC+B;AAC/B,eAAO,MAAM,IAAI;;;;;;;;;;;;;CAA2B,CAAA;AAE5C;+CAC+C;AAC/C,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;CAA8B,CAAA"}
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/tokens/palette.ts"],"names":[],"mappings":"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"}
@@ -453,13 +453,13 @@ const SPACE_STEP_BASE = {
453
453
  * `tokens/index.ts` for why), because it is the single most visible spacing number the framework
454
454
  * ships and a consumer retuning its identity has to be able to reach it.
455
455
  *
456
- * 20, up from the 13 (`SPACE_SCALE.sm`) the main column used to borrow. The sidebar's nav ICON
457
- * column already sits at x=20 — 10px of `.root` frame inset plus 10px of NavLink inset
458
- * (`rowInsetX`) — and the brand row claims to align with it while sitting at 13. 20 makes that
459
- * claim true across the seam: brand mark, nav icons and the page's first column all start on one
460
- * vertical line, and the content gets a seam-side gutter that reads deliberate instead of
461
- * incidental. */
462
- appShellInset: 20,
456
+ * 16, down from 20 (and from the 13 `SPACE_SCALE.sm` the main column borrowed before that): at 20
457
+ * the content read as pushed away from the seam. 16 sits on the 4px grid. It is NOT the sidebar's
458
+ * nav-icon column any more (x=20: 10px of `.root` frame inset plus 10px of NavLink inset,
459
+ * `rowInsetX` twice) — the header's brand zone aligns to that column on its own
460
+ * (`shell/app-brand.module.css`), so the page gutter is free to be a gutter. The header's
461
+ * breadcrumb, the page-bar band and Main all land on this one number. */
462
+ appShellInset: 16,
463
463
  /** The page gutter BELOW `sm` — the phone half of `appShellInset` above. A separate entry rather
464
464
  * than one responsive value for the same reason `appShellNavbarWidth` is one: there is no sidebar
465
465
  * seam to align to on a phone, so the number is answering a different question (how much of a
package/dist/tokens.css CHANGED
@@ -95,7 +95,7 @@
95
95
  --vx-space-sidebar-child-list-indent: 15px;
96
96
  --vx-space-sidebar-child-row-inset-y: 4px;
97
97
  --vx-space-sidebar-child-row-indent: 12px;
98
- --vx-space-app-shell-inset: 20px;
98
+ --vx-space-app-shell-inset: 16px;
99
99
  --vx-space-app-shell-inset-mobile: 8px;
100
100
  --vx-space-app-shell-header-lead-min: 96px;
101
101
  --vx-space-mobile-nav-tab-gap: 3px;
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # basalt-ui v1.37.1
1
+ # basalt-ui v1.38.1
2
2
  # Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets
3
3
  #
4
4
  # basalt-ui is an opinionated framework for Mantine-based React apps.
@@ -19,7 +19,7 @@
19
19
  # ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
20
20
 
21
21
  Package: basalt-ui
22
- Version: 1.37.1
22
+ Version: 1.38.1
23
23
 
24
24
  ## basalt-ui
25
25
  Import: import { ... } from 'basalt-ui'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basalt-ui",
3
- "version": "1.37.1",
3
+ "version": "1.38.1",
4
4
  "description": "Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets",
5
5
  "keywords": [
6
6
  "charts",
@@ -2,7 +2,7 @@
2
2
  * ./controls — the form layout primitives: `FormSection`, `FormRow`, `FormGroup`, `FormActions`.
3
3
  * Mantine-coupled. They need no `@mantine/form` (layout only), which is why they live here and not
4
4
  * in `./forms`, whose barrel value-imports it: importing a row from there made a consumer install a
5
- * peer it never used. `./forms` re-exports them as deprecated aliases until 1.38.0.
5
+ * peer it never used. `./forms` re-exports them as deprecated aliases until 1.39.0.
6
6
  *
7
7
  * The gap they close (audit B #5 / §4): `./forms` shipped no layout at all, so the only row
8
8
  * primitive in the package was `SettingsRow` over in `./dashboard` — which is the SETTINGS-page
@@ -56,7 +56,7 @@ export { SliderControl, type SliderControlProps } from './slider-control'
56
56
 
57
57
  // ── The form layout (moved from ./forms in 1.36.0) ────────────────────────────────────────────
58
58
  // Layout needs no `@mantine/form`, and `./forms`' barrel value-imports it — so a consumer rendering
59
- // a `FormRow` had to install a peer it never used. `./forms` re-exports these until 1.38.0.
59
+ // a `FormRow` had to install a peer it never used. `./forms` re-exports these until 1.39.0.
60
60
  export {
61
61
  FormSection,
62
62
  FormRow,
@@ -10,7 +10,7 @@
10
10
  * (`useFormSubmit` + `FormStateProvider`), the list field (`useFieldArray`) and the draft
11
11
  * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) moved to
12
12
  * `basalt-ui/controls` in 1.36.0 — it needs no `@mantine/form` — and stays here as deprecated
13
- * aliases until 1.38.0, as do the `useForm`/`schemaResolver` re-exports (import from
13
+ * aliases until 1.39.0, as do the `useForm`/`schemaResolver` re-exports (import from
14
14
  * `@mantine/form`).
15
15
  *
16
16
  * Optional peer: @mantine/form ^9.3.0 — install with: bun add @mantine/form
@@ -24,29 +24,29 @@ export type { UseBasaltFormOptions } from './create-form'
24
24
  // Two calls, never one object: `key` inside a spread is a React 19 warning. See field.ts.
25
25
  export { inputProps, fieldKey } from './field'
26
26
 
27
- // ── layout — moved to ./controls (1.36.0), deprecated aliases until 1.38.0 ─────
27
+ // ── layout — moved to ./controls (1.36.0), deprecated aliases until 1.39.0 ─────
28
28
  export {
29
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
29
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
30
30
  FormSection,
31
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
31
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
32
32
  FormRow,
33
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
33
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
34
34
  FormGroup,
35
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
35
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
36
36
  FormActions,
37
37
  } from '../controls/form-layout'
38
38
  export type {
39
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
39
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
40
40
  FormSectionProps,
41
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
41
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
42
42
  FormSectionSlot,
43
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
43
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
44
44
  FormRowProps,
45
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
45
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
46
46
  FormRowSlot,
47
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
47
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
48
48
  FormGroupProps,
49
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.38.0. */
49
+ /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
50
50
  FormActionsProps,
51
51
  } from '../controls/form-layout'
52
52
 
@@ -70,14 +70,14 @@ export type { UseFormDraftOptions, UseFormDraftReturn } from './use-form-draft'
70
70
 
71
71
  // ── @mantine/form re-exports — deprecated, zero consumers import them from here ──
72
72
  export {
73
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
73
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
74
74
  useForm,
75
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
75
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
76
76
  schemaResolver,
77
77
  } from '@mantine/form'
78
78
  export type {
79
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
79
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
80
80
  UseFormReturnType,
81
- /** @deprecated Import from '@mantine/form' — removed in 1.38.0. */
81
+ /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
82
82
  UseFormInput,
83
83
  } from '@mantine/form'
@@ -8,17 +8,38 @@
8
8
  *
9
9
  * The zone's WIDTH is `--app-shell-navbar-offset`, so it tracks the rail collapse with no React
10
10
  * state and lands its trailing edge exactly on the sidebar|main seam. The negative
11
- * `margin-inline-start` cancels `AppShell.Header`'s own `px` inset so the zone starts at the
12
- * viewport edge and re-applies that inset as padding — which is what puts the brand lead on the
13
- * same x as the sidebar's nav ICON column below it. The arithmetic, now that the page gutter is
14
- * `SPACE.appShellInset`: the zone re-applies `--app-shell-padding` = 20, and a nav icon sits at
15
- * 10px of `.root` frame inset plus 10px of NavLink inset (`rowInsetX`) = 20. One vertical line
16
- * across the seam — a claim this comment used to make while the gutter was 13, and that the
17
- * 13 -> 20 move made true.
11
+ * `margin-inline-start` cancels `AppShell.Header`'s own `px` inset (the page gutter,
12
+ * `--app-shell-padding`) so the zone starts at the viewport edge, and the zone's OWN inline padding
13
+ * is the sidebar's nav-icon column — 10px of `.root` frame inset plus 10px of NavLink inset, i.e.
14
+ * `row-inset-x` twice — which is what puts the brand lead on the same x as the nav ICON column below
15
+ * it. That padding used to BE the page gutter (`--app-shell-padding`, 20, the same number by
16
+ * coincidence); the gutter is 16 now, and the two are different claims, so each is stated on its
17
+ * own. The breadcrumb lands on Main's content edge: the zone's trailing margin is the gutter minus
18
+ * the header row's flex gap (`app-header.module.css`'s `--basalt-header-gap`), so zone end + margin
19
+ * + gap = seam + gutter.
20
+ *
21
+ * `--basalt-shell-lead-inset` (default 0px, set by the consumer on `:root`) is the opt-in native
22
+ * title-bar contract: a macOS overlay title bar paints its traffic lights ON TOP of this zone, so a
23
+ * consumer publishes their span (~70px) and the zone (a) grows its inline-start padding by it and
24
+ * (b) is never narrower than inset + the collapse toggle, so the 48px rail does not clip the toggle
25
+ * under `overflow: hidden` (the toggle lands right of the lights; the breadcrumb after a widened
26
+ * rail zone shifts right by the same amount — accepted). Unset, every value below resolves to
27
+ * exactly what it was before the property existed: `max(offset, 0px + toggle)` is the offset
28
+ * (256 / 48 are both above the 28px toggle) and the added padding is 0px.
18
29
  */
19
30
  .zone {
20
- flex: 0 0 var(--app-shell-navbar-offset, 0rem);
21
- width: var(--app-shell-navbar-offset, 0rem);
31
+ /* The collapse toggle's box — `app-brand.tsx`'s `size={28}`, which is Mantine's rem-scaled
32
+ * `--ai-size-md` (1.75rem). Mantine defines that var on the ActionIcon, not on `:root`, so the
33
+ * zone restates the same arithmetic; `app-brand.module.css.test.ts` pins the two together. */
34
+ --basalt-shell-toggle-size: calc(1.75rem * var(--mantine-scale, 1));
35
+ /* The sidebar's nav-icon column: `.root` inset + NavLink inset, both `row-inset-x`. */
36
+ --basalt-nav-icon-x: calc(2 * var(--vx-space-row-inset-x));
37
+ --basalt-shell-zone-width: max(
38
+ var(--app-shell-navbar-offset, 0rem),
39
+ calc(var(--basalt-shell-lead-inset, 0px) + var(--basalt-shell-toggle-size))
40
+ );
41
+ flex: 0 0 var(--basalt-shell-zone-width);
42
+ width: var(--basalt-shell-zone-width);
22
43
  min-width: 0;
23
44
  display: flex;
24
45
  align-items: center;
@@ -26,7 +47,9 @@
26
47
  * like, and the rail's centred toggle centres against the whole row. */
27
48
  align-self: stretch;
28
49
  margin-inline-start: calc(-1 * var(--app-shell-padding, 0px));
29
- padding-inline: var(--app-shell-padding, 0px);
50
+ margin-inline-end: calc(var(--app-shell-padding, 0px) - var(--basalt-header-gap, 0px));
51
+ padding-inline: var(--basalt-nav-icon-x);
52
+ padding-inline-start: calc(var(--basalt-nav-icon-x) + var(--basalt-shell-lead-inset, 0px));
30
53
  overflow: hidden;
31
54
  /* Mantine's own AppShell timing, so the zone and the navbar under it move as one box. */
32
55
  transition-property: flex-basis, width;
@@ -101,11 +124,12 @@
101
124
  /*
102
125
  * The rail form, mirroring exactly what the sidebar's own brand row did when collapsed: the lead
103
126
  * (logo + name) hides and the toggle centres. The zone drops its inset so the toggle's centre lands
104
- * on the rail's icon column rather than 13px right of it.
127
+ * on the rail's icon column rather than 13px right of it. The lead inset is the one padding the
128
+ * rail keeps: the toggle sits right of the native title-bar controls, not centred under them.
105
129
  */
106
130
  @media (min-width: 52.5em) {
107
131
  .zone[data-collapsed] {
108
- padding-inline: 0;
132
+ padding-inline: var(--basalt-shell-lead-inset, 0px) 0;
109
133
  }
110
134
 
111
135
  .zone[data-collapsed] .brand {
@@ -17,9 +17,12 @@
17
17
  * `alt` — never a border in this module.
18
18
  */
19
19
  .bar {
20
+ /* Named so the leading zone (`app-brand.module.css`) can offset its trailing margin by exactly
21
+ * this gap and land the breadcrumb on Main's content edge. */
22
+ --basalt-header-gap: var(--mantine-spacing-sm);
20
23
  display: flex;
21
24
  align-items: center;
22
- gap: var(--mantine-spacing-sm);
25
+ gap: var(--basalt-header-gap);
23
26
  width: 100%;
24
27
  height: 100%;
25
28
  }
@@ -97,13 +97,13 @@
97
97
  * value rather than an offset, because Mantine owns the responsive switch (`shell/index.tsx`
98
98
  * hands `AppShell` the `appShellInset`/`appShellInsetMobile` pair) and the header, the band and
99
99
  * Main all have to land on the SAME number — re-deriving it here would fork it. It is an
100
- * ALIGNMENT constraint: 20 at `sm`+ puts the page's first column on the sidebar nav icon
101
- * column's x across the seam (`app-brand.module.css` states that arithmetic).
100
+ * ALIGNMENT constraint: the header's breadcrumb and globals land on the same edges as the
101
+ * content (`app-brand.module.css` states the arithmetic).
102
102
  *
103
- * Block is `stack-md` and is only breathing room under the band's single `--vx-divider` line —
104
- * nothing aligns to it, so it has no business tracking a gutter that grew for an alignment
105
- * reason. Holding it at 12 keeps the total chrome above the first card at ~97px (44 header + 40
106
- * band + 1 seam + 12) — DOWN from 100 — even though the inline gutter grew 13 -> 20.
103
+ * Block is breathing room under the band's single `--vx-divider` line — nothing aligns to it.
104
+ * `stack-md` (12) on a phone, one rung down (`stack-sm`, 8) from `sm` up where the inline gutter
105
+ * is 16: the page then sits 16 from the seam and 8 under the header, rather than the 20/12 it
106
+ * used to.
107
107
  */
108
108
  padding: var(--vx-space-stack-md) var(--app-shell-padding);
109
109
  /* Without this a wide flex/grid child (a bare table, a nowrap control row) sizes Main to ITSELF. */
@@ -122,11 +122,17 @@
122
122
  transition-property: margin;
123
123
  }
124
124
 
125
+ @media (min-width: 52.5em) {
126
+ .main {
127
+ padding-block: var(--vx-space-stack-sm);
128
+ }
129
+ }
130
+
125
131
  /* Installed PWA (C5 consolidation, seeded from argo's `styles/native.css`): clear the landscape
126
132
  * notch on the side Main touches. `max()` is a FLOOR over the INLINE value of `.main`'s `padding`
127
133
  * shorthand above — same mechanism as `app-sidebar.module.css`'s left counterpart, and it still
128
134
  * floors correctly now that the shorthand is two axes and the inline one is responsive: this rule
129
- * reads the same `--app-shell-padding`, so the floor is against whichever of 20/8 is live, and on
135
+ * reads the same `--app-shell-padding`, so the floor is against whichever of 16/8 is live, and on
130
136
  * the phone half (8) it is doing MORE work than before, not less. It overrides only
131
137
  * `padding-right`; the block padding keeps coming from the shorthand. The bottom inset already
132
138
  * rides `margin-bottom` above (`env(safe-area-inset-bottom)`); the PWA's top inset needs no rule here
@@ -212,6 +212,11 @@
212
212
  .footer {
213
213
  flex-shrink: 0;
214
214
  padding-top: var(--vx-space-sidebar-region-gap);
215
+ /* The bottom inset equals the column's side inset (`.root`'s `row-inset-x`), so the last row —
216
+ * the settings link, the account row or a bottom progress block — does not sit FLUSH on the
217
+ * navbar's bottom edge against a 10px side gap. Rail and expanded alike: this is the footer's own
218
+ * edge, not a rail rule, so a collapsed sidebar cannot double it. */
219
+ padding-bottom: var(--vx-space-row-inset-x);
215
220
  }
216
221
 
217
222
  .footer > * + * {
@@ -697,6 +702,17 @@
697
702
  display: none;
698
703
  }
699
704
 
705
+ /* The FIRST section's band keeps its label gap in the rail. Expanded, that band's
706
+ * `margin-bottom` is what seats the first nav row `section-label-gap` below the navbar top (an
707
+ * unlabelled band is zero-height); zeroing it above left the rail's first icon flush at 0, a few
708
+ * px higher than the same row expanded. Only the first band: every later band's zeroed margin is
709
+ * what keeps the gap BETWEEN sections at `section-gap` in the rail, where the label it separated
710
+ * from the rows is gone. (A labelled first section expands to label + gap, which the rail cannot
711
+ * match — its label is `display: none`; the equal-offset contract is the unlabelled case.) */
712
+ .root[data-collapsed] .nav > div:first-child > .sectionBand {
713
+ margin-bottom: var(--vx-space-sidebar-section-label-gap);
714
+ }
715
+
700
716
  /* Collapse every nav row to its icon. Targets `.navItem` — the wrapper Box present on EVERY render
701
717
  * path — so it covers the shell's fallback NavLink AND a consumer's `SidebarItem.Anchor` (e.g. a router
702
718
  * <Link>), both of which render a Mantine NavLink inside. Keying off `.link` alone missed consumer
@@ -319,6 +319,13 @@ function collapseStore(key: string): CollapseStore {
319
319
  * inside it: `PageBarProvider` owns the header portal and the single-kebab claim, `AsideProvider`
320
320
  * owns the aside portal, the region CLAIM and the claiming page's fold state — which `ShellFrame`
321
321
  * has to READ to size `AppShell.Aside`, so it cannot be the component that provides it.
322
+ *
323
+ * **Native title bar (opt-in CSS contract).** A desktop host with a macOS overlay title bar paints
324
+ * its traffic lights ON TOP of the header's leading zone. Set `--basalt-shell-lead-inset` on
325
+ * `:root` to their span (e.g. `html { --basalt-shell-lead-inset: 70px }`; default `0px`, which
326
+ * changes nothing): the zone's inline-start padding grows by it, and the zone is never narrower than
327
+ * the inset plus the collapse toggle, so the 48px rail pushes the toggle to the right of the lights
328
+ * instead of clipping it. The breadcrumb after a widened rail zone shifts right by the same amount.
322
329
  */
323
330
  export function BasaltShell(props: BasaltShellProps) {
324
331
  assertRequiredProps('BasaltShell', props, ['brand', 'sections'])
@@ -650,13 +650,13 @@ const SPACE_STEP_BASE = {
650
650
  * `tokens/index.ts` for why), because it is the single most visible spacing number the framework
651
651
  * ships and a consumer retuning its identity has to be able to reach it.
652
652
  *
653
- * 20, up from the 13 (`SPACE_SCALE.sm`) the main column used to borrow. The sidebar's nav ICON
654
- * column already sits at x=20 — 10px of `.root` frame inset plus 10px of NavLink inset
655
- * (`rowInsetX`) — and the brand row claims to align with it while sitting at 13. 20 makes that
656
- * claim true across the seam: brand mark, nav icons and the page's first column all start on one
657
- * vertical line, and the content gets a seam-side gutter that reads deliberate instead of
658
- * incidental. */
659
- appShellInset: 20,
653
+ * 16, down from 20 (and from the 13 `SPACE_SCALE.sm` the main column borrowed before that): at 20
654
+ * the content read as pushed away from the seam. 16 sits on the 4px grid. It is NOT the sidebar's
655
+ * nav-icon column any more (x=20: 10px of `.root` frame inset plus 10px of NavLink inset,
656
+ * `rowInsetX` twice) — the header's brand zone aligns to that column on its own
657
+ * (`shell/app-brand.module.css`), so the page gutter is free to be a gutter. The header's
658
+ * breadcrumb, the page-bar band and Main all land on this one number. */
659
+ appShellInset: 16,
660
660
  /** The page gutter BELOW `sm` — the phone half of `appShellInset` above. A separate entry rather
661
661
  * than one responsive value for the same reason `appShellNavbarWidth` is one: there is no sidebar
662
662
  * seam to align to on a phone, so the number is answering a different question (how much of a