@sableui/react 0.1.1 → 0.3.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 (137) hide show
  1. package/AGENTS.md +3 -1
  2. package/CHANGELOG.md +120 -0
  3. package/CONTRIBUTING.md +8 -0
  4. package/README.md +1 -0
  5. package/bin/sable-lint.mjs +0 -0
  6. package/bin/sable.mjs +68 -26
  7. package/dist/{_contract-CYScOdf5.d.ts → _contract-o3tUc8Ig.d.ts} +1 -1
  8. package/dist/blocks/index.d.ts +396 -0
  9. package/dist/blocks/index.js +1997 -0
  10. package/dist/chunk-6LCIBMMG.js +4908 -0
  11. package/dist/{chunk-J23ELQQZ.js → chunk-CKNM7KSB.js} +1664 -4270
  12. package/dist/chunk-K6LII3OE.js +5093 -0
  13. package/dist/{chunk-RWP4XBSK.js → chunk-KFZ43RKU.js} +1 -1
  14. package/dist/{chunk-PAOZBZME.js → chunk-NGBDP3BM.js} +1 -1
  15. package/dist/{chunk-5Z5KLOAU.js → chunk-TH563WLW.js} +14 -1
  16. package/dist/{chunk-JI7WJP2L.js → chunk-X276MF2W.js} +5 -0
  17. package/dist/foundations/index.js +1 -1
  18. package/dist/icon/index.js +2 -2
  19. package/dist/icon-sets/reicon.js +1 -1
  20. package/dist/index.d.ts +624 -133
  21. package/dist/index.js +767 -4964
  22. package/dist/ios/index.d.ts +14 -2
  23. package/dist/ios/index.js +10 -9
  24. package/dist/ios/preview.d.ts +11 -1
  25. package/dist/ios/preview.js +14 -9
  26. package/dist/ios/styles.css +26 -6
  27. package/dist/{meta-6dUzgC6M.d.ts → meta-CcE_SeFu.d.ts} +37 -1
  28. package/dist/patterns/index.d.ts +1 -1
  29. package/dist/patterns/index.js +1684 -471
  30. package/dist/presets/index.d.ts +1 -1
  31. package/dist/presets/index.js +1 -1
  32. package/dist/styles.css +238 -40
  33. package/dist/{theme-provider-BWcizhAt.d.ts → theme-provider-BE-KqUG-.d.ts} +1 -1
  34. package/dist/themes/atelier/atelier.css +3 -0
  35. package/dist/themes/atelier/index.d.ts +1 -1
  36. package/dist/themes/base/base.css +34 -4
  37. package/dist/themes/base/index.d.ts +1 -1
  38. package/dist/themes/ember/ember.css +3 -0
  39. package/dist/themes/ember/index.d.ts +1 -1
  40. package/dist/themes/index.d.ts +2 -2
  41. package/dist/themes/index.js +2 -2
  42. package/dist/themes/meridian/index.d.ts +1 -1
  43. package/dist/themes/meridian/meridian.css +10 -5
  44. package/dist/themes/poppy/index.d.ts +1 -1
  45. package/dist/themes/poppy/poppy.css +16 -0
  46. package/dist/themes/prism/index.d.ts +1 -1
  47. package/dist/themes/prism/prism.css +4 -1
  48. package/dist/themes/verdant/index.d.ts +1 -1
  49. package/dist/themes/verdant/verdant.css +7 -2
  50. package/llms/blocks/api-keys-block.md +79 -0
  51. package/llms/blocks/chat-thread-block.md +51 -0
  52. package/llms/blocks/command-palette-block.md +48 -0
  53. package/llms/blocks/cta-band-block.md +62 -0
  54. package/llms/blocks/danger-zone-block.md +69 -0
  55. package/llms/blocks/device-comparison-block.md +91 -0
  56. package/llms/blocks/event-card-block.md +84 -0
  57. package/llms/blocks/faq-block.md +72 -0
  58. package/llms/blocks/feature-grid-block.md +75 -0
  59. package/llms/blocks/feedback-form-block.md +66 -0
  60. package/llms/blocks/goal-progress-block.md +54 -0
  61. package/llms/blocks/hero-block.md +65 -0
  62. package/llms/blocks/invite-team-block.md +61 -0
  63. package/llms/blocks/invoice-history-block.md +84 -0
  64. package/llms/blocks/kpi-sparkline-block.md +57 -0
  65. package/llms/blocks/media-player-block.md +100 -0
  66. package/llms/blocks/newsletter-block.md +64 -0
  67. package/llms/blocks/not-found-block.md +56 -0
  68. package/llms/blocks/notification-list-block.md +63 -0
  69. package/llms/blocks/notification-settings-block.md +54 -0
  70. package/llms/blocks/order-tracking-block.md +62 -0
  71. package/llms/blocks/pricing-card-block.md +82 -0
  72. package/llms/blocks/pricing-table-block.md +129 -0
  73. package/llms/blocks/product-card-block.md +69 -0
  74. package/llms/blocks/profile-card-block.md +103 -0
  75. package/llms/blocks/profile-form-block.md +114 -0
  76. package/llms/blocks/revenue-breakdown-block.md +70 -0
  77. package/llms/blocks/sign-in-block.md +64 -0
  78. package/llms/blocks/sign-up-block.md +78 -0
  79. package/llms/blocks/site-footer-block.md +96 -0
  80. package/llms/blocks/stat-row-block.md +59 -0
  81. package/llms/blocks/steps-block.md +73 -0
  82. package/llms/blocks/task-list-block.md +81 -0
  83. package/llms/blocks/team-members-block.md +91 -0
  84. package/llms/blocks/testimonial-block.md +78 -0
  85. package/llms/blocks/traffic-sources-block.md +63 -0
  86. package/llms/blocks/traffic-trend-block.md +95 -0
  87. package/llms/blocks/upload-list-block.md +66 -0
  88. package/llms/blocks/verify-code-block.md +59 -0
  89. package/llms/blocks/wallet-block.md +84 -0
  90. package/llms/components/area-chart.md +112 -0
  91. package/llms/components/bar-chart.md +131 -0
  92. package/llms/components/bubble.md +5 -5
  93. package/llms/components/button.md +1 -1
  94. package/llms/components/card.md +2 -2
  95. package/llms/components/checkbox-card.md +1 -1
  96. package/llms/components/context-card.md +2 -2
  97. package/llms/components/context-menu.md +1 -1
  98. package/llms/components/date-tile.md +79 -0
  99. package/llms/components/dialog.md +1 -1
  100. package/llms/components/empty-state.md +4 -4
  101. package/llms/components/entity.md +5 -3
  102. package/llms/components/fieldset.md +1 -1
  103. package/llms/components/kbd.md +18 -6
  104. package/llms/components/line-chart.md +101 -0
  105. package/llms/components/menu.md +1 -1
  106. package/llms/components/{dots-menu.md → overflow-menu.md} +9 -9
  107. package/llms/components/pie-chart.md +103 -0
  108. package/llms/components/pill.md +1 -1
  109. package/llms/components/radar-chart.md +106 -0
  110. package/llms/components/radial-chart.md +102 -0
  111. package/llms/components/segmented-bar.md +102 -0
  112. package/llms/components/settings-menu.md +2 -2
  113. package/llms/components/side-nav.md +1 -1
  114. package/llms/components/skeleton.md +1 -1
  115. package/llms/components/sparkline.md +80 -0
  116. package/llms/components/table.md +1 -1
  117. package/llms/components/theme-selector.md +1 -1
  118. package/llms/foundations/shape.md +1 -1
  119. package/llms/patterns/auth-page.md +132 -42
  120. package/llms/patterns/brand-landing-page.md +271 -175
  121. package/llms/patterns/chat-panel.md +120 -39
  122. package/llms/patterns/dashboard-page.md +276 -65
  123. package/llms/patterns/feed-page.md +245 -64
  124. package/llms/patterns/landing-page.md +473 -75
  125. package/llms/patterns/list-detail-page.md +377 -68
  126. package/llms/patterns/settings-page.md +268 -67
  127. package/llms/reference/token-intent.md +4 -2
  128. package/llms/reference/utilities.md +20 -5
  129. package/llms/tasks/building-an-ios-prototype.md +4 -1
  130. package/llms/tasks/choosing-a-component.md +2 -2
  131. package/llms-full.txt +6428 -892
  132. package/llms.txt +67 -16
  133. package/package.json +5 -1
  134. package/registry.json +3217 -552
  135. package/targets/ios.json +88 -18
  136. package/llms/components/description.md +0 -96
  137. package/dist/{chunk-L6Y46C62.js → chunk-MXJX3NZI.js} +1 -1
