@turquoisehealth/pit-viper 2.179.1-dev.0 → 2.181.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 (33) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +8 -2
  2. package/claude-plugin/.mcp.json +8 -0
  3. package/claude-plugin/CLAUDE.md +71 -250
  4. package/claude-plugin/README.md +123 -69
  5. package/claude-plugin/skills/pit-viper/SKILL.md +180 -0
  6. package/claude-plugin/skills/pit-viper/references/design-language.md +80 -0
  7. package/claude-plugin/skills/pit-viper/references/design-rules.md +254 -0
  8. package/claude-plugin/skills/pit-viper/references/html-patterns.md +451 -0
  9. package/claude-plugin/skills/pit-viper/references/layout-patterns.md +359 -0
  10. package/claude-plugin/skills/pit-viper/references/patterns-core.md +97 -0
  11. package/claude-plugin/skills/pit-viper/references/theme-guide.md +149 -0
  12. package/claude-plugin/skills/pit-viper/references/vue-guidelines.md +513 -0
  13. package/package.json +3 -3
  14. package/pv-components/dist/stats/vue/base/stats.html +1 -1
  15. package/pv-components/dist/stats/vue/visualizations/stats.html +1 -1
  16. package/pv-components/dist/stats/web/pv-menu-stats.html +1 -1
  17. package/pv-components/dist/stats/web/pv-multi-select-button-stats.html +1 -1
  18. package/pv-components/dist/stats/web/pv-query-builder-input-stats.html +1 -1
  19. package/pv-components/dist/stats/web/pv-select-button-stats.html +1 -1
  20. package/pv-components/dist/vue/base/pv-components-base.mjs +2 -2
  21. package/pv-components/dist/vue/base/pv-components-base.mjs.map +1 -1
  22. package/pv-components/dist/vue/visualizations/components/tables/PvDataTable/filters/filterHelpers.d.ts +1 -1
  23. package/pv-components/dist/vue/visualizations/pv-components-visualizations.mjs +5 -5
  24. package/pv-components/dist/vue/visualizations/pv-components-visualizations.mjs.map +1 -1
  25. package/pv-components/dist/web/components/pv-menu/pv-menu.js +2 -2
  26. package/pv-components/dist/web/components/pv-multi-select-button/pv-multi-select-button.js +2 -2
  27. package/pv-components/dist/web/components/pv-query-builder-input/pv-query-builder-input.js +2 -2
  28. package/pv-components/dist/web/components/pv-select-button/pv-select-button.js +2 -2
  29. package/pv-components/dist/web/pv-components.iife.js +1 -1
  30. package/pv-components/dist/web/pv-components.iife.js.map +1 -1
  31. package/claude-plugin/skills/audit/SKILL.md +0 -125
  32. package/claude-plugin/skills/create/SKILL.md +0 -389
  33. package/claude-plugin/skills/resolve/SKILL.md +0 -142
