cursedbelt 5.67.0 → 5.68.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 (38) hide show
  1. package/dist/react/canvas-hud/CanvasToolbar.d.ts +67 -0
  2. package/dist/react/canvas-hud/CanvasToolbar.d.ts.map +1 -0
  3. package/dist/react/canvas-hud/CanvasToolbar.js +84 -0
  4. package/dist/react/canvas-hud/CanvasToolbar.js.map +1 -0
  5. package/dist/react/canvas-hud/index.d.ts +2 -0
  6. package/dist/react/canvas-hud/index.d.ts.map +1 -1
  7. package/dist/react/canvas-hud/index.js +1 -0
  8. package/dist/react/canvas-hud/index.js.map +1 -1
  9. package/dist/react/components/EntityCard.d.ts +35 -0
  10. package/dist/react/components/EntityCard.d.ts.map +1 -0
  11. package/dist/react/components/EntityCard.js +18 -0
  12. package/dist/react/components/EntityCard.js.map +1 -0
  13. package/dist/react/index.d.ts +1 -0
  14. package/dist/react/index.d.ts.map +1 -1
  15. package/dist/react/index.js +1 -0
  16. package/dist/react/index.js.map +1 -1
  17. package/dist/styles-areas/canvas-hud.css +6 -4
  18. package/dist/styles-areas/core.css +8 -8
  19. package/dist/styles-areas/fields.css +2 -2
  20. package/dist/styles-areas/filter-rail.css +5 -5
  21. package/dist/styles-areas/nav.css +6 -6
  22. package/dist/styles-areas/notifications.css +3 -3
  23. package/dist/styles-areas/place-bar.css +2 -2
  24. package/dist/styles-utilities.css +33 -0
  25. package/package.json +1 -1
  26. package/scripts/styleAreas.ts +1 -0
  27. package/src/react/canvas-hud/CanvasToolbar.tsx +177 -0
  28. package/src/react/canvas-hud/index.ts +2 -0
  29. package/src/react/components/EntityCard.tsx +76 -0
  30. package/src/react/index.ts +1 -0
  31. package/src/styles-areas/canvas-hud.css +6 -4
  32. package/src/styles-areas/core.css +8 -8
  33. package/src/styles-areas/fields.css +2 -2
  34. package/src/styles-areas/filter-rail.css +5 -5
  35. package/src/styles-areas/nav.css +6 -6
  36. package/src/styles-areas/notifications.css +3 -3
  37. package/src/styles-areas/place-bar.css +2 -2
  38. package/src/styles-utilities.css +33 -0
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 33 candidate(s).
21
+ * 32 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -26,8 +26,8 @@
26
26
  */
27
27
  @source inline("-right-0.5 -top-0.5 [&::-webkit-scrollbar]:hidden [scrollbar-width:none] bg-accent/15");
28
28
  @source inline("group-focus-within:opacity-100 group-focus-within:pointer-events-auto");
29
- @source inline("group-hover:pointer-events-auto hover:bg-muted/80 leading-4 list-none min-w-4 ml-1.5 ml-2 pb");
30
- @source inline("pb-0.5 pointer-coarse:basis-full pointer-coarse:bg-transparent pointer-coarse:justify-end");
29
+ @source inline("group-hover:pointer-events-auto hover:bg-muted/80 list-none min-w-4 ml-1.5 ml-2 pb pb-0.5");
30
+ @source inline("pointer-coarse:basis-full pointer-coarse:bg-transparent pointer-coarse:justify-end");
31
31
  @source inline("pointer-coarse:p-0 pointer-coarse:pointer-events-auto pointer-coarse:shadow-none");
32
32
  @source inline("pointer-coarse:static py py-10 right-3 ring-1 ring-accent ring-accent/30 ring-inset self-stretch");
33
33
  @source inline("text-muted-foreground/50 top-3");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 30 candidate(s).
21
+ * 29 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -27,7 +27,7 @@
27
27
  @source inline("-mt-5 -top-1 bg-accent/15 border-l border-r data-[state=closed]:slide-out-to-bottom");
28
28
  @source inline("data-[state=closed]:slide-out-to-left data-[state=closed]:slide-out-to-right");
29
29
  @source inline("data-[state=open]:slide-in-from-bottom data-[state=open]:slide-in-from-left");
30
- @source inline("data-[state=open]:slide-in-from-right inset-x-3 items-stretch justify-around leading-4 list-none");
30
+ @source inline("data-[state=open]:slide-in-from-right inset-x-3 items-stretch justify-around list-none");
31
31
  @source inline("max-h-[var(--sheet-h-lg)] max-h-[var(--sheet-h-md)] max-h-[var(--sheet-h-sm)] max-w-sm min-h-12");