@@ -1,79 +1,113 @@
1
1
  # BrandLandingPage
2
2
 
3
- High-fidelity brand/product landing page: pill navigation, editorial hero type, a dark product scene, calm status tones, CTA pair, feature cards, metrics, and a complete branded footer.
3
+ High-fidelity brand/product landing page: pill navigation, editorial hero type, a dark product scene, a value section, a how-it-works sequence, a customer story with outcomes, a closing CTA band, and a complete branded footer.
4
4
 
5
5
  **Intent:** Use this for a polished product marketing route that still needs to show a credible app surface. It is warmer and more tactile than the canonical LandingPage, but avoids trend-driven neon and generic hype cues.
6
6
 
7
7
  ## Notes
8
8
 
9
- - One display headline owns the first viewport; supporting copy stays in body-lg at prose measure.
9
+ - The story runs promise → product → value → process → proof → ask: hero, product scene, 'Why Cove' value cards, a three-step how-it-works list, a customer story with outcome figures, then one closing CTA. Each section adds new evidence; no number is repeated from the product scene.
10
+ - One display headline owns the first viewport; supporting copy stays in body-lg at prose measure. Section headings are heading-1 under a `text-overline` eyebrow.
10
11
  - The nav spends one compact pill surface, with a clear brand signal and two primary paths: sign in and request access.
