@xenide-io/the-old-ui-theme 0.5.4 → 0.6.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 (63) hide show
  1. package/dist/{Chip-C5hRFAhe.d.mts → Chip-DzC5xtK9.d.mts} +8 -3
  2. package/dist/{Chip-C5hRFAhe.d.ts → Chip-DzC5xtK9.d.ts} +8 -3
  3. package/dist/chunk-3G43JEI3.mjs +2564 -0
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +7 -2
  7. package/dist/index.mjs +3 -1
  8. package/dist/tailwind-preset.js +1 -0
  9. package/dist/tailwind-preset.mjs +1 -0
  10. package/dist/ui.d.mts +4 -531
  11. package/dist/ui.d.ts +4 -531
  12. package/dist/ui.js +407 -2504
  13. package/dist/ui.mjs +5 -91
  14. package/package.json +1 -1
  15. package/src/app/globals.css +18 -0
  16. package/src/components/ui/Typography.tsx +12 -4
  17. package/src/components/ui/index.ts +7 -184
  18. package/src/components/ui/typography.test.tsx +27 -0
  19. package/src/styles/suite-skin.css +21 -1
  20. package/src/styles/typography.css +72 -3
  21. package/tailwind-preset.ts +1 -0
  22. package/dist/chunk-SBBKXV35.mjs +0 -4620
  23. package/src/components/ui/AlertDialog.tsx +0 -62
  24. package/src/components/ui/AppLayout.tsx +0 -27
  25. package/src/components/ui/Autocomplete.tsx +0 -106
  26. package/src/components/ui/Banner.tsx +0 -63
  27. package/src/components/ui/ButtonGroup.tsx +0 -16
  28. package/src/components/ui/ChatBubble.tsx +0 -71
  29. package/src/components/ui/Collapsible.tsx +0 -46
  30. package/src/components/ui/Combobox.tsx +0 -119
  31. package/src/components/ui/ContextMenu.tsx +0 -81
  32. package/src/components/ui/DataTable.tsx +0 -133
  33. package/src/components/ui/DatePicker.tsx +0 -96
  34. package/src/components/ui/Dialog.tsx +0 -75
  35. package/src/components/ui/Divider.tsx +0 -39
  36. package/src/components/ui/Drawer.tsx +0 -71
  37. package/src/components/ui/HoverCard.tsx +0 -36
  38. package/src/components/ui/Indicator.tsx +0 -61
  39. package/src/components/ui/InputGroup.tsx +0 -16
  40. package/src/components/ui/Lettermark.tsx +0 -47
  41. package/src/components/ui/LoadingBar.tsx +0 -25
  42. package/src/components/ui/Menubar.tsx +0 -66
  43. package/src/components/ui/Metric.tsx +0 -34
  44. package/src/components/ui/Navigation.tsx +0 -94
  45. package/src/components/ui/NumberField.tsx +0 -76
  46. package/src/components/ui/Popover.tsx +0 -73
  47. package/src/components/ui/ProgressCircle.tsx +0 -63
  48. package/src/components/ui/Rating.tsx +0 -65
  49. package/src/components/ui/Resizable.tsx +0 -71
  50. package/src/components/ui/Row.tsx +0 -51
  51. package/src/components/ui/ScrollArea.tsx +0 -54
  52. package/src/components/ui/Sidebar.tsx +0 -79
  53. package/src/components/ui/Snack.tsx +0 -48
  54. package/src/components/ui/Splotch.tsx +0 -33
  55. package/src/components/ui/Stepper.tsx +0 -74
  56. package/src/components/ui/Tabs.tsx +0 -53
  57. package/src/components/ui/Tag.tsx +0 -65
  58. package/src/components/ui/Terminal.tsx +0 -54
  59. package/src/components/ui/ThemeManager.tsx +0 -18
  60. package/src/components/ui/Timeline.tsx +0 -60
  61. package/src/components/ui/Toast.tsx +0 -70
  62. package/src/components/ui/Toggle.tsx +0 -62
  63. package/src/components/ui/Widget.tsx +0 -31