32
32
  @source inline("min-w-3.5 no-underline place-items-center pt-0 px-0.5 rounded-l-xl rounded-r-xl rounded-t-xl");
33
33
  @source inline("shadow-lg");
@@ -357,6 +357,15 @@
357
357
  .z-\[var\(--z-popover\)\] {
358
358
  z-index: var(--z-popover);
359
359
  }
360
+ .order-1 {
361
+ order: 1;
362
+ }
363
+ .order-2 {
364
+ order: 2;
365
+ }
366
+ .order-3 {
367
+ order: 3;
368
+ }
360
369
  .col-span-2 {
361
370
  grid-column: span 2 / span 2;
362
371
  }
@@ -827,6 +836,9 @@
827
836
  .min-h-12 {
828
837
  min-height: calc(var(--spacing) * 12);
829
838
  }
839
+ .min-h-14 {
840
+ min-height: calc(var(--spacing) * 14);
841
+ }
830
842
  .min-h-20 {
831
843
  min-height: calc(var(--spacing) * 20);
832
844
  }
@@ -1124,6 +1136,9 @@
1124
1136
  .min-w-24 {
1125
1137
  min-width: calc(var(--spacing) * 24);
1126
1138
  }
1139
+ .min-w-26 {
1140
+ min-width: calc(var(--spacing) * 26);
1141
+ }
1127
1142
  .min-w-28 {
1128
1143
  min-width: calc(var(--spacing) * 28);
1129
1144
  }
@@ -1184,6 +1199,9 @@
1184
1199
  .grow {
1185
1200
  flex-grow: 1;
1186
1201
  }
1202
+ .basis-0 {
1203
+ flex-basis: 0px;
1204
+ }
1187
1205
  .basis-40 {
1188
1206
  flex-basis: calc(var(--spacing) * 40);
1189
1207
  }
@@ -4934,12 +4952,24 @@
4934
4952
  }
4935
4953
  }
4936
4954
  @container (width >= 48rem) {
4955
+ .\@3xl\:order-none {
4956
+ order: 0;
4957
+ }
4937
4958
  .\@3xl\:block {
4938
4959
  display: block;
4939
4960
  }
4961
+ .\@3xl\:flex {
4962
+ display: flex;
4963
+ }
4940
4964
  .\@3xl\:hidden {
4941
4965
  display: none;
4942
4966
  }
4967
+ .\@3xl\:shrink-0 {
4968
+ flex-shrink: 0;
4969
+ }
4970
+ .\@3xl\:basis-auto {
4971
+ flex-basis: auto;
4972
+ }
4943
4973
  }
4944
4974
  .dark\:bg-amber-900\/40:where(.dark, .dark *) {
4945
4975
  background-color: color-mix(in srgb, oklch(41.4% 0.112 45.904) 40%, transparent);
@@ -5239,6 +5269,9 @@
5239
5269
  min-width: calc(var(--spacing) * 11);
5240
5270
  }
5241
5271
  }