11
- - The product scene uses overlay tokens for a stable dark media surface, then semantic tones for status and chart signals.
12
- - The footer closes the page with brand reassurance, a three-column sitemap, a digest signup, operational mini-metrics, and legal links.
13
- - Every surface outside the product scene is a real Card (feature, metric and digest cards); status marks are StatusDot. The scene's nested panels take `rounded-concentric-xl/<inset>` from the shell's radius, so the corners stay parallel at any radius preset.
14
- - Radius and shadow are theme-controlled. In Cove the same rounded-lg/xl classes read larger and softer; in other themes the structure still holds.
15
- - Color is intentionally broad: porcelain/plum/lavender/blue/mint/saffron/coral through semantic roles, not a one-note purple gradient.
12
+ - The product scene and the closing CTA band are dark islands: a `dark` class on the wrapper re-scopes every semantic token, so surfaces, muted ink, Badge tones and Buttons take the theme's own dark values in either page mode. Never fake a dark panel with overlay ink at reduced opacity — status tones tuned for a light page vanish on it.
13
+ - The scene is a picture of the product: `aria-hidden` + `inert` keep its sample button and figures out of the tab order and the outline. On narrow screens it drops the side column and keeps the signal map, so it scales instead of stacking into a second page.
14
+ - The chart keeps past weeks on the quiet `secondary` fill and gives the current week the one accent, so the signal reads at a glance.
15
+ - Value cards are real Cards with a neutral `sable-well` icon tile; the customer story is a Card rendered as a figure, with outcome figures split by Separator. The scene's nested panels take `rounded-concentric-xl/<inset>` from the shell's radius, so the corners stay parallel at any radius preset.
16
+ - The footer closes the page with brand reassurance, a plain status Badge, a three-column sitemap (three columns at every width), a digest signup, and legal links.
17
+ - All figures, names and the testimonial are sample content; replace them with real, verifiable claims.
16
18
 
17
19
  ## Accessibility
18
20
 
19
21
  - The brand nav is a labeled nav landmark with real links and visible text.
22
+ - Each content section is a labelled region (by its h2, or aria-label for the customer story); the decorative product scene is hidden from assistive tech and inert.
23
+ - The how-it-works steps are an ordered list; the testimonial is a figure with a blockquote and a figcaption naming the speaker.
20
24
  - The footer is a real footer landmark with a labeled footer nav, visible link text, and a labeled email field.
21
- - TextReveal preserves the full headline as one accessible label and honors reduced-motion policy.
22
- - Status dots are paired with visible text labels so color is never the only signal.
25
+ - TextReveal preserves the full headline as one accessible label and honors reduced-motion policy; Reveal shows the value cards immediately when motion is off.
26
+ - Status dots and the status Badge are paired with visible text labels so color is never the only signal.
23
27
 
24
28
  ## Source
25
29
 