@@ -0,0 +1,359 @@
1
+ # Layout Patterns
2
+
3
+ Use this reference when building page-level layouts in any output mode.
4
+
5
+ ## Dashboard Pattern
6
+
7
+ Three-column layout with navigation sidebar, main content, and optional right panel.
8
+
9
+ ### Vue Example
10
+ ```vue
11
+ <script setup>
12
+ import { ref } from 'vue'
13
+ import { PvButton, PvSearchInput, PvIcon } from '@turquoisehealth/pit-viper/components'
14
+ import { PvDataTable } from '@turquoisehealth/pit-viper/components/visualizations'
15
+ import PvSidePanel from '@turquoisehealth/pit-viper/components/layout/PvSidePanel/PvSidePanel.vue'
16
+
17
+ const searchQuery = ref('')
18
+ const activeNav = ref('dashboard')
19
+
20
+ const navItems = [
21
+ { id: 'dashboard', label: 'Dashboard', icon: 'home' },
22
+ { id: 'users', label: 'Users', icon: 'user' },
23
+ { id: 'settings', label: 'Settings', icon: 'gear' },
24
+ ]
25
+
26
+ const colDefs = [
27
+ { field: 'name', headerName: 'Name', flex: 1 },
28
+ { field: 'email', headerName: 'Email', flex: 1 },
29
+ { field: 'role', headerName: 'Role', width: 120 },
30
+ ]
31
+
32
+ const rowData = [
33
+ { name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
34
+ { name: 'Bob Smith', email: 'bob@example.com', role: 'Editor' },
35
+ ]
36
+ </script>
37
+
38
+ <template>
39
+ <div style="height: 100vh;">
40
+ <PvSidePanel :showLeftSidebar="true" :showRightSidebar="false">
41
+ <template #left-sidebar>
42
+ <nav class="pv-inset-square-16">
43
+ <p class="pv-text-title-md pv-stack-24">My App</p>
44
+ <ul style="list-style: none; padding: 0; margin: 0;" class="pv-flow-4">
45
+ <li
46
+ v-for="item in navItems"
47
+ :key="item.id"
48
+ class="pv-flex pv-inset-squish-8 pv-radius"
49
+ :class="{ 'pv-surface-highlight': activeNav === item.id }"
50
+ style="cursor: pointer; --flex-gap: 0.75rem;"
51
+ @click="activeNav = item.id"
52
+ >
53
+ <PvIcon :name="item.icon" :size="16" />
54
+ <span class="pv-text-body-md">{{ item.label }}</span>
55
+ </li>
56
+ </ul>
57
+ </nav>
58
+ </template>
59
+
60
+ <template #main>
61
+ <div class="pv-inset-square-24">
62
+ <div class="pv-flex pv-space-between pv-stack-24">
63
+ <h1 class="pv-heading-1">Users</h1>
64
+ <PvButton leftIcon="plus">Add User</PvButton>
65
+ </div>
66
+
67
+ <div class="pv-stack-16">
68
+ <PvSearchInput v-model="searchQuery" placeholder="Search users..." style="max-width: 300px;" />
69
+ </div>
70
+
71
+ <PvDataTable :rowData="rowData" :colDefs="colDefs" style="height: 400px;" />
72
+ </div>
73
+ </template>
74
+ </PvSidePanel>
75
+ </div>
76
+ </template>
77
+ ```
78
+
79
+ ## Form Pattern
80
+
81
+ Card-based form with header, body (inputs), and footer (actions).
82
+
83
+ ### Vue Example
84
+ ```vue
85
+ <script setup>
86
+ import { ref } from 'vue'
87
+ import { PvButton, PvInput, PvSelectButton, PvCard } from '@turquoisehealth/pit-viper/components'
88
+
89
+ const formData = ref({
90
+ name: '',
91
+ email: '',
92
+ role: null,
93
+ })
94
+
95
+ const roleOptions = [
96
+ { label: 'Admin', value: 'admin' },
97
+ { label: 'Editor', value: 'editor' },
98
+ { label: 'Viewer', value: 'viewer' },
99
+ ]
100
+
101
+ const handleSubmit = () => {
102
+ console.log('Submitting:', formData.value)
103
+ }
104
+ </script>
105
+
106
+ <template>
107
+ <PvCard style="max-width: 500px;">
108
+ <template #header>
109
+ <h2 class="pv-heading-2">Create User</h2>
110
+ </template>
111
+
112
+ <form @submit.prevent="handleSubmit" class="pv-flow-16">
113
+ <div>
114
+ <label class="pv-text-title-sm pv-stack-4">Name</label>
115
+ <PvInput v-model="formData.name" placeholder="Full name" />
116
+ </div>
117
+
118
+ <div>
119
+ <label class="pv-text-title-sm pv-stack-4">Email</label>
120
+ <PvInput v-model="formData.email" type="email" placeholder="email@example.com" />
121
+ </div>
122
+
123
+ <div>
124
+ <label class="pv-text-title-sm pv-stack-4">Role</label>
125
+ <PvSelectButton v-model="formData.role" :options="roleOptions" placeholder="Select role" />
126
+ </div>
127
+ </form>
128
+
129
+ <template #footer>
130
+ <div class="pv-flex" style="--flex-justify: flex-end; --flex-gap: 0.5rem;">
131
+ <PvButton variant="ghost">Cancel</PvButton>
132
+ <PvButton @click="handleSubmit">Create User</PvButton>
133
+ </div>
134
+ </template>
135
+ </PvCard>
136
+ </template>
137
+ ```
138
+
139
+ ## Settings Pattern
140
+
141
+ Tabbed interface with accordion sections for complex settings.
142
+
143
+ ### Vue Example
144
+ ```vue
145
+ <script setup>
146
+ import { ref } from 'vue'
147
+ import { PvTabs, PvAccordion, PvInput, PvSwitch, PvButton } from '@turquoisehealth/pit-viper/components'
148
+
149
+ const activeTab = ref('profile')
150
+ const profileExpanded = ref(true)
151
+ const notificationsExpanded = ref(false)
152
+
153
+ const settings = ref({
154
+ displayName: 'Alice Johnson',
155
+ email: 'alice@example.com',
156
+ emailNotifications: true,
157
+ slackNotifications: false,
158
+ })
159
+ </script>
160
+
161
+ <template>
162
+ <div class="pv-inset-square-24">
163
+ <h1 class="pv-heading-1 pv-stack-24">Settings</h1>
164
+
165
+ <PvTabs
166
+ v-model="activeTab"
167
+ :tabs="[
168
+ { label: 'Profile', value: 'profile' },
169
+ { label: 'Notifications', value: 'notifications' },
170
+ { label: 'Security', value: 'security' },
171
+ ]"
172
+ class="pv-stack-24"
173
+ />
174
+
175
+ <div v-if="activeTab === 'profile'" class="pv-flow-16">
176
+ <PvAccordion v-model="profileExpanded" header="Personal Information">
177
+ <div class="pv-flow-16 pv-inset-square-16">
178
+ <div>
179
+ <label class="pv-text-title-sm pv-stack-4">Display Name</label>
180
+ <PvInput v-model="settings.displayName" />
181
+ </div>
182
+ <div>
183
+ <label class="pv-text-title-sm pv-stack-4">Email</label>
184
+ <PvInput v-model="settings.email" type="email" />
185
+ </div>
186
+ </div>
187
+ </PvAccordion>
188
+ </div>
189
+
190
+ <div v-if="activeTab === 'notifications'" class="pv-flow-16">
191
+ <PvAccordion v-model="notificationsExpanded" header="Notification Preferences">
192
+ <div class="pv-flow-16 pv-inset-square-16">
193
+ <div class="pv-flex pv-space-between">
194
+ <span class="pv-text-body-md">Email notifications</span>
195
+ <PvSwitch v-model="settings.emailNotifications" />
196
+ </div>
197
+ <div class="pv-flex pv-space-between">
198
+ <span class="pv-text-body-md">Slack notifications</span>
199
+ <PvSwitch v-model="settings.slackNotifications" />
200
+ </div>
201
+ </div>
202
+ </PvAccordion>
203
+ </div>
204
+
205
+ <div class="pv-stack-24">
206
+ <PvButton>Save Changes</PvButton>
207
+ </div>
208
+ </div>
209
+ </template>
210
+ ```
211
+
212
+ ## Marketing / Landing Pattern
213
+
214
+ Consumer theme with large typography, full-width sections, and prominent CTAs.
215
+
216
+ ### HTML Example (Consumer Theme)
217
+ ```html
218
+ <!DOCTYPE html>
219
+ <html lang="en">
220
+ <head>
221
+ <meta charset="UTF-8">
222
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
223
+ <title>Product Landing</title>
224
+ <link rel="stylesheet" href="https://pitviper.turquoise.health/assets/css/pit-viper-consumer.css">
225
+ <script src="https://unpkg.com/@turquoisehealth/pit-viper/pv-components/dist/web/pv-components.iife.js"></script>
226
+ </head>
227
+ <body>
228
+ <!-- Hero Section -->
229
+ <section class="pv-surface-brand-accent pv-inset-square-64">
230
+ <div class="pv-container-md" style="margin: 0 auto; text-align: center;">
231
+ <h1 class="pv-heading-1 pv-stack-24">Transform Your Healthcare Data</h1>
232
+ <p class="pv-text-body-xl pv-text-subdued pv-stack-32" style="max-width: 600px; margin: 0 auto;">
233
+ Unlock insights from your healthcare data with our powerful analytics platform.
234
+ </p>
235
+ <pv-button size="lg">Get Started</pv-button>
236
+ </div>
237
+ </section>
238
+
239
+ <!-- Features Section -->
240
+ <section class="pv-inset-square-64">
241
+ <div class="pv-container-lg" style="margin: 0 auto;">
242
+ <h2 class="pv-heading-2 pv-stack-32" style="text-align: center;">Features</h2>
243
+ <div class="pv-flex pv-flex-responsive" style="--flex-gap: 2rem;">
244
+ <pv-card style="flex: 1;">
245
+ <div slot="default" class="pv-inset-square-24">
246
+ <h3 class="pv-heading-3 pv-stack-8">Real-time Analytics</h3>
247
+ <p class="pv-text-body-md pv-text-subdued">
248
+ Monitor your data in real-time with customizable dashboards.
249
+ </p>
250
+ </div>
251
+ </pv-card>
252
+ <pv-card style="flex: 1;">
253
+ <div slot="default" class="pv-inset-square-24">
254
+ <h3 class="pv-heading-3 pv-stack-8">Secure & Compliant</h3>
255
+ <p class="pv-text-body-md pv-text-subdued">
256
+ HIPAA-compliant infrastructure with enterprise-grade security.
257
+ </p>
258
+ </div>
259
+ </pv-card>
260
+ <pv-card style="flex: 1;">
261
+ <div slot="default" class="pv-inset-square-24">
262
+ <h3 class="pv-heading-3 pv-stack-8">Easy Integration</h3>
263
+ <p class="pv-text-body-md pv-text-subdued">
264
+ Connect to your existing systems with our REST API.
265
+ </p>
266
+ </div>
267
+ </pv-card>
268
+ </div>
269
+ </div>
270
+ </section>
271
+
272
+ <!-- CTA Section -->
273
+ <section class="pv-surface-brand pv-inset-square-64">
274
+ <div class="pv-container-md" style="margin: 0 auto; text-align: center;">
275
+ <h2 class="pv-heading-2 pv-text-inverse pv-stack-16">Ready to get started?</h2>
276
+ <p class="pv-text-body-lg pv-text-inverse pv-stack-24" style="opacity: 0.8;">
277
+ Join thousands of healthcare organizations using our platform.
278
+ </p>
279
+ <pv-button variant="inverse" size="lg">Contact Sales</pv-button>
280
+ </div>
281
+ </section>
282
+ </body>
283
+ </html>
284
+ ```
285
+
286
+ ## List-Detail Pattern
287
+
288
+ Table with a drawer or modal for viewing/editing details.
289
+
290
+ ### Vue Example
291
+ ```vue
292
+ <script setup>
293
+ import { ref } from 'vue'
294
+ import { PvButton, PvDrawer, PvInput } from '@turquoisehealth/pit-viper/components'
295
+ import { PvDataTable } from '@turquoisehealth/pit-viper/components/visualizations'
296
+
297
+ const selectedUser = ref(null)
298
+ const drawerOpen = ref(false)
299
+
300
+ const users = ref([
301
+ { id: 1, name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
302
+ { id: 2, name: 'Bob Smith', email: 'bob@example.com', role: 'Editor' },
303
+ ])
304
+
305
+ const colDefs = [
306
+ { field: 'name', headerName: 'Name', flex: 1 },
307
+ { field: 'email', headerName: 'Email', flex: 1 },
308
+ { field: 'role', headerName: 'Role', width: 120 },
309
+ {
310
+ headerName: 'Actions',
311
+ width: 100,
312
+ cellRenderer: 'actionCell',
313
+ },
314
+ ]
315
+
316
+ const openDetail = (user) => {
317
+ selectedUser.value = { ...user }
318
+ drawerOpen.value = true
319
+ }
320
+ </script>
321
+
322
+ <template>
323
+ <div class="pv-inset-square-24">
324
+ <div class="pv-flex pv-space-between pv-stack-24">
325
+ <h1 class="pv-heading-1">Users</h1>
326
+ <PvButton leftIcon="plus">Add User</PvButton>
327
+ </div>
328
+
329
+ <PvDataTable
330
+ :rowData="users"
331
+ :colDefs="colDefs"
332
+ @row-clicked="openDetail($event.data)"
333
+ style="height: 400px;"
334
+ />
335
+
336
+ <PvDrawer v-model="drawerOpen" header="Edit User">
337
+ <template v-if="selectedUser">
338
+ <div class="pv-flow-16">
339
+ <div>
340
+ <label class="pv-text-title-sm pv-stack-4">Name</label>
341
+ <PvInput v-model="selectedUser.name" />
342
+ </div>
343
+ <div>
344
+ <label class="pv-text-title-sm pv-stack-4">Email</label>
345
+ <PvInput v-model="selectedUser.email" type="email" />
346
+ </div>
347
+ </div>
348
+ </template>
349
+
350
+ <template #footer>
351
+ <div class="pv-flex" style="--flex-justify: flex-end; --flex-gap: 0.5rem;">
352
+ <PvButton variant="ghost" @click="drawerOpen = false">Cancel</PvButton>
353
+ <PvButton>Save</PvButton>
354
+ </div>
355
+ </template>
356
+ </PvDrawer>
357
+ </div>
358
+ </template>
359
+ ```
@@ -0,0 +1,97 @@
1
+ # Core Patterns
2
+
3
+ Universal patterns for Pit Viper utility classes. These apply to both Vue and HTML output.
4
+
5
+ ## Anti-Pattern: Tailwind Classes
6
+
7
+ Pit Viper has its own utility system. Never use Tailwind.
8
+
9
+ ```html
10
+ <!-- BAD: Tailwind -->
11
+ <div class="flex gap-4 p-6 bg-gray-100 rounded-lg">
12
+ <h1 class="text-xl font-semibold mb-4">Title</h1>
13
+ <p class="text-sm text-gray-600">Description</p>
14
+ </div>
15
+
16
+ <!-- GOOD: Pit Viper -->
17
+ <div class="pv-flex pv-inset-square-24 pv-surface-accent pv-radius">
18
+ <h1 class="pv-heading-2 pv-stack-16">Title</h1>
19
+ <p class="pv-text-body-sm pv-text-subdued">Description</p>
20
+ </div>
21
+ ```
22
+
23
+ | Tailwind | Pit Viper |
24
+ |----------|-----------|
25
+ | `flex` | `pv-flex` |
26
+ | `gap-4` | `--flex-gap: 1rem` or spacing class |
27
+ | `p-6` | `pv-inset-square-24` |
28
+ | `bg-gray-100` | `pv-surface-accent` |
29
+ | `rounded-lg` | `pv-radius` |
30
+ | `text-xl font-semibold` | `pv-heading-2` |
31
+ | `text-sm text-gray-600` | `pv-text-body-sm pv-text-subdued` |
32
+ | `mb-4` | `pv-stack-16` |
33
+
34
+ ## Anti-Pattern: Components Without Spacing
35
+
36
+ Elements jammed together without breathing room look broken.
37
+
38
+ ```html
39
+ <!-- BAD: No spacing -->
40
+ <div>
41
+ <h1>Settings</h1>
42
+ <p>Configure your preferences below.</p>
43
+ <pv-input placeholder="Name"></pv-input>
44
+ <pv-input placeholder="Email"></pv-input>
45
+ <pv-button label="Save"></pv-button>
46
+ </div>
47
+
48
+ <!-- GOOD: Proper spacing hierarchy -->
49
+ <div class="pv-inset-square-24">
50
+ <h1 class="pv-heading-1 pv-stack-8">Settings</h1>
51
+ <p class="pv-text-body-md pv-text-subdued pv-stack-24">Configure your preferences below.</p>
52
+ <div class="pv-flex-vertical pv-stack-24" style="--flex-gap: 1rem;">
53
+ <pv-input placeholder="Name"></pv-input>
54
+ <pv-input placeholder="Email"></pv-input>
55
+ </div>
56
+ <pv-button label="Save"></pv-button>
57
+ </div>
58
+ ```
59
+
60
+ ## Anti-Pattern: Hardcoded Colors
61
+
62
+ Never use hex values. Use semantic color classes.
63
+
64
+ ```html
65
+ <!-- BAD: Hardcoded colors -->
66
+ <span style="color: #0E8019;">Success!</span>
67
+ <span style="color: #DA1E28;">Error!</span>
68
+ <div style="background: #F7F8F8;">Content</div>
69
+
70
+ <!-- GOOD: Semantic classes -->
71
+ <span class="pv-text-success">Success!</span>
72
+ <span class="pv-text-error">Error!</span>
73
+ <div class="pv-surface-accent">Content</div>
74
+ ```
75
+
76
+ ## Allowed Inline Styles
77
+
78
+ These inline styles are acceptable when no pv-* class exists:
79
+
80
+ | Style | Use Case |
81
+ |-------|----------|
82
+ | `style="max-width: 500px;"` | Constrain element width |
83
+ | `style="width: 298px;"` | Specific width for modals |
84
+ | `style="height: 400px;"` | Table/chart height |
85
+ | `style="--flex-gap: 1rem;"` | Flex gap override |
86
+ | `style="--flex-justify: flex-end;"` | Flex alignment |
87
+ | `style="--flow-size: 16px;"` | Flow spacing override |
88
+ | `style="text-decoration: none;"` | Link reset |
89
+ | `style="cursor: pointer;"` | Clickable non-button elements |
90
+ | `style="padding: 0px;"` | Reset default padding |
91
+
92
+ **Not allowed:**
93
+ - `style="color: #xxx;"` — use `pv-text-*` classes
94
+ - `style="background: #xxx;"` — use `pv-surface-*` classes
95
+ - `style="font-size: Xpx;"` — use `pv-heading-*` or `pv-text-*` classes
96
+ - `style="margin-bottom: Xpx;"` — use `pv-stack-*` classes
97
+ - `style="display: flex;"` — use `pv-flex` class
@@ -0,0 +1,149 @@
1
+ # Theme Selection Guide
2
+
3
+ Use this reference when choosing between Platform and Consumer themes or applying design tokens.
4
+
5
+ ## Theme Comparison
6
+
7
+ | Aspect | Platform | Consumer |
8
+ |--------|----------|----------|
9
+ | **Use case** | Internal tools, dashboards, admin panels | Marketing sites, public pages, consumer apps |
10
+ | **CSS file** | `pit-viper-v2.css` | `pit-viper-consumer.css` |
11
+ | **Font** | Inter | GT Standard |
12
+ | **Body text** | 12px (compact) | 16px (spacious) |
13
+ | **Heading 1** | 20px | 62px |
14
+ | **Overall density** | Compact, data-dense | Spacious, content-focused |
15
+ | **Color warmth** | Cool blue-gray | Warmer teal |
16
+
17
+ ## Theme URLs
18
+
19
+ ```
20
+ Platform: https://pitviper.turquoise.health/assets/css/pit-viper-v2.css
21
+ Consumer: https://pitviper.turquoise.health/assets/css/pit-viper-consumer.css
22
+ ```
23
+
24
+ Do NOT use the `-scoped` variants.
25
+
26
+ ## Auto-Detection Keywords
27
+
28
+ ### Platform Theme (Default)
29
+ - "dashboard"
30
+ - "admin"
31
+ - "internal"
32
+ - "tool"
33
+ - "portal"
34
+ - "app"
35
+ - "settings"
36
+ - "management"
37
+
38
+ ### Consumer Theme
39
+ - "marketing"
40
+ - "landing"
41
+ - "public"
42
+ - "consumer"
43
+ - "website"
44
+ - "customer-facing"
45
+ - "external"
46
+ - "hero"
47
+
48
+ If none of these keywords appear, default to **Platform**.
49
+
50
+ ## Typography Scale
51
+
52
+ ### Platform Theme
53
+ | Class | Size | Weight | Line Height |
54
+ |-------|------|--------|-------------|
55
+ | `.pv-heading-1` | 1.25rem (20px) | 600 | 1.2 |
56
+ | `.pv-heading-2` | 1rem (16px) | 600 | 1.5 |
57
+ | `.pv-heading-3` | 0.875rem (14px) | 600 | 1.43 |
58
+ | `.pv-heading-4` | 0.75rem (12px) | 600 | 1.33 |
59
+ | `.pv-text-body-xl` | 0.875rem (14px) | 400 | 1.14 |
60
+ | `.pv-text-body-lg` | 0.875rem (14px) | 400 | 1.14 |
61
+ | `.pv-text-body-md` | 0.75rem (12px) | 400 | 1.33 |
62
+ | `.pv-text-body-sm` | 0.6875rem (11px) | 400 | 1.45 |
63
+
64
+ ### Consumer Theme
65
+ Heading 1 scales up dramatically (62px). Body text is larger (16px base). Use for marketing pages where readability at a glance matters more than information density.
66
+
67
+ ## Spacing System
68
+
69
+ 4px base grid. Valid values:
70
+
71
+ | Class | Value | Pixels |
72
+ |-------|-------|--------|
73
+ | `.pv-stack-0` | 0 | 0 |
74
+ | `.pv-stack-4` | 0.25rem | 4px |
75
+ | `.pv-stack-8` | 0.5rem | 8px |
76
+ | `.pv-stack-12` | 0.75rem | 12px |
77
+ | `.pv-stack-16` | 1rem | 16px |
78
+ | `.pv-stack-20` | 1.25rem | 20px |
79
+ | `.pv-stack-24` | 1.5rem | 24px |
80
+ | `.pv-stack-32` | 2rem | 32px |
81
+ | `.pv-stack-64` | 4rem | 64px |
82
+ | `.pv-stack-128` | 8rem | 128px |
83
+
84
+ Same values exist for `.pv-inset-square-*` (padding) and `.pv-flow-*` (gap).
85
+
86
+ ## Color Palette
87
+
88
+ ### Brand Colors
89
+ | Token | Hex | Usage |
90
+ |-------|-----|-------|
91
+ | Primary Brand | `#176F6F` | Interactive elements, links, primary buttons |
92
+ | Secondary Brand | `#02363D` | Body text, secondary buttons, dark surfaces |
93
+ | Brand Accent Light | `#A8E6E1` | Inverse buttons, AI button, tertiary |
94
+ | Brand Accent Bg | `#F3FCFB` | Light teal backgrounds |
95
+
96
+ ### Text Colors
97
+ | Class | Usage |
98
+ |-------|-------|
99
+ | `.pv-text-default` | Primary body text |
100
+ | `.pv-text-subdued` | Secondary/helper text |
101
+ | `.pv-text-brand` | Links, brand-colored text |
102
+ | `.pv-text-inverse` | Text on dark surfaces |
103
+ | `.pv-text-critical` | Error messages |
104
+ | `.pv-text-warning` | Warning text |
105
+ | `.pv-text-success` | Success text |
106
+
107
+ ### Surface Colors
108
+ | Class | Usage |
109
+ |-------|-------|
110
+ | `.pv-surface` | Default white background |
111
+ | `.pv-surface-accent` | Subtle alternate backgrounds |
112
+ | `.pv-surface-brand` | Dark brand surfaces |
113
+ | `.pv-surface-highlight` | Selection/highlight backgrounds |
114
+ | `.pv-surface-brand-accent` | Light teal backgrounds |
115
+ | `.pv-surface-critical` | Error backgrounds |
116
+ | `.pv-surface-warning` | Warning backgrounds |
117
+ | `.pv-surface-success` | Success backgrounds |
118
+
119
+ ## Border Radius
120
+
121
+ | Class | Value | Use Case |
122
+ |-------|-------|----------|
123
+ | `.pv-radius-sm` | 2px | Tight, subtle rounding |
124
+ | `.pv-radius` | 5px | Default, most components |
125
+ | `.pv-radius-lg` | 12px | Cards, modals, prominent elements |
126
+
127
+ ## Layout Classes
128
+
129
+ | Class | Description |
130
+ |-------|-------------|
131
+ | `.pv-flex` | `display: flex; gap: 0.5rem; align-items: center` |
132
+ | `.pv-flex-vertical` | Column direction |
133
+ | `.pv-flex-responsive` | Column on mobile, row at 768px+ |
134
+ | `.pv-space-between` | `justify-content: space-between` |
135
+ | `.pv-container-sm` | Max-width 768px |
136
+ | `.pv-container-md` | Max-width 972px |
137
+ | `.pv-container-lg` | Max-width 1448px |
138
+
139
+ Use CSS custom property `--flex-gap` to override gap.
140
+
141
+ ## Responsive Breakpoint
142
+
143
+ Primary breakpoint: **768px**
144
+
145
+ - Below 768px: Mobile layout (sidebar collapses, flex stacks)
146
+ - 768px and above: Desktop layout
147
+
148
+ Use `.pv-flex-responsive` for automatic column-to-row behavior.
149
+ Use `.pv-stack-*-responsive` for half-size spacing on mobile.