5272
+ .\[\&_select\]\:w-full select {
5273
+ width: 100%;
5274
+ }
5242
5275
  .\[\&_sup\]\:leading-none sup {
5243
5276
  --tw-leading: 1;
5244
5277
  line-height: 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt",
3
- "version": "5.67.0",
3
+ "version": "5.68.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The React design system of the cursedbelt split — components, styles, theme. cursedbelt-core below it; server tier in cursedbelt-server.",
@@ -155,6 +155,7 @@ export const AREAS: readonly Area[] = [
155
155
  'components/ButtonLink.tsx',
156
156
  'components/CardDisplayControls.tsx',
157
157
  'components/CardTapTarget.tsx',
158
+ 'components/EntityCard.tsx',
158
159
  'components/Checkbox.tsx',
159
160
  'components/ChoiceGroup.tsx',
160
161
  'components/ChoiceMenu.tsx',
@@ -0,0 +1,177 @@
1
+ import type { KeyboardEvent, MouseEvent, ReactNode } from 'react';
2
+ import { ScrollArea } from '../components/ScrollArea.js';
3
+ import { cn } from '../lib/cn.js';
4
+
5
+ export interface CanvasToolbarProps {
6
+ /** The left half: what the canvas shows (a reach, a layer switch). Hidden while the bar is
7
+ * under 768px wide when `compactFilters` is given — five stops beside the tools would scroll out of a thumb's sight. */
8
+ filters?: ReactNode;
9
+ /** The same choice as a phone wants it, usually the OS picker (`NativeSelect`): shown only while
10
+ * the bar is under 768px wide, on row two beside the legend. */
11
+ compactFilters?: ReactNode;
12
+ /** A key or chip strip (houses, layers, tags): ONE line that scrolls inside itself, its ends
13
+ * fading where there is more. Beside the filters at every width; never under 10rem. */
14
+ legend?: ReactNode;
15
+ /** Names the legend strip for a screen reader. */
16
+ legendLabel?: string;
17
+ /** The right half: the find box and the views. Never shrinks — the legend does. */
18
+ tools?: ReactNode;
19
+ /**
20
+ * Where the keyboard goes after a control in the bar acts: a POINTER click on a button, tab or
21
+ * radio, or Escape from one. Default: the `[role="application"]` beside the bar (the canvas the
22
+ * bar sits above). `false` keeps focus on the control, the browser's default.
23
+ */
24
+ returnFocus?: (() => void) | false;
25
+ 'aria-label'?: string;
26
+ className?: string;
27
+ /** Rides on the bar's root, for an app's own selectors (`data-view`, …). */
28
+ [data: `data-${string}`]: string | undefined;
29
+ }
30
+
31
+ /**
32
+ * Whether a POINTER click landed on a control that should hand the keyboard back to the canvas
33
+ * once it has acted — a filter stop, a chip, a HUD button. A field keeps focus (it is typed into);
34
+ * a click the keyboard made (`detail` 0 — Enter or Space on a focused button) is a reader moving
35
+ * by Tab, whose focus stays where they put it.
36
+ *
37
+ * 🔴 The failure this exists for (family, 2026-10-06): the reach stops are a tab list, and a click
38
+ * leaves focus on the stop. Every arrow after that went to the stop — ← and → re-rooted and
39
+ * re-packed the tree — while the reader believed they were walking the family. Figma's rule: a
40
+ * toolbar click acts and the canvas keeps the keyboard.
41
+ */
42
+ export function controlReleasesFocus(event: Pick<MouseEvent, 'target' | 'currentTarget' | 'detail'>): boolean {
43
+ if (event.detail === 0) return false;
44
+ const target = event.target;
45
+ if (!(target instanceof Element) || target === event.currentTarget) return false;
46
+ if (target.closest("input, select, textarea, [contenteditable='true'], [role='combobox'], [role='listbox'], [role='menu']")) {
47
+ return false;
48
+ }
49
+ return target.closest("button, [role='tab'], [role='radio']") !== null;
50
+ }
51
+
52
+ /** A key on a field is the field's whole language — Escape there is not the way back to the canvas. */
53
+ export const isTextControl = (target: EventTarget | null): boolean =>
54
+ target instanceof Element && target.closest("input, select, textarea, [contenteditable='true'], [role='combobox']") !== null;
55
+
56
+ /** The canvas drawn under a bar — the `application` in the box the bar shares with it. */
57
+ const canvasBeside = (bar: Element): HTMLElement | null =>
58
+ bar.parentElement?.querySelector<HTMLElement>("[role='application']") ?? null;
59
+
60
+ /**
61
+ * The toolbar a canvas wears ABOVE itself, in flow — filters left, find and views right, a legend
62
+ * strip that scrolls inside itself, the OS picker in place of the filters below 768px.
63
+ *
64
+ * 🔴 ONE BAR, IN FLOW — never five overlays over the drawing. family's tree floated its reach
65
+ * buttons, house legend, find box and view switch over the canvas's top edge until 2026-10-06, and
66
+ * their collisions were fought width by width while cards were drawn under them at every width. A
67
+ * bar above the canvas, like Figma's and Linear's, cannot collide with anything by construction:
68
+ * the drawing starts where the bar ends. Built from family's `TreeBar` (forge task 2917) so
69
+ * patterns' and desk's boards never hand-roll a second one. Not `ListToolbar`: that one is a
70
+ * search box and a chip filter above a list; a canvas's bar carries its own reach, a legend of
71
+ * anything, and gives the keyboard back to the drawing.
72
+ *
73
+ * Narrow (the BAR under 768px — a container query, so a split pane counts): row one is the
74
+ * `tools`, right-aligned; row two is what the canvas shows — `compactFilters` (or `filters`) and the
75
+ * legend strip beside it. A phone's find button and four views do not leave a picker room beside
76
+ * them (family at 390: 300px of tools in a 366px row), and the picker and the legend are the same
77
+ * question — who is drawn — so they share a row. Wide: one line when the filters, a
78
+ * 10rem legend and the tools fit; when they do not (a 900px window), the tools ride down to row two
79
+ * as a group, right-aligned, rather than the filters being cut — the stops never shrink on a wide
80
+ * bar. Two rows at most at every width: the legend scrolls rather than wrapping.
81
+ *
82
+ * The bar hands the keyboard back to the canvas after a control acts (`returnFocus`), because a
83
+ * bar in flow sits OUTSIDE the canvas, so the canvas's own hand-back never sees its clicks.
84
+ */
85
+ export function CanvasToolbar({
86
+ filters,
87
+ compactFilters,
88
+ legend,
89
+ legendLabel,
90
+ tools,
91
+ returnFocus,
92
+ 'aria-label': ariaLabel,
93
+ className,
94
+ ...data
95
+ }: CanvasToolbarProps) {
96
+ const giveBack = (bar: Element) => {
97
+ if (returnFocus === false) return false;
98
+ if (returnFocus) {
99
+ returnFocus();
100
+ return true;
101
+ }
102
+ const canvas = canvasBeside(bar);
103
+ canvas?.focus({ preventScroll: true });
104
+ return canvas !== null;
105
+ };
106
+ const onClick = (event: MouseEvent<HTMLDivElement>) => {
107
+ if (controlReleasesFocus(event)) giveBack(event.currentTarget);
108
+ };
109
+ const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
110
+ if (event.key !== 'Escape' || event.target === event.currentTarget || isTextControl(event.target)) return;
111
+ if (giveBack(event.currentTarget)) event.preventDefault();
112
+ };
113
+ return (
114
+ // The handlers delegate — the bar's buttons, tabs and fields are the controls; these only hand
115
+ // the keyboard back to the canvas after one of them acts.
116
+ // biome-ignore lint/a11y/useSemanticElements: a <fieldset> is a FORM's grouping (its legend, its min-width quirk); this is a toolbar's layout box, and `group` only names it. No `toolbar` role: it promises arrow-key roving, which would take the arrows from the find box (ListToolbar's reasoning).
117
+ <div
118
+ {...data}
119
+ data-slot='canvas-toolbar'
120
+ role='group'
121
+ aria-label={ariaLabel}
122
+ onClick={onClick}
123
+ onKeyDown={onKeyDown}
124
+ // `@container`: the bar answers to ITS width, not the window's — a canvas in a split pane
125
+ // or a demo column is a phone-width bar on a desk-width screen.
126
+ className={cn('@container border-b border-border bg-card', className)}
127
+ >
128
+ <div className='flex flex-wrap items-center gap-x-3 gap-y-2 px-3 py-2'>
129
+ {filters ? (
130
+ <div
131
+ data-slot='canvas-toolbar-filters'
132
+ className={cn(
133
+ 'order-2 min-w-0 items-center gap-2 @3xl:order-none @3xl:shrink-0',
134
+ compactFilters ? 'hidden @3xl:flex' : 'flex',
135
+ )}
136
+ >
137
+ {filters}
138
+ </div>
139
+ ) : null}
140
+ {compactFilters ? (
141
+ <div
142
+ data-slot='canvas-toolbar-compact-filters'
143
+ className='order-2 flex min-w-26 max-w-48 flex-1 items-center @3xl:hidden [&>*]:w-full [&_select]:w-full'
144
+ >
145
+ {compactFilters}
146
+ </div>
147
+ ) : null}
148
+ {legend ? (
149
+ <ScrollArea
150
+ axis='x'
151
+ space='none'
152
+ safeArea={false}
153
+ fade
154
+ role='group'
155
+ aria-label={legendLabel}
156
+ data-slot='canvas-toolbar-legend'
157
+ className={cn(
158
+ 'order-3 flex min-w-40 basis-0 items-center gap-1 px-0.5 @3xl:order-none',
159
+ // The strip's own scrollbar is hidden; its fading ends are the "there is more" cue.
160
+ '[scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
161
+ )}
162
+ >
163
+ {legend}
164
+ </ScrollArea>
165
+ ) : null}
166
+ {tools ? (
167
+ <div
168
+ data-slot='canvas-toolbar-tools'
169
+ className='order-1 ml-auto flex flex-none basis-full items-center justify-end gap-2 @3xl:order-none @3xl:basis-auto'
170
+ >
171
+ {tools}
172
+ </div>
173
+ ) : null}
174
+ </div>
175
+ </div>
176
+ );
177
+ }
@@ -7,6 +7,8 @@ export type { CanvasNodeMenuItem, CanvasNodeMenuProps, CanvasNodeMenuSection } f
7
7
  export { CanvasNodeMenu } from './CanvasNodeMenu.js';
8
8
  export type { CanvasSearchFieldProps } from './CanvasSearchField.js';
9
9
  export { CanvasSearchField } from './CanvasSearchField.js';
10
+ export type { CanvasToolbarProps } from './CanvasToolbar.js';
11
+ export { CanvasToolbar, controlReleasesFocus, isTextControl } from './CanvasToolbar.js';
10
12
  export type { CanvasZoomHintProps, HudButtonProps, HudZoomControlsProps } from './HudControls.js';
11
13
  export { CanvasZoomHint, HudButton, HudZoomControls } from './HudControls.js';
12
14
  export type { CanvasWheelMode, CanvasWheelOptions } from './useCanvasWheel.js';
@@ -0,0 +1,76 @@
1
+ import type { ReactNode } from 'react';
2
+ import { cn } from '../lib/cn.js';
3
+ import { CardTapTarget } from './CardTapTarget.js';
4
+
5
+ export interface EntityCardProps {
6
+ /** The face: an `Avatar`, a portrait, a cover thumbnail. Drawn at its own size, never squeezed. */
7
+ media: ReactNode;
8
+ /** The name — one line, ellipsed. */
9
+ name: ReactNode;
10
+ /** One line under the name (dates, a role, a count) — muted, tabular figures, ellipsed. */
11
+ line?: ReactNode;
12
+ /** Fired on tap/click and on Enter/Space — the whole card is the target. */
13
+ onClick: () => void;
14
+ /** What a tap does, for a screen reader ("Open Ada Lovelace") — the name alone says what, not why. */
15
+ 'aria-label'?: string;
16
+ /**
17
+ * Skip `onClick` when the click only completes a text selection inside the card. Default
18
+ * `false`: a face, a name and one line hold nothing worth selecting, and a press that the
19
+ * selection check swallows reads as a dead card on a phone.
20
+ */
21
+ selectionSafe?: boolean;
22
+ className?: string;
23
+ /** Rides on the card's root, for an app's own selectors (`data-ended`, `data-self`, …). */
24
+ [data: `data-${string}`]: string | undefined;
25
+ }
26
+
27
+ /**
28
+ * A person, a title, a game — a face, a name, one line, the whole card one tap target that dips
29
+ * on press. Built from family's close-family `KinCard` (forge task 2918), on `CardTapTarget`, so
30
+ * the tap floor (`TAP_TARGET_HEIGHT`), the press dip (`PRESS_SURFACE`) and the iPhone-safe
31
+ * `div[role=button]` come from the one place they are kept.
32
+ *
33
+ * The card is a row: the face left, the text beside it. It fills its grid cell, and its text
34
+ * truncates rather than wrapping, so every card in a grid row is the same height whatever the
35
+ * name. `relative isolate` keeps anything the face positions from painting over the next card and
36
+ * eating its taps (`CardTapTarget`'s other half).
37
+ */
38
+ export function EntityCard({
39
+ media,
40
+ name,
41
+ line,
42
+ onClick,
43
+ 'aria-label': ariaLabel,
44
+ selectionSafe = false,
45
+ className,
46
+ ...data
47
+ }: EntityCardProps) {
48
+ return (
49
+ <CardTapTarget
50
+ {...data}
51
+ onClick={onClick}
52
+ aria-label={ariaLabel}
53
+ selectionSafe={selectionSafe}
54
+ className={cn(
55
+ 'relative isolate flex min-h-14 min-w-0 items-center gap-3 rounded-lg border border-border bg-card px-3 py-2',
56
+ 'hover:border-border-strong hover:bg-card-raised',
57
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
58
+ className,
59
+ )}
60
+ >
61
+ <span data-slot='entity-card-media' className='flex flex-none items-center'>
62
+ {media}
63
+ </span>
64
+ <span className='flex min-w-0 flex-col gap-0.5'>
65
+ <span data-slot='entity-card-name' className='truncate text-sm leading-5 font-medium text-foreground'>
66
+ {name}
67
+ </span>
68
+ {line ? (
69
+ <span data-slot='entity-card-line' className='truncate text-xs leading-4 text-muted-foreground tabular-nums'>
70
+ {line}
71
+ </span>
72
+ ) : null}
73
+ </span>
74
+ </CardTapTarget>
75
+ );
76
+ }
@@ -153,6 +153,7 @@ export {
153
153
  } from './components/ChartTablePanel.js';
154
154
  export * from './companion-link/index.js';
155
155
  export { CardTapTarget, type CardTapTargetProps } from './components/CardTapTarget.js';
156
+ export { EntityCard, type EntityCardProps } from './components/EntityCard.js';
156
157
  export { CardDisplayControls, type CardDisplayControlsProps } from './components/CardDisplayControls.js';
157
158
  export {
158
159
  CARD_SIZES,
@@ -18,13 +18,15 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 22 candidate(s).
21
+ * 39 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
25
25
  * import closures rather than a hand-written list, is scripts/styleAreas.ts.
26
26
  */
27
- @source inline("[&::-webkit-search-cancel-button]:hidden aria-pressed:bg-muted aria-pressed:text-foreground");
27
+ @source inline("@3xl:basis-auto @3xl:flex @3xl:hidden @3xl:order-none @3xl:shrink-0");
28
+ @source inline("[&::-webkit-scrollbar]:hidden [&::-webkit-search-cancel-button]:hidden [&_select]:w-full");
29
+ @source inline("[scrollbar-width:none] aria-pressed:bg-muted aria-pressed:text-foreground basis-0 basis-full");
28
30
  @source inline("bg-background/40 bg-background/70 bottom-3 bottom-4 focus-visible:border-transparent");
29
- @source inline("focus-visible:ring-0 left-3 min-w-10 ml-2 opacity-100 pb-1.5 pl-0 pl-1 place-items-center pr-1");
30
- @source inline("pt-1 right-4 w-40 w-64");
31
+ @source inline("focus-visible:ring-0 left-3 max-w-48 min-w-10 min-w-26 min-w-40 ml-2 opacity-100 order-1 order-2");
32
+ @source inline("order-3 pb-1.5 pl-0 pl-1 place-items-center pr-1 pt-1 px-0.5 right-4 w-40 w-64");
@@ -15,7 +15,7 @@
15
15
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
16
16
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
17
17
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
18
- * 898 candidate(s).
18
+ * 903 candidate(s).
19
19
  *
20
20
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
21
21
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -125,16 +125,16 @@
125
125
  @source inline("h-[min(var(--region-h-sm),var(--region-h-phone))] h-[var(--control-h-lg)]");
126
126
  @source inline("h-[var(--control-h-md)] h-[var(--control-h-sm)] h-[var(--indicator-w)] h-auto h-full h-px hi hid");
127
127
  @source inline("hidden hover hover:bg-accent hover:bg-accent-solid-hover hover:bg-accent/10 hover:bg-accent/20");
128
- @source inline("hover:bg-border hover:bg-destructive-solid hover:bg-destructive-solid-hover");
128
+ @source inline("hover:bg-border hover:bg-card-raised hover:bg-destructive-solid hover:bg-destructive-solid-hover");
129
129
  @source inline("hover:bg-destructive/10 hover:bg-muted hover:bg-success-solid-hover hover:bg-transparent");
130
130
  @source inline("hover:border-accent hover:border-border-strong hover:border-destructive-solid hover:opacity-70");
131
131
  @source inline("hover:text-accent hover:text-destructive hover:text-destructive-foreground hover:text-foreground");
132
132
  @source inline("hover:text-foreground! hover:underline i in inline inline-block inline-flex inline-grid inset");
133
133
  @source inline("inset-0 inset-x-0 inset-y-0 invisible is iso isolate it item items items-baseline items-center");
134
134
  @source inline("items-end items-start just justify-between justify-center justify-end justify-start l last");
135
- @source inline("last:border-b-0 lead leading leading-none leading-relaxed leading-snug leading-tight left left-0");
136
- @source inline("left-1/2 left-2 lg lg:px-8 line line-clamp-2 low lower lowercase m m-0 max max-h max-h-[80vh]");
137
- @source inline("max-h-[calc(var(--radix-popper-available-height,100dvh)-1rem)]");
135
+ @source inline("last:border-b-0 lead leading leading-4 leading-5 leading-none leading-relaxed leading-snug");
136
+ @source inline("leading-tight left left-0 left-1/2 left-2 lg lg:px-8 line line-clamp-2 low lower lowercase m m-0");
137
+ @source inline("max max-h max-h-[80vh] max-h-[calc(var(--radix-popper-available-height,100dvh)-1rem)]");
138
138
  @source inline("max-h-[var(--guide-popover-max-h)] max-h-[var(--radix-select-content-available-height)]");
139
139
  @source inline("max-sm:border-b-0 max-sm:border-x-0 max-sm:bottom-0");
140
140
  @source inline("max-sm:data-[state=closed]:slide-out-to-bottom max-sm:data-[state=open]:slide-in-from-bottom");
@@ -144,7 +144,7 @@
144
144
  @source inline("max-w-40 max-w-[var(--modal-w-sm)] max-w-[var(--page-w-dashboard)] max-w-[var(--page-w-form)]");
145
145
  @source inline("max-w-[var(--page-w-wide)] max-w-[var(--reading-width)] max-w-full max-w-lg max-w-md max-w-xl");
146
146
  @source inline("max-w-xs mb-0.5 mb-1 mb-3 md md:divide-border md:divide-x md:flex-none md:flex-row");
147
- @source inline("md:grid-cols-4 md:inline md:w-1/3 md:w-2/5 min min-h-0 min-h-11 min-h-[1lh]");
147
+ @source inline("md:grid-cols-4 md:inline md:w-1/3 md:w-2/5 min min-h-0 min-h-11 min-h-14 min-h-[1lh]");
148
148
  @source inline("min-h-[var(--control-h-lg)] min-h-[var(--control-h-md)] min-h-[var(--control-h-sm)] min-h-row");
149
149
  @source inline("min-w-0 min-w-11 min-w-32 min-w-[var(--radix-select-trigger-width)] ml-1 ml-auto motion");
150
150
  @source inline("motion-reduce:active:scale-100 motion-reduce:animate-none motion-reduce:duration-0");
@@ -172,8 +172,8 @@
172
172
  @source inline("sm:max-w-[var(--modal-w-lg)] sm:max-w-[var(--modal-w-md)] sm:max-w-[var(--modal-w-sm)] sm:p-4");
173
173
  @source inline("sm:p-5 sm:p-8 sm:pointer-fine:text-sm sm:px-6 sm:rounded-xl sm:text-sm sm:top-1/2");
174
174
  @source inline("sm:w-[calc(100vw-2rem)] space space-y-1 space-y-3 sr-only stat static sticky stroke");
175
- @source inline("stroke-accent-solid stroke-destructive stroke-muted stroke-warning t ta tab table tabular-nums");
176
- @source inline("text text-2xl text-[length:var(--text-glyph-relative)] text-[var(--foreground)]");
175
+ @source inline("stroke-accent-solid stroke-destructive stroke-muted stroke-warning t ta tab table tabular");
176
+ @source inline("tabular-nums text text-2xl text-[length:var(--text-glyph-relative)] text-[var(--foreground)]");
177
177
  @source inline("text-[var(--muted-foreground)] text-accent text-accent-strong text-base text-caption text-center");
178
178
  @source inline("text-current text-data text-destructive text-destructive-foreground text-destructive-strong");
179
179
  @source inline("text-emerald-700 text-field-error text-field-fg text-foreground text-h1 text-h3 text-inherit");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 120 candidate(s).
21
+ * 119 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -40,7 +40,7 @@
40
40
  @source inline("focus-within:ring-2 focus-within:ring-field-ring/30 focus-within:ring-offset-1");
41
41
  @source inline("focus-within:ring-ring group-focus-within:opacity-100 h-105 h-12 h-3.5");
42
42
  @source inline("has-[[aria-invalid=true]]:border-field-error hover:bg-muted/50 hover:border-field-ring");
43
- @source inline("hover:scale-110 hover:text-warning italic leading-5 left-2.5 li list-none max-h-64");
43
+ @source inline("hover:scale-110 hover:text-warning italic left-2.5 li list-none max-h-64");
44
44
  @source inline("max-h-[var(--sheet-h-lg)] max-h-[var(--sheet-h-md)] max-h-[var(--sheet-h-sm)] max-w-sm");
45
45
  @source inline("md:flex-col md:gap-0.5 md:justify-start md:overflow-visible md:text-left md:w-full min-h-20");
46
46
  @source inline("min-w-24 min-w-64 min-w-[var(--anchor-width)] min-w-full min-w-max mix-blend-difference mr-2");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 31 candidate(s).
21
+ * 30 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -27,7 +27,7 @@
27
27
  @source inline("-mx-2 -outline-offset-2 [&_button]:min-h-0 [&_button]:min-w-0 [&_button]:p-0 [&_button]:size-7");
28
28
  @source inline("bg-card-overlay border-r duration-150 group-data-[state=open]/rail-section:rotate-90");
29
29
  @source inline("group-focus-within/rail-row:opacity-100 group-hover/rail-row:opacity-100 group/rail-row");
30
- @source inline("group/rail-section hover:bg-card-raised last:mb-0 mx-2 opacity-100 outline-2 outline-accent");
31
- @source inline("outline-dashed place-items-center pointer-coarse:[&_button]:min-h-11");
32
- @source inline("pointer-coarse:[&_button]:min-w-11 pointer-coarse:[&_button]:size-11 pt-1 self-stretch");
33
- @source inline("shadow-[inset_3px_0_0_0_var(--accent)] w-14 w-3 w-56");
30
+ @source inline("group/rail-section last:mb-0 mx-2 opacity-100 outline-2 outline-accent outline-dashed");
31
+ @source inline("place-items-center pointer-coarse:[&_button]:min-h-11 pointer-coarse:[&_button]:min-w-11");
32
+ @source inline("pointer-coarse:[&_button]:size-11 pt-1 self-stretch shadow-[inset_3px_0_0_0_var(--accent)] w-14");
33
+ @source inline("w-3 w-56");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 142 candidate(s).
21
+ * 141 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -42,11 +42,11 @@
42
42
  @source inline("group-hover/tile:opacity-100 group/navitem group/tile h-12 h-[var(--header-h)]");
43
43
  @source inline("h-[var(--header-h-dense)] h-[var(--header-h-roomy)] h-dvh hover:border-foreground/20");
44
44
  @source inline("hover:decoration-border hover:scale-110 hover:underline-offset-4 inset-x-2 inset-x-3 inset-y-1");
45
- @source inline("inset-y-1.5 items-stretch justify-around leading-4 left-3 lg:flex lg:flex-col lg:hidden");
46
- @source inline("lg:shrink-0 list-none max-h-72 max-h-[inherit] max-h-[var(--palette-max-h)]");
47
- @source inline("max-h-[var(--sheet-h-lg)] max-h-[var(--sheet-h-md)] max-h-[var(--sheet-h-sm)] max-md:-right-0.5");
48
- @source inline("max-md:-top-0.5 max-md:absolute max-md:hidden max-sm:flex-none max-sm:justify-center max-sm:px-0");
49
- @source inline("max-sm:w-10 max-w max-w-48 max-w-64 max-w-80 max-w-sm md:flex md:flex-col md:gap-4 md:hidden");
45
+ @source inline("inset-y-1.5 items-stretch justify-around left-3 lg:flex lg:flex-col lg:hidden lg:shrink-0");
46
+ @source inline("list-none max-h-72 max-h-[inherit] max-h-[var(--palette-max-h)] max-h-[var(--sheet-h-lg)]");
47
+ @source inline("max-h-[var(--sheet-h-md)] max-h-[var(--sheet-h-sm)] max-md:-right-0.5 max-md:-top-0.5");
48
+ @source inline("max-md:absolute max-md:hidden max-sm:flex-none max-sm:justify-center max-sm:px-0 max-sm:w-10");
49
+ @source inline("max-w max-w-48 max-w-64 max-w-80 max-w-sm md:flex md:flex-col md:gap-4 md:hidden");
50
50
  @source inline("md:pointer-coarse:w-auto md:px-3 md:px-6 md:shrink-0 min-h-10 min-h-12 min-h-dvh min-w-3.5");
51
51
  @source inline("min-w-8 min-w-9 mix-blend-difference mt-auto mx-1 no-underline opacity-55 opacity-80");
52
52
  @source inline("pb-[env(safe-area-inset-bottom,0px)] pl-11 pl-9 place-items-center");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 33 candidate(s).
21
+ * 32 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -26,8 +26,8 @@
26
26
  */
27
27
  @source inline("-right-0.5 -top-0.5 [&::-webkit-scrollbar]:hidden [scrollbar-width:none] bg-accent/15");
28
28
  @source inline("group-focus-within:opacity-100 group-focus-within:pointer-events-auto");
29
- @source inline("group-hover:pointer-events-auto hover:bg-muted/80 leading-4 list-none min-w-4 ml-1.5 ml-2 pb");
30
- @source inline("pb-0.5 pointer-coarse:basis-full pointer-coarse:bg-transparent pointer-coarse:justify-end");
29
+ @source inline("group-hover:pointer-events-auto hover:bg-muted/80 list-none min-w-4 ml-1.5 ml-2 pb pb-0.5");
30
+ @source inline("pointer-coarse:basis-full pointer-coarse:bg-transparent pointer-coarse:justify-end");
31
31
  @source inline("pointer-coarse:p-0 pointer-coarse:pointer-events-auto pointer-coarse:shadow-none");
32
32
  @source inline("pointer-coarse:static py py-10 right-3 ring-1 ring-accent ring-accent/30 ring-inset self-stretch");
33
33
  @source inline("text-muted-foreground/50 top-3");
@@ -18,7 +18,7 @@
18
18
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
19
19
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
20
20
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
21
- * 30 candidate(s).
21
+ * 29 candidate(s).
22
22
  *
23
23
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
24
24
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -27,7 +27,7 @@
27
27
  @source inline("-mt-5 -top-1 bg-accent/15 border-l border-r data-[state=closed]:slide-out-to-bottom");
28
28
  @source inline("data-[state=closed]:slide-out-to-left data-[state=closed]:slide-out-to-right");
29
29
  @source inline("data-[state=open]:slide-in-from-bottom data-[state=open]:slide-in-from-left");
30
- @source inline("data-[state=open]:slide-in-from-right inset-x-3 items-stretch justify-around leading-4 list-none");
30
+ @source inline("data-[state=open]:slide-in-from-right inset-x-3 items-stretch justify-around list-none");
31
31
  @source inline("max-h-[var(--sheet-h-lg)] max-h-[var(--sheet-h-md)] max-h-[var(--sheet-h-sm)] max-w-sm min-h-12");
32
32
  @source inline("min-w-3.5 no-underline place-items-center pt-0 px-0.5 rounded-l-xl rounded-r-xl rounded-t-xl");
33
33
  @source inline("shadow-lg");