26
30
  ```tsx
27
- import { Badge, Button, Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle, Icon, Input, Region, Row, Stack, StatusDot, TextReveal } from "@sableui/react"
31
+ import { Avatar, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Grid, Icon, Input, Region, Reveal, Row, Separator, Stack, StatusDot, TextReveal } from "@sableui/react"
28
32
 
29
- const navItems = ["Platform", "Signals", "Security", "Company"]
33
+ const navItems = [
34
+ { label: "Platform", href: "#platform" },
35
+ { label: "How it works", href: "#how-it-works" },
36
+ { label: "Customers", href: "#customers" },
37
+ { label: "Pricing", href: "/pricing" },
38
+ ]
30
39
 
31
- const metrics = [
32
- { label: "Checks cleared", value: "1.8M", detail: "in the last 30 days" },
33
- { label: "Review time", value: "42s", detail: "median approval path" },
34
- { label: "Spaces online", value: "284", detail: "across active teams" },
40
+ const spaces = [
41
+ { name: "Waypoint", value: "98.4%", label: "clear routes" },
42
+ { name: "Fielddesk", value: "12", label: "open holds" },
43
+ { name: "Archive", value: "4.8k", label: "sealed records" },
35
44
  ]
36
45
 
37
- const workflow = [
46
+ const routes = [
38
47
  { label: "Intake", state: "Open", tone: "info" as const },
39
48
  { label: "Review", state: "Live", tone: "edition" as const },
40
49
  { label: "Archive", state: "Safe", tone: "success" as const },
41
50
  ]
42
51
 
52
+ // Weekly approvals: past weeks recede, the current week carries the signal.
43
53
  const bars = [
44
- { height: "38%", tone: "bg-tone-info" },
45
- { height: "56%", tone: "bg-tone-edition" },
46
- { height: "44%", tone: "bg-tone-standard" },
47
- { height: "68%", tone: "bg-success" },
48
- { height: "52%", tone: "bg-tone-info" },
49
- { height: "78%", tone: "bg-highlight" },
50
- { height: "60%", tone: "bg-tone-edition" },
51
- { height: "86%", tone: "bg-success" },
52
- { height: "64%", tone: "bg-tone-standard" },
54
+ { week: "w1", height: "38%", current: false },
55
+ { week: "w2", height: "56%", current: false },
56
+ { week: "w3", height: "44%", current: false },
57
+ { week: "w4", height: "68%", current: false },
58
+ { week: "w5", height: "52%", current: false },
59
+ { week: "w6", height: "78%", current: false },
60
+ { week: "w7", height: "60%", current: false },
61
+ { week: "w8", height: "72%", current: false },
62
+ { week: "w9", height: "88%", current: true },
53
63
  ]
54
64
 
55
- const features = [
65
+ const sceneMetrics = [
66
+ { label: "Cleared", value: "1.8M", detail: "last 30 days" },
67
+ { label: "Review", value: "42s", detail: "median path" },
68
+ { label: "Spaces", value: "284", detail: "active teams" },
69
+ ]
70
+
71
+ const values = [
56
72
  {
57
73
  icon: "lock" as const,
58
74
  title: "Private by default",
59
- body: "Workspace roles, approval trails, and handoff history stay clear without turning the interface into compliance fog.",
75
+ body: "Roles, approvals, and handoff history stay with the people who need them. No shared inboxes, no forwarded screenshots.",
60
76
  },
61
77
  {
62
- icon: "layout" as const,
63
- title: "Brand and product together",
64
- body: "Editorial sections and dense console views share the same semantic tokens, radius, and motion contract.",
78
+ icon: "bell" as const,
79
+ title: "Signals before surprises",
80
+ body: "Cove watches every route and surfaces stalled reviews and expiring approvals while there is still time to act.",
65
81
  },
66
82
  {
67
- icon: "circle-check" as const,
68
- title: "Calm confidence",
69
- body: "Large type, tactile controls, and focused status tones make complex work feel understandable on first pass.",
83
+ icon: "clock" as const,
84
+ title: "A trail for every decision",
85
+ body: "Each approval keeps its context, reviewer, and timestamp, so an audit takes an afternoon instead of a quarter.",
70
86
  },
71
87
  ]
72
88
 
73
- const reviews = [
74
- { name: "Waypoint", value: "98.4%", label: "clear routes" },
75
- { name: "Fielddesk", value: "12", label: "open holds" },
76
- { name: "Archive", value: "4.8k", label: "sealed records" },
89
+ const steps = [
90
+ {
91
+ number: "01",
92
+ title: "Connect your spaces",
93
+ body: "Bring teams, vendors, and record stores into one workspace, with roles that mirror how you already work.",
94
+ },
95
+ {
96
+ number: "02",
97
+ title: "Route every approval",
98
+ body: "Requests follow the path you define, with reviewers, deadlines, and escalation built in from the start.",
99
+ },
100
+ {
101
+ number: "03",
102
+ title: "Seal the record",
103
+ body: "Approved work is archived with its full context and is ready for review the moment it closes.",
104
+ },
105
+ ]
106
+
107
+ const outcomes = [
108
+ { value: "3.2×", label: "faster approvals in the first quarter" },
109
+ { value: "68%", label: "fewer follow-ups on handoffs" },
110
+ { value: "1 day", label: "to prepare a quarterly audit" },
77
111
  ]
78
112
 
79
113
  const footerGroups = [
@@ -81,9 +115,9 @@ const footerGroups = [
81
115
  title: "Platform",
82
116
  links: [
83
117
  { label: "Overview", href: "#platform" },
84
- { label: "Signals", href: "#signals" },
85
- { label: "Approvals", href: "#approvals" },
86
- { label: "Records", href: "#records" },
118
+ { label: "Signals", href: "/signals" },
119
+ { label: "Approvals", href: "/approvals" },
120
+ { label: "Records", href: "/records" },
87
121
  ],
88
122
  },
89
123
  {
@@ -91,7 +125,7 @@ const footerGroups = [
91
125
  links: [
92
126
  { label: "About", href: "/about" },
93
127
  { label: "Security", href: "/security" },
94
- { label: "Customers", href: "/customers" },
128
+ { label: "Customers", href: "#customers" },
95
129
  { label: "Careers", href: "/careers" },
96
130
  ],
97
131
  },
@@ -106,10 +140,10 @@ const footerGroups = [
106
140
  },
107
141
  ]
108
142
 
109
- const footerSignals = [
110
- { label: "Uptime", value: "99.98%" },
111
- { label: "Regions", value: "12" },
112
- { label: "Response", value: "42s" },
143
+ const legalLinks = [
144
+ { label: "Privacy", href: "/privacy" },
145
+ { label: "Terms", href: "/terms" },
146
+ { label: "Contact", href: "/contact" },
113
147
  ]
114
148
 
115
149
  export function BrandLandingPage() {
@@ -130,8 +164,8 @@ export function BrandLandingPage() {
130
164
  <div className="hidden lg:block">
131
165
  <Row gap={1}>
132
166
  {navItems.map((item) => (
133
- <Button key={item} variant="ghost" size="sm" render={<a href={`#${item.toLowerCase()}`} />}>
134
- {item}
167
+ <Button key={item.label} variant="ghost" size="sm" render={<a href={item.href} />}>
168
+ {item.label}
135
169
  </Button>
136
170
  ))}
137
171
  </Row>