package/dist/ui.mjs CHANGED
@@ -2,39 +2,24 @@
2
2
  import {
3
3
  Accordion,
4
4
  Alert,
5
- AlertDialog,
6
- AppLayout,
7
5
  AuthCard,
8
6
  AuthDivider,
9
7
  AuthLayout,
10
- Autocomplete,
11
8
  Avatar,
12
9
  AvatarGroup,
13
10
  Badge,
14
- Banner,
15
- Breadcrumbs,
16
11
  Button,
17
- ButtonGroup,
18
12
  Calendar,
19
13
  Caption,
20
14
  Card,
21
- ChatBubble,
22
15
  Checkbox,
23
16
  Chip,
24
17
  CodeBlock,
25
- Collapsible,
26
18
  CollapsibleSection,
27
- Combobox,
28
19
  CommandPalette,
29
20
  ComponentDocs,
30
- ContextMenu,
31
- DataTable,
32
- DatePicker,
33
- Dialog,
34
21
  Display,
35
- Divider,
36
22
  Dot,
37
- Drawer,
38
23
  EmptyState,
39
24
  FileUpload,
40
25
  FilterBar,
@@ -47,68 +32,40 @@ import {
47
32
  H3,
48
33
  H4,
49
34
  H5,
50
- HoverCard,
51
- Indicator,
52
35
  Input,
53
- InputGroup,
54
36
  Kbd,
55
37
  Label,
56
38
  Lead,
57
- Lettermark,
58
39
  Link,
59
40
  Loader,
60
- LoadingBar,
61
41
  LoadingState,
62
- Menubar,
63
- Metric,
64
42
  Modal,
65
43
  Mono,
66
- NumberField,
67
44
  Overline,
68
45
  P,
69
- Pagination,
70
46
  Panel,
71
- Popover,
72
47
  Progress,
73
- ProgressCircle,
74
48
  Radio,
75
49
  Range,
76
- Rating,
77
- Resizable,
78
- Row,
79
- ScrollArea,
80
50
  SearchGroup,
81
51
  SearchInput,
52
+ SectionTitle,
82
53
  SegmentedControl,
83
54
  Select,
84
55
  SettingsLayout,
85
56
  SettingsNav,
86
57
  ShowcaseWrapper,
87
- Sidebar,
88
58
  Skeleton,
89
59
  Small,
90
- Snack,
91
60
  SortMenu,
92
61
  Spinner,
93
- Splotch,
94
62
  Stat,
95
- Stepper,
96
63
  Table,
97
- Tabs,
98
- Tag,
99
- Terminal,
100
64
  Textarea,
101
65
  ThemeDomSync,
102
- ThemeManager,
103
66
  ThemeSwitcher,
104
- Timeline,
105
- Toast,
106
- ToastStack,
107
- Toggle,
108
- ToggleButton,
109
- ToggleGroup,
110
- Widget
111
- } from "./chunk-SBBKXV35.mjs";
67
+ Toggle
68
+ } from "./chunk-3G43JEI3.mjs";
112
69
  import {
113
70
  ButtonChrome,
114
71
  DropdownButton,
@@ -125,40 +82,25 @@ import "./chunk-FWCSY2DS.mjs";
125
82
  export {
126
83
  Accordion,
127
84
  Alert,
128
- AlertDialog,
129
- AppLayout,
130
85
  AuthCard,
131
86
  AuthDivider,
132
87
  AuthLayout,
133
- Autocomplete,
134
88
  Avatar,
135
89
  AvatarGroup,
136
90
  Badge,
137
- Banner,
138
- Breadcrumbs,
139
91
  Button,
140
92
  ButtonChrome,
141
- ButtonGroup,
142
93
  Calendar,
143
94
  Caption,
144
95
  Card,
145
- ChatBubble,
146
96
  Checkbox,
147
97
  Chip,
148
98
  CodeBlock,
149
- Collapsible,
150
99
  CollapsibleSection,
151
- Combobox,
152
100
  CommandPalette,
153
101
  ComponentDocs,
154
- ContextMenu,
155
- DataTable,
156
- DatePicker,
157
- Dialog,
158
102
  Display,
159
- Divider,
160
103
  Dot,
161
- Drawer,
162
104
  DropdownButton,
163
105
  DropdownItem,
164
106
  DropdownMenu,
@@ -176,69 +118,41 @@ export {
176
118
  H3,
177
119
  H4,
178
120
  H5,
179
- HoverCard,
180
121
  IconBase as Icon,
181
122
  IconByName,
182
- Indicator,
183
123
  Input,
184
- InputGroup,
185
124
  Kbd,
186
125
  Label,
187
126
  Lead,
188
- Lettermark,
189
127
  Link,
190
128
  Loader,
191
- LoadingBar,
192
129
  LoadingState,
193
- Menubar,
194
- Metric,
195
130
  Modal,
196
131
  Mono,
197
- NumberField,
198
132
  Overline,
199
133
  P,
200
- Pagination,
201
134
  Panel,
202
- Popover,
203
135
  Progress,
204
- ProgressCircle,
205
136
  Radio,
206
137
  Range,
207
- Rating,
208
- Resizable,
209
- Row,
210
- ScrollArea,
211
138
  SearchGroup,
212
139
  SearchInput,
140
+ SectionTitle,
213
141
  SegmentedControl,
214
142
  Select,
215
143
  SettingsLayout,
216
144
  SettingsNav,
217
145
  ShowcaseWrapper,
218
- Sidebar,
219
146
  Skeleton,
220
147
  Small,
221
- Snack,
222
148
  SortMenu,
223
149
  Spinner,
224
- Splotch,
225
150
  Stat,
226
- Stepper,
227
151
  Table,
228
- Tabs,
229
- Tag,
230
- Terminal,
231
152
  Textarea,
232
153
  ThemeDomSync,
233
- ThemeManager,
234
154
  ThemeSwitcher,
235
- Timeline,
236
- Toast,
237
- ToastStack,
238
155
  Toggle,
239
- ToggleButton,
240
- ToggleGroup,
241
156
  Tooltip,
242
- TooltipProvider,
243
- Widget
157
+ TooltipProvider
244
158
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenide-io/the-old-ui-theme",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "Props-driven React components and theme tokens inspired by classic interface design \u2014 optimized for Next.js apps and internal tools.",
5
5
  "author": "Xenide",
6
6
  "license": "MIT",
@@ -36,6 +36,24 @@
36
36
  font-display: swap;
37
37
  }
38
38
 
39
+ /* Instrument Serif — the one display voice, for marketing and document titles.
40
+ Single weight on purpose: contrast comes from the serif shapes and scale,
41
+ not from more weights competing with Open Runde. */
42
+ @font-face {
43
+ font-family: "Instrument Serif";
44
+ src: url("/fonts/InstrumentSerif-Regular.woff2") format("woff2");
45
+ font-weight: 400;
46
+ font-style: normal;
47
+ font-display: swap;
48
+ }
49
+ @font-face {
50
+ font-family: "Instrument Serif";
51
+ src: url("/fonts/InstrumentSerif-Italic.woff2") format("woff2");
52
+ font-weight: 400;
53
+ font-style: italic;
54
+ font-display: swap;
55
+ }
56
+
39
57
  /* Structural tokens — shared across colour themes */
40
58
  :where(:root) {
41
59
  --ph-shadow-elevation-3000: 0 3px 0 var(--ph-border-3000);
@@ -57,7 +57,10 @@ function textClass(
57
57
  return cn(base, toneMap[tone], weight && weightMap[weight], truncate && "truncate", className);
58
58
  }
59
59
 
60
- /** Display text — largest heading, use once per page */
60
+ /**
61
+ * Display — the marketing hero voice: Instrument Serif, fluid size, one per page.
62
+ * Product page titles use H1/`SuitePageHeader` (sans) instead.
63
+ */
61
64
  export function Display({
62
65
  children,
63
66
  tone = "default",
@@ -65,7 +68,12 @@ export function Display({
65
68
  truncate,
66
69
  className,
67
70
  }: TextBaseProps) {
68
- return <h1 className={textClass("text-4xl font-extrabold tracking-tight md:text-5xl", tone, weight, truncate, className)}>{children}</h1>;
71
+ return <h1 className={textClass("ph-hero-title", tone, weight, truncate, className)}>{children}</h1>;
72
+ }
73
+
74
+ /** Section title — serif, fluid; pairs with Display on public pages. */
75
+ export function SectionTitle({ children, tone = "default", weight, truncate, className }: TextBaseProps) {
76
+ return <h2 className={textClass("ph-section-title", tone, weight, truncate, className)}>{children}</h2>;
69
77
  }
70
78
 
71
79
  /** H1 — page title */
@@ -113,9 +121,9 @@ export function Overline({ children, tone = "muted", weight, truncate, className
113
121
  return <span className={textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className)}>{children}</span>;
114
122
  }
115
123
 
116
- /** Lead — intro paragraph, larger and muted */
124
+ /** Lead — intro paragraph under a Display/SectionTitle; measure-capped for readability */
117
125
  export function Lead({ children, tone = "subtle", weight, truncate, className }: TextBaseProps) {
118
- return <p className={textClass("text-lg leading-relaxed", tone, weight, truncate, className)}>{children}</p>;
126
+ return <p className={textClass("ph-lead", tone, weight, truncate, className)}>{children}</p>;
119
127
  }
120
128
 
121
129
  /** Mono — code, data, technical text */
@@ -1,5 +1,11 @@
1
1
  "use client";
2
2
 
3
+ /**
4
+ * Full UI surface — also published as `@xenide-io/the-old-ui-theme/ui`.
5
+ * Scoped to primitives the ShellStack apps use, plus the demo-only docs
6
+ * helpers (ShowcaseWrapper, ComponentDocs, CollapsibleSection, CodeBlock).
7
+ */
8
+
3
9
  export {
4
10
  Button as Button,
5
11
  type ButtonProps as ButtonProps,
@@ -27,12 +33,6 @@ export {
27
33
  type CardProps as CardProps,
28
34
  type CardVariant as CardVariant,
29
35
  } from "@/components/ui/Card";
30
- export {
31
- Drawer as Drawer,
32
- type DrawerProps as DrawerProps,
33
- type DrawerSide as DrawerSide,
34
- type DrawerSize as DrawerSize,
35
- } from "@/components/ui/Drawer";
36
36
  export {
37
37
  Kbd as Kbd,
38
38
  type KbdPlatform as KbdPlatform,
@@ -110,21 +110,10 @@ export {
110
110
  type ModalProps as ModalProps,
111
111
  type ModalSize as ModalSize,
112
112
  } from "@/components/ui/Modal";
113
- export {
114
- Breadcrumbs as Breadcrumbs,
115
- Pagination as Pagination,
116
- type BreadcrumbItem as BreadcrumbItem,
117
- type BreadcrumbsProps as BreadcrumbsProps,
118
- type PaginationProps as PaginationProps,
119
- } from "@/components/ui/Navigation";
120
113
  export {
121
114
  Panel as Panel,
122
115
  type PanelProps as PanelProps,
123
116
  } from "@/components/ui/Panel";
124
- export {
125
- Rating as Rating,
126
- type RatingProps as RatingProps,
127
- } from "@/components/ui/Rating";
128
117
  export {
129
118
  SearchGroup as SearchGroup,
130
119
  SearchInput as SearchInput,
@@ -141,24 +130,7 @@ export {
141
130
  type StatProps as StatProps,
142
131
  type StatTone as StatTone,
143
132
  } from "@/components/ui/Stat";
144
- export {
145
- Toast as Toast,
146
- ToastStack as ToastStack,
147
- type ToastProps as ToastProps,
148
- type ToastStackProps as ToastStackProps,
149
- type ToastStatus as ToastStatus,
150
- } from "@/components/ui/Toast";
151
- export {
152
- Tabs as Tabs,
153
- type TabItem as TabItem,
154
- type TabsProps as TabsProps,
155
- type TabsVariant as TabsVariant,
156
- } from "@/components/ui/Tabs";
157
133
  export { ThemeDomSync } from "@/components/ui/ThemeDomSync";
158
- export {
159
- ThemeManager,
160
- type ThemeManagerProps,
161
- } from "@/components/ui/ThemeManager";
162
134
  export {
163
135
  ThemeSwitcher,
164
136
  type ThemeSwitcherProps,
@@ -172,11 +144,9 @@ export {
172
144
  type IconName as IconName,
173
145
  } from "@/components/icons";
174
146
  export { Accordion } from "@/components/ui/Accordion";
175
- export { Stepper } from "@/components/ui/Stepper";
176
147
  export { SegmentedControl } from "@/components/ui/SegmentedControl";
177
148
  export { CommandPalette } from "@/components/ui/CommandPalette";
178
149
  export { Calendar } from "@/components/ui/Calendar";
179
- export { HoverCard } from "@/components/ui/HoverCard";
180
150
  export {
181
151
  Tooltip,
182
152
  TooltipProvider,
@@ -214,6 +184,7 @@ export { ShowcaseWrapper } from "@/components/ui/ShowcaseWrapper";
214
184
  export { CollapsibleSection } from "@/components/ui/CollapsibleSection";
215
185
  export {
216
186
  Display,
187
+ SectionTitle,
217
188
  H1,
218
189
  H2,
219
190
  H3,
@@ -239,72 +210,6 @@ export {
239
210
  Progress as Progress,
240
211
  type ProgressProps as ProgressProps,
241
212
  } from "@/components/ui/Progress";
242
- export {
243
- ChatBubble as ChatBubble,
244
- type ChatBubbleProps as ChatBubbleProps,
245
- type ChatBubbleVariant as ChatBubbleVariant,
246
- } from "@/components/ui/ChatBubble";
247
- export {
248
- Terminal as Terminal,
249
- type TerminalProps as TerminalProps,
250
- } from "@/components/ui/Terminal";
251
- export {
252
- Indicator as Indicator,
253
- type IndicatorProps as IndicatorProps,
254
- type IndicatorPosition as IndicatorPosition,
255
- } from "@/components/ui/Indicator";
256
- export {
257
- Timeline as Timeline,
258
- type TimelineProps as TimelineProps,
259
- type TimelineEvent as TimelineEvent,
260
- } from "@/components/ui/Timeline";
261
- export {
262
- Banner as Banner,
263
- type BannerProps as BannerProps,
264
- type BannerType as BannerType,
265
- } from "@/components/ui/Banner";
266
- export {
267
- Dialog as Dialog,
268
- type DialogProps as DialogProps,
269
- } from "@/components/ui/Dialog";
270
- export {
271
- Divider as Divider,
272
- type DividerProps as DividerProps,
273
- } from "@/components/ui/Divider";
274
- export {
275
- Tag as Tag,
276
- type TagProps as TagProps,
277
- type TagType as TagType,
278
- } from "@/components/ui/Tag";
279
- export {
280
- ProgressCircle as ProgressCircle,
281
- type ProgressCircleProps as ProgressCircleProps,
282
- } from "@/components/ui/ProgressCircle";
283
- export {
284
- Row as Row,
285
- type RowProps as RowProps,
286
- } from "@/components/ui/Row";
287
- export {
288
- Widget as Widget,
289
- type WidgetProps as WidgetProps,
290
- } from "@/components/ui/Widget";
291
- export {
292
- Lettermark as Lettermark,
293
- type LettermarkProps as LettermarkProps,
294
- } from "@/components/ui/Lettermark";
295
- export {
296
- Splotch as Splotch,
297
- type SplotchProps as SplotchProps,
298
- type SplotchColor as SplotchColor,
299
- } from "@/components/ui/Splotch";
300
- export {
301
- Popover as Popover,
302
- type PopoverProps as PopoverProps,
303
- } from "@/components/ui/Popover";
304
- export {
305
- LoadingBar as LoadingBar,
306
- type LoadingBarProps as LoadingBarProps,
307
- } from "@/components/ui/LoadingBar";
308
213
  export {
309
214
  Link as Link,
310
215
  type LinkProps as LinkProps,
@@ -313,93 +218,11 @@ export {
313
218
  Spinner as Spinner,
314
219
  type SpinnerProps as SpinnerProps,
315
220
  } from "@/components/ui/Spinner";
316
- export {
317
- Snack as Snack,
318
- type SnackProps as SnackProps,
319
- } from "@/components/ui/Snack";
320
- export {
321
- Combobox as Combobox,
322
- type ComboboxProps as ComboboxProps,
323
- type ComboboxOption as ComboboxOption,
324
- } from "@/components/ui/Combobox";
325
- export {
326
- Autocomplete as Autocomplete,
327
- type AutocompleteProps as AutocompleteProps,
328
- type AutocompleteOption as AutocompleteOption,
329
- } from "@/components/ui/Autocomplete";
330
- export {
331
- ContextMenu as ContextMenu,
332
- type ContextMenuProps as ContextMenuProps,
333
- type ContextMenuItem as ContextMenuItem,
334
- } from "@/components/ui/ContextMenu";
335
- export {
336
- Resizable as Resizable,
337
- type ResizableProps as ResizableProps,
338
- } from "@/components/ui/Resizable";
339
- export {
340
- ScrollArea as ScrollArea,
341
- type ScrollAreaProps as ScrollAreaProps,
342
- } from "@/components/ui/ScrollArea";
343
- export {
344
- NumberField as NumberField,
345
- type NumberFieldProps as NumberFieldProps,
346
- } from "@/components/ui/NumberField";
347
- export {
348
- InputGroup as InputGroup,
349
- type InputGroupProps as InputGroupProps,
350
- } from "@/components/ui/InputGroup";
351
- export {
352
- ButtonGroup as ButtonGroup,
353
- type ButtonGroupProps as ButtonGroupProps,
354
- } from "@/components/ui/ButtonGroup";
355
- export {
356
- ToggleButton as ToggleButton,
357
- ToggleGroup as ToggleGroup,
358
- type ToggleButtonProps as ToggleButtonProps,
359
- type ToggleGroupProps as ToggleGroupProps,
360
- } from "@/components/ui/Toggle";
361
- export {
362
- Menubar as Menubar,
363
- type MenubarProps as MenubarProps,
364
- type MenubarItem as MenubarItem,
365
- } from "@/components/ui/Menubar";
366
- export {
367
- AlertDialog as AlertDialog,
368
- type AlertDialogProps as AlertDialogProps,
369
- } from "@/components/ui/AlertDialog";
370
221
  export {
371
222
  Dot as Dot,
372
223
  type DotProps as DotProps,
373
224
  } from "@/components/ui/Dot";
374
- export {
375
- Collapsible as Collapsible,
376
- type CollapsibleProps as CollapsibleProps,
377
- } from "@/components/ui/Collapsible";
378
- export {
379
- Metric as Metric,
380
- type MetricProps as MetricProps,
381
- } from "@/components/ui/Metric";
382
225
  export {
383
226
  Chip as Chip,
384
227
  type ChipProps as ChipProps,
385
228
  } from "@/components/ui/Chip";
386
- export {
387
- DataTable as DataTable,
388
- type DataTableProps as DataTableProps,
389
- type DataTableColumn as DataTableColumn,
390
- } from "@/components/ui/DataTable";
391
- export {
392
- DatePicker as DatePicker,
393
- type DatePickerProps as DatePickerProps,
394
- } from "@/components/ui/DatePicker";
395
- export {
396
- AppLayout as AppLayout,
397
- type AppLayoutProps as AppLayoutProps,
398
- } from "@/components/ui/AppLayout";
399
-
400
- export {
401
- Sidebar as Sidebar,
402
- type SidebarProps as SidebarProps,
403
- type SidebarGroup as SidebarGroup,
404
- type SidebarItemDef as SidebarItemDef,
405
- } from "@/components/ui/Sidebar";
@@ -0,0 +1,27 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+ import { Display, Lead, H1, SectionTitle } from "@/components/ui/Typography";
4
+
5
+ describe("typography voices", () => {
6
+ it("gives marketing display the serif hero class and keeps product H1 sans", () => {
7
+ render(
8
+ <>
9
+ <Display>Track time without ceremony</Display>
10
+ <SectionTitle>Built for the suite</SectionTitle>
11
+ <Lead>One scale across five apps.</Lead>
12
+ </>,
13
+ );
14
+
15
+ expect(screen.getByText("Track time without ceremony")).toHaveClass("ph-hero-title");
16
+ expect(screen.getByText("Built for the suite")).toHaveClass("ph-section-title");
17
+ expect(screen.getByText("One scale across five apps.")).toHaveClass("ph-lead");
18
+ });
19
+
20
+ it("renders product headings without the marketing classes", () => {
21
+ render(<H1>Reports</H1>);
22
+
23
+ const heading = screen.getByRole("heading", { name: "Reports" });
24
+ expect(heading).not.toHaveClass("ph-hero-title");
25
+ expect(heading.className).toContain("font-bold");
26
+ });
27
+ });
@@ -11,7 +11,8 @@
11
11
  ───────────────────────────────────────────────────────────────────────── */
12
12
 
13
13
  html {
14
- /* Native-app touch: no grey flash on tap, no double-tap delay. */
14
+ /* Native-app touch: no grey flash on tap, no double-tap zoom delay. */
15
+ touch-action: manipulation;
15
16
  -webkit-tap-highlight-color: transparent;
16
17
  /* App-like vertical scrolling: no rubber-band chaining into the page. */
17
18
  overscroll-behavior-y: none;
@@ -292,6 +293,25 @@ html.dark .today-page-frame__cloud--2 {
292
293
  }
293
294
  }
294
295
 
296
+ /* Sticky title chrome is for Today only — workspace pages scroll normally. */
297
+ .suite-app-layout__main:not(:has([data-test="today-page"])) .suite-page-header-sticky {
298
+ position: static;
299
+ top: auto;
300
+ z-index: auto;
301
+ margin-left: 0;
302
+ margin-right: 0;
303
+ padding-left: 0;
304
+ padding-right: 0;
305
+ background: none;
306
+ border-bottom: none;
307
+ -webkit-backdrop-filter: none;
308
+ backdrop-filter: none;
309
+ }
310
+ .suite-app-layout__main:not(:has([data-test="today-page"]))
311
+ .suite-page-header-sticky[data-stuck="true"] {
312
+ padding-top: 0;
313
+ }
314
+
295
315
  /* Page stage — ONE layout standard for every suite app.
296
316
  - Default width="full": use the full main column (no max-width centring)
297
317
  - Always use suite-page-inset for title baseline (top + left)
@@ -1,11 +1,19 @@
1
1
  /**
2
- * Font stacks — `next/font` only injects `--font-inter`; glyphs & canvas should match body.
2
+ * Type system — two voices, one scale.
3
3
  *
4
- * `@tailwindcss/typography`: not wired here on purpose — this repo uses PostHog-style
5
- * component-level sizes (`.ph-btn`, `.ph-table`, `.ph-h2-rule`) instead of prose blocks.
4
+ * 1. Open Runde (`font-sans`) — every product surface: UI, body copy, controls.
5
+ * Also `font-display` in app configs, i.e. tight-tracked in-app page titles.
6
+ * 2. Instrument Serif (`font-serif`) — the single display voice: marketing
7
+ * heroes, section titles, and document titles. One weight only.
8
+ * 3. Monospace stack — code, CSV, token chips. Functional, never decorative.
9
+ *
10
+ * Marketing type uses `clamp()` so a hero has ONE definition instead of three
11
+ * breakpoint variants per app. Product UI keeps Tailwind's step scale.
6
12
  */
7
13
 
8
14
  :root {
15
+ /* Display / editorial — pairs with Open Runde by contrast, not similarity */
16
+ --ph-font-serif-stack: "Instrument Serif", ui-serif, Georgia, "Times New Roman", serif;
9
17
  /* Code / CSV / token chips — monospace with clear ASCII */
10
18
  --ph-font-monospace-stack:
11
19
  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
@@ -16,4 +24,65 @@
16
24
  */
17
25
  --ph-font-shortcut-stack: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
18
26
  Helvetica, Arial, sans-serif;
27
+
28
+ /* Fluid marketing scale — min at 360px, max at ~1280px */
29
+ --ph-type-hero: clamp(2.75rem, 1.6rem + 5.2vw, 5.25rem);
30
+ --ph-type-section: clamp(2rem, 1.35rem + 2.6vw, 3.25rem);
31
+ --ph-type-feature: clamp(1.375rem, 1.15rem + 0.9vw, 1.75rem);
32
+ --ph-type-lead: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
33
+ }
34
+
35
+ /* ── Marketing / landing type ─────────────────────────────────────────────
36
+ Use these on public pages so all five apps share one hero rhythm.
37
+ In-app chrome keeps `font-sans`; do not use hero classes inside the shell. */
38
+
39
+ .ph-hero-title {
40
+ font-family: var(--ph-font-serif-stack);
41
+ font-weight: 400;
42
+ font-size: var(--ph-type-hero);
43
+ line-height: 1.02;
44
+ letter-spacing: -0.02em;
45
+ text-wrap: balance;
46
+ }
47
+
48
+ .ph-section-title {
49
+ font-family: var(--ph-font-serif-stack);
50
+ font-weight: 400;
51
+ font-size: var(--ph-type-section);
52
+ line-height: 1.08;
53
+ letter-spacing: -0.015em;
54
+ text-wrap: balance;
55
+ }
56
+
57
+ /* Feature/card headings stay sans — they sit next to body copy and need weight. */
58
+ .ph-feature-title {
59
+ font-size: var(--ph-type-feature);
60
+ font-weight: 600;
61
+ line-height: 1.25;
62
+ letter-spacing: -0.01em;
63
+ }
64
+
65
+ .ph-lead {
66
+ font-size: var(--ph-type-lead);
67
+ line-height: 1.6;
68
+ max-width: 42ch;
69
+ text-wrap: pretty;
70
+ }
71
+
72
+ .ph-lead-wide {
73
+ max-width: 60ch;
74
+ }
75
+
76
+ /* Eyebrow above a hero — the only place small caps tracking is worth it. */
77
+ .ph-eyebrow {
78
+ font-size: 0.6875rem;
79
+ font-weight: 600;
80
+ letter-spacing: 0.14em;
81
+ text-transform: uppercase;
82
+ }
83
+
84
+ /* Emphasis inside a serif hero: italic, not a third font. */
85
+ .ph-hero-title em,
86
+ .ph-section-title em {
87
+ font-style: italic;
19
88
  }