@@ -149,16 +183,16 @@ export function BrandLandingPage() {
149
183
  </header>
150
184
 
151
185
  <main>
152
- <Region as="section" max="wide" className="pb-16 pt-14 sm:pt-20 lg:pb-24">
153
- <div className="grid items-center gap-10 lg:grid-cols-[0.92fr_1.08fr]">
154
- <Stack gap={4} className="max-w-3xl">
186
+ <Region as="section" max="wide" className="pb-20 pt-14 sm:pt-20 lg:pb-28">
187
+ <div className="grid items-center gap-12 lg:grid-cols-[1fr_1.1fr] lg:gap-10">
188
+ <Stack gap={3} className="max-w-2xl">
155
189
  <Badge appearance="outline" icon={<Icon name="lock" className="text-sm" />}>
156
190
  Private operations, made legible
157
191
  </Badge>
158
192
  <TextReveal
159
193
  as="h1"
160
- text="A calmer command center for high-trust digital work"
161
- className="max-w-4xl text-balance text-display-xl sm:text-display-3xl"
194
+ text="A calmer command center for high-trust work"
195
+ className="text-balance text-display-lg sm:text-display-2xl"
162
196
  once
163
197
  />
164
198
  <p className="max-w-(--measure-prose) text-body-lg text-muted-foreground">
@@ -166,89 +200,96 @@ export function BrandLandingPage() {
166
200
  surface: approvals, signals, records, and handoffs in one
167
201
  understandable flow.
168
202
  </p>
169
- <Row gap={2} wrap>
203
+ <Row gap={2} wrap className="pt-3">
170
204
  <Button size="cta" render={<a href="/demo" />}>
171
205
  Book a walkthrough
172
206
  </Button>
173
207
  <Button size="cta" variant="outline" render={<a href="#platform" />}>
174
- Explore platform
208
+ Explore the platform
175
209
  </Button>
176
210
  </Row>
177
211
  </Stack>
178
212
 
179
- <div className="relative">
180
- {/* Nested surfaces take concentric corners: each level's radius is
181
- the shell's xl minus every inset between it and the shell edge. */}
182
- <div className="overflow-hidden rounded-xl border border-border-floating bg-overlay p-3 text-overlay-foreground shadow-xl">
183
- <div className="rounded-concentric-xl/3 border border-overlay-foreground/10 bg-overlay-foreground/8">
184
- <div className="flex items-center justify-between border-b border-overlay-foreground/10 px-4 py-3">
213
+ {/* The product scene is a dark island: `dark` re-scopes every
214
+ semantic token, so its surfaces, muted ink and status tones
215
+ are the theme's own dark values in either page mode. It is a
216
+ picture of the product, so it stays out of the tab order and
217
+ the accessibility tree; the hero copy carries its meaning. */}
218
+ <div className="dark" aria-hidden inert>
219
+ <div className="overflow-hidden rounded-xl border border-border-floating bg-popover p-3 text-popover-foreground shadow-xl">
220
+ {/* Nested surfaces take concentric corners: each level's radius is
221
+ the shell's xl minus every inset between it and the shell edge. */}
222
+ <div className="rounded-concentric-xl/3 border border-border bg-card">
223
+ <div className="flex items-center justify-between border-b border-border px-4 py-3">
185
224
  <Row gap={1}>
186
225
  <StatusDot tone="warning" />
187
226
  <StatusDot tone="edition" />
188
227
  <StatusDot tone="success" />
189
228
  </Row>
190
- <span className="text-label-sm text-overlay-foreground/70">Live workspace</span>
229
+ <span className="text-label-sm text-muted-foreground">Live workspace</span>
191
230
  </div>
192
231
  <div className="grid gap-3 p-3 md:grid-cols-[0.7fr_1.3fr]">
193
- <div className="space-y-3">
194
- <div className="rounded-concentric-xl/6 border border-overlay-foreground/10 bg-overlay-foreground/8 p-4">
195
- <p className="text-label-sm text-overlay-foreground/60">Spaces</p>
232
+ <div className="space-y-3 max-md:hidden">
233
+ <div className="rounded-concentric-xl/6 border border-border bg-background p-4">
234
+ <p className="text-label-sm text-muted-foreground">Spaces</p>
196
235
  <div className="mt-4 space-y-2">
197
- {reviews.map((review) => (
198
- <div key={review.name} className="rounded-concentric-xl/10 bg-overlay p-3">
236
+ {spaces.map((space) => (
237
+ <div key={space.name} className="rounded-concentric-xl/10 bg-card p-3">
199
238
  <Row justify="between">
200
- <span className="text-title-sm">{review.name}</span>
201
- <span className="text-mono-sm text-overlay-foreground">{review.value}</span>
239
+ <span className="text-title-sm">{space.name}</span>
240
+ <span className="text-mono-sm">{space.value}</span>
202
241
  </Row>
203
- <p className="mt-1 text-body-xs text-overlay-foreground/60">{review.label}</p>
242
+ <p className="mt-1 text-body-xs text-muted-foreground">{space.label}</p>
204
243
  </div>
205
244
  ))}
206
245
  </div>
207
246
  </div>
208
- <div className="rounded-concentric-xl/6 border border-overlay-foreground/10 bg-overlay-foreground/8 p-4">
247
+ <div className="rounded-concentric-xl/6 border border-border bg-background p-4">
209
248
  <Row justify="between">
210
249
  <span className="text-title-sm">Route status</span>
211
- <Badge tone="success" size="sm">Healthy</Badge>
250
+ <Badge tone="success" size="sm" dot>
251
+ Healthy
252
+ </Badge>
212
253
  </Row>
213
254
  <div className="mt-4 space-y-2">
214
- {workflow.map((item) => (
215
- <Row key={item.label} justify="between" className="rounded-full bg-overlay px-3 py-2">
255
+ {routes.map((route) => (
256
+ <Row key={route.label} justify="between" className="rounded-full bg-card px-3 py-2">
216
257
  <Row gap={1}>
217
- <StatusDot tone={item.tone} />
218
- <span className="text-body-sm">{item.label}</span>
258
+ <StatusDot tone={route.tone} />
259
+ <span className="text-body-sm">{route.label}</span>
219
260
  </Row>
220
- <span className="text-label-sm text-overlay-foreground/60">{item.state}</span>
261
+ <span className="text-label-sm text-muted-foreground">{route.state}</span>
221
262
  </Row>
222
263
  ))}
223
264
  </div>
224
265
  </div>
225
266
  </div>
226
267
 
227
- <div className="rounded-concentric-xl/6 border border-overlay-foreground/10 bg-overlay-foreground/8 p-4">
228
- <Row justify="between" className="border-b border-overlay-foreground/10 pb-4">
268
+ <div className="rounded-concentric-xl/6 border border-border bg-background p-4">
269
+ <Row justify="between" className="border-b border-border pb-4">
229
270
  <div>
230
- <p className="text-label-sm text-overlay-foreground/60">Signal map</p>
231
- <h2 className="mt-1 text-heading-3">Every approval path in view</h2>
271
+ <p className="text-label-sm text-muted-foreground">Signal map</p>
272
+ <p className="mt-1 text-heading-4 sm:text-heading-3">Every approval path in view</p>
232
273
  </div>
233
274
  <Button variant="secondary" size="sm">Review</Button>
234
275
  </Row>
235
- <div className="mt-6 grid min-h-72 grid-rows-[1fr_auto] gap-5">
236
- <div className="grid grid-cols-9 items-end gap-2 rounded-concentric-xl/10 bg-overlay p-4">
237
- {bars.map((bar, index) => (
238
- <div key={`${bar.tone}-${index}`} className="flex h-56 items-end">
276
+ <div className="mt-5 grid gap-4 sm:mt-6 sm:gap-5">
277
+ <div className="grid grid-cols-9 items-end gap-1.5 rounded-concentric-xl/10 bg-card p-4 sm:gap-2">
278
+ {bars.map((bar) => (
279
+ <div key={bar.week} className="flex h-36 items-end sm:h-56">
239
280
  <div
240
- className={`w-full rounded-full ${bar.tone}`}
281
+ className={`w-full rounded-full ${bar.current ? "bg-success" : "bg-secondary"}`}
241
282
  style={{ height: bar.height }}
242
283
  />
243
284
  </div>
244
285
  ))}
245
286
  </div>
246
- <div className="grid gap-2 sm:grid-cols-3">
247
- {metrics.map((metric) => (
248
- <div key={metric.label} className="rounded-concentric-xl/10 border border-overlay-foreground/10 bg-overlay p-3">
249
- <p className="text-label-sm text-overlay-foreground/60">{metric.label}</p>
250
- <p className="mt-2 text-heading-3">{metric.value}</p>
251
- <p className="mt-1 text-body-xs text-overlay-foreground/60">{metric.detail}</p>
287
+ <div className="grid grid-cols-3 gap-2">
288
+ {sceneMetrics.map((metric) => (
289
+ <div key={metric.label} className="rounded-concentric-xl/10 border border-border bg-card p-3">
290
+ <p className="truncate text-label-sm text-muted-foreground">{metric.label}</p>
291
+ <p className="mt-2 text-heading-4 sm:text-heading-3">{metric.value}</p>
292
+ <p className="mt-1 text-body-xs text-muted-foreground max-sm:hidden">{metric.detail}</p>
252
293
  </div>
253
294
  ))}
254
295
  </div>
@@ -261,54 +302,136 @@ export function BrandLandingPage() {
261
302
  </div>
262
303
  </Region>
263
304
 
264
- <section id="platform" className="border-y border-border bg-muted/40 py-14">
305
+ <section id="platform" aria-labelledby="brand-platform-title" className="border-y border-border bg-muted/40 py-20 lg:py-28">
265
306
  <Region max="wide">
266
- <div className="grid gap-5 lg:grid-cols-[0.8fr_1.2fr]">
267
- <Stack gap={3}>
268
- <Badge>Design mood</Badge>
269
- <h2 className="text-heading-1">Marketing warmth, product discipline.</h2>
270
- <p className="max-w-(--measure-prose) text-body-md text-muted-foreground">
271
- The page uses a pill nav, tactile surfaces, soft status tones, and
272
- slower ease-out movement. It stays broad in color so it does not
273
- collapse into purple-brand sameness.
307
+ <Stack gap={6}>
308
+ <Stack gap={2} className="max-w-2xl">
309
+ <p className="text-overline text-muted-foreground">Why Cove</p>
310
+ <h2 id="brand-platform-title" className="text-balance text-heading-1">
311
+ One private workspace for the decisions that matter.
312
+ </h2>
313
+ <p className="max-w-(--measure-prose) text-body-lg text-muted-foreground">
314
+ Most operations work lives in threads, spreadsheets, and memory.
315
+ Cove gives it a home: every request routed, every signal visible,
316
+ every outcome on the record.
274
317
  </p>
275
318
  </Stack>
276
- <div className="grid gap-3 md:grid-cols-3">
277
- {features.map((feature) => (
278
- <Card key={feature.title} render={<article />} className="h-full">
279
- <CardContent>
280
- <span className="grid size-10 place-items-center rounded-md bg-highlight text-highlight-foreground">
281
- <Icon name={feature.icon} className="text-xl" />
282
- </span>
283
- <h3 className="mt-5 text-title-lg">{feature.title}</h3>
284
- <p className="mt-2 text-body-sm text-muted-foreground">{feature.body}</p>
285
- </CardContent>
286
- </Card>
287
- ))}
288
- </div>
289
- </div>
319
+ <Reveal>
320
+ <Grid minItemWidth="calc(var(--spacing) * 64)" gap={2}>
321
+ {values.map((value) => (
322
+ <Card key={value.title} render={<article />} className="h-full">
323
+ <CardContent className="flex flex-col gap-2">
324
+ <span className="mb-4 grid size-11 place-items-center rounded-md border border-border sable-well">
325
+ <Icon name={value.icon} className="text-xl" />
326
+ </span>
327
+ <h3 className="text-title-lg">{value.title}</h3>
328
+ <p className="text-body-sm text-muted-foreground">{value.body}</p>
329
+ </CardContent>
330
+ </Card>
331
+ ))}
332
+ </Grid>
333
+ </Reveal>
334
+ </Stack>
290
335
  </Region>
291
336
  </section>
292
337
 
293
- <Region as="section" max="wide" className="py-14">
294
- <div className="grid gap-3 md:grid-cols-3">
295
- {metrics.map((metric) => (
296
- <Card key={metric.label}>
297
- <CardContent>
298
- <p className="text-label-md text-muted-foreground">{metric.label}</p>
299
- <p className="mt-3 text-display-lg">{metric.value}</p>
300
- <p className="mt-1 text-body-sm text-muted-foreground">{metric.detail}</p>
338
+ <Region as="section" id="how-it-works" aria-labelledby="brand-steps-title" max="wide" className="py-20 lg:py-28">
339
+ <div className="grid gap-12 lg:grid-cols-[1fr_2fr] lg:gap-16">
340
+ <Stack gap={2} className="max-w-md">
341
+ <p className="text-overline text-muted-foreground">How it works</p>
342
+ <h2 id="brand-steps-title" className="text-balance text-heading-1">
343
+ From request to sealed record.
344
+ </h2>
345
+ <p className="text-body-md text-muted-foreground">
346
+ Teams are usually live within a week. Cove adapts to the routes
347
+ you already run instead of asking you to start over.
348
+ </p>
349
+ <div className="pt-3">
350
+ <Button variant="outline" iconEnd={<Icon name="arrow-right" />} render={<a href="/guides/rollout" />}>
351
+ Read the rollout guide
352
+ </Button>
353
+ </div>
354
+ </Stack>
355
+ <ol className="grid gap-10 sm:grid-cols-3 sm:gap-6">
356
+ {steps.map((step) => (
357
+ <li key={step.number} className="flex flex-col gap-2 border-t border-border-strong pt-6">
358
+ <span className="text-mono-sm text-muted-foreground">{step.number}</span>
359
+ <h3 className="mt-3 text-title-lg sm:mt-6">{step.title}</h3>
360
+ <p className="text-body-sm text-muted-foreground">{step.body}</p>
361
+ </li>
362
+ ))}
363
+ </ol>
364
+ </div>
365
+ </Region>
366
+
367
+ <Region as="section" id="customers" aria-label="Customer story" max="wide" className="pb-20 lg:pb-28">
368
+ <Card render={<figure />}>
369
+ <div className="grid lg:grid-cols-[1.5fr_1fr]">
370
+ <CardContent className="flex flex-col justify-between gap-10 sm:p-10">
371
+ <Stack gap={3}>
372
+ <p className="text-overline text-muted-foreground">Customer story</p>
373
+ <blockquote className="text-balance text-heading-3 sm:text-heading-2">
374
+ “We used to chase approvals across four tools. Now every request
375
+ has an owner, a deadline, and a record, and our auditors stopped
376
+ asking for screenshots.”
377
+ </blockquote>
378
+ </Stack>
379
+ <figcaption className="flex items-center gap-3">
380
+ <Avatar size="lg" fallback="MO" />
381
+ <div>
382
+ <p className="text-title-sm">Maya Okafor</p>
383
+ <p className="text-body-sm text-muted-foreground">Head of operations, Fielddesk</p>
384
+ </div>
385
+ </figcaption>
386
+ </CardContent>
387
+ <div className="border-border max-lg:border-t lg:border-s">
388
+ <CardContent className="flex h-full flex-col justify-center gap-6 sm:p-10">
389
+ {outcomes.map((outcome, index) => (
390
+ <Stack key={outcome.label} gap={3}>
391
+ {index > 0 && <Separator />}
392
+ <div>
393
+ <p className="text-heading-1 sm:text-display-lg">{outcome.value}</p>
394
+ <p className="mt-1 text-body-sm text-muted-foreground">{outcome.label}</p>
395
+ </div>
396
+ </Stack>
397
+ ))}
301
398
  </CardContent>
302
- </Card>
303
- ))}
399
+ </div>
400
+ </div>
401
+ </Card>
402
+ </Region>
403
+
404
+ <Region as="section" aria-labelledby="brand-cta-title" max="wide" className="pb-20 lg:pb-28">
405
+ <div className="dark">
406
+ <div className="rounded-xl border border-border bg-card px-6 py-12 text-card-foreground sm:px-12 sm:py-16">
407
+ <div className="flex flex-col gap-8 lg:flex-row lg:items-end lg:justify-between">
408
+ <Stack gap={3} className="max-w-2xl">
409
+ <h2 id="brand-cta-title" className="text-balance text-heading-1">
410
+ See your own approval paths in Cove.
411
+ </h2>
412
+ <p className="text-body-lg text-muted-foreground">
413
+ A 30-minute walkthrough with your routes, your roles, and your
414
+ records. No slides.
415
+ </p>
416
+ </Stack>
417
+ <Row gap={2} wrap>
418
+ <Button size="cta" render={<a href="/demo" />}>
419
+ Book a walkthrough
420
+ </Button>
421
+ <Button size="cta" variant="ghost" render={<a href="/pricing" />}>
422
+ View pricing
423
+ </Button>
424
+ </Row>
425
+ </div>
426
+ </div>
304
427
  </div>
305
428
  </Region>
306
429
  </main>
307
430
 
308
431
  <footer className="border-t border-border bg-muted/35">
309
- <Region max="wide" className="py-10 sm:py-12">
310
- <div className="grid gap-8 lg:grid-cols-[1fr_1.35fr_1fr]">
311
- <Stack gap={3} className="max-w-md">
432
+ <Region max="wide" className="py-12 sm:py-16">
433
+ <div className="grid gap-10 lg:grid-cols-[1fr_1.35fr_1fr] lg:gap-8">
434
+ <Stack gap={4} className="max-w-sm">
312
435
  <a href="/" className="flex w-fit items-center gap-2 rounded-full motion-interactive motion-press">
313
436
  <span className="grid size-9 place-items-center rounded-full bg-primary text-primary-foreground">
314
437
  <Icon name="sparkles" className="text-sm" />
@@ -319,20 +442,15 @@ export function BrandLandingPage() {
319
442
  A calm operating surface for teams that need trust, speed, and
320
443
  context without the noise.
321
444
  </p>
322
- <Row gap={1} wrap>
323
- <Badge size="sm" icon={<Icon name="lock" />}>
324
- Private
325
- </Badge>
326
- <Badge tone="success" size="sm" icon={<Icon name="circle-check" />}>
327
- Live
328
- </Badge>
329
- </Row>
445
+ <Badge appearance="plain" tone="success" dot>
446
+ All systems normal
447
+ </Badge>
330
448
  </Stack>
331
449
 
332
- <nav aria-label="Footer" className="grid gap-6 sm:grid-cols-3">
450
+ <nav aria-label="Footer" className="grid grid-cols-3 gap-6">
333
451
  {footerGroups.map((group) => (
334
452
  <div key={group.title}>
335
- <h2 className="text-label-md text-muted-foreground">{group.title}</h2>
453
+ <h2 className="text-label-md">{group.title}</h2>
336
454
  <ul className="mt-3 space-y-1">
337
455
  {group.links.map((link) => (
338
456
  <li key={link.label}>
@@ -349,22 +467,17 @@ export function BrandLandingPage() {
349
467
  ))}
350
468
  </nav>
351
469
 
352
- <Card>
470
+ <Card className="h-fit">
353
471
  <CardHeader>
354
472
  {/* CardTitle carries the type; the h2 inside it keeps the outline. */}
355
473
  <CardTitle>
356
- <h2>Signal digest</h2>
474
+ <h2>The Cove digest</h2>
357
475
  </CardTitle>
358
476
  <CardDescription>
359
- One weekly note on trusted workflows and product releases.
477
+ One note a month on trusted workflows and product releases.
360
478
  </CardDescription>
361
- <CardAction>
362
- <span className="grid size-9 place-items-center rounded-full bg-highlight text-highlight-foreground">
363
- <Icon name="sparkles" className="text-sm" />
364
- </span>
365
- </CardAction>
366
479
  </CardHeader>
367
- <CardContent className="flex flex-col gap-4">
480
+ <CardContent>
368
481
  <form action="/newsletter" className="grid gap-2 sm:grid-cols-[1fr_auto]">
369
482
  <label htmlFor="brand-footer-email" className="sr-only">
370
483
  Work email
@@ -377,42 +490,25 @@ export function BrandLandingPage() {
377
490
  placeholder="you@company.com"
378
491
  />
379
492
  <Button type="submit" className="w-full sm:w-auto">
380
- Join
493
+ Subscribe
381
494
  </Button>
382
495
  </form>
383
- <div className="grid grid-cols-3 gap-2">
384
- {footerSignals.map((signal) => (
385
- <div key={signal.label} className="rounded-md bg-muted p-3">
386
- <p className="text-mono-sm">{signal.value}</p>
387
- <p className="mt-1 text-caption text-muted-foreground">{signal.label}</p>
388
- </div>
389
- ))}
390
- </div>
391
496
  </CardContent>
392
497
  </Card>
393
498
  </div>
394
499
 
395
- <div className="mt-10 flex flex-col gap-3 border-t border-border pt-5 text-caption text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
500
+ <div className="mt-12 flex flex-col gap-3 border-t border-border pt-6 text-caption text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
396
501
  <p>© 2026 Cove. All rights reserved.</p>
397
- <Row gap={3} wrap>
398
- <a
399
- href="/privacy"
400
- className="flex min-h-9 min-w-9 items-center motion-interactive hover:text-foreground"
401
- >
402
- Privacy
403
- </a>
404
- <a
405
- href="/terms"
406
- className="flex min-h-9 min-w-9 items-center motion-interactive hover:text-foreground"
407
- >
408
- Terms
409
- </a>
410
- <a
411
- href="/contact"
412
- className="flex min-h-9 min-w-9 items-center motion-interactive hover:text-foreground"
413
- >
414
- Contact
415
- </a>
502
+ <Row gap={4} wrap>
503
+ {legalLinks.map((link) => (
504
+ <a
505
+ key={link.label}
506
+ href={link.href}
507
+ className="flex min-h-9 min-w-9 items-center motion-interactive hover:text-foreground"
508
+ >
509
+ {link.label}
510
+ </a>
511
+ ))}
416
512
  </Row>
417
513
  </div>
418
514
  </Region>