common_component_library_vue 0.1.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.
package/DESIGN.md ADDED
@@ -0,0 +1,487 @@
1
+ ---
2
+ version: alpha
3
+ name: Stripi-Inspired-design-analysis
4
+ description: An inspired interpretation of Stripi's design language — a financial-infrastructure brand built on a deep navy ink, an electric indigo primary, and a recurring atmospheric gradient mesh that occupies the upper third of nearly every marketing page. The system pairs the proprietary Sohne family at thin (300) weights with negative letter-spacing for editorial-density display headlines, and uses tabular-figure body type where money and numerics matter. Buttons are tight-radius pills, cards live on near-white surfaces, and the dashboard track flips polarity to a familiar dark-app shell.
5
+
6
+ colors:
7
+ primary: "#533afd"
8
+ primary-deep: "#4434d4"
9
+ primary-press: "#2e2b8c"
10
+ primary-soft: "#665efd"
11
+ primary-bg-subdued-hover: "#b9b9f9"
12
+ brand-dark-900: "#1c1e54"
13
+ ink: "#0d253d"
14
+ ink-secondary: "#273951"
15
+ ink-mute: "#64748d"
16
+ ink-mute-2: "#61718a"
17
+ on-primary: "#ffffff"
18
+ canvas: "#ffffff"
19
+ canvas-soft: "#f6f9fc"
20
+ canvas-cream: "#f5e9d4"
21
+ hairline: "#e3e8ee"
22
+ hairline-input: "#a8c3de"
23
+ ruby: "#ea2261"
24
+ magenta: "#f96bee"
25
+ lemon: "#9b6829"
26
+ shadow-blue: "#003770"
27
+
28
+ typography:
29
+ display-xxl:
30
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
31
+ fontSize: 56px
32
+ fontWeight: 300
33
+ lineHeight: 1.03
34
+ letterSpacing: -1.4px
35
+ fontFeature: ss01
36
+ display-xl:
37
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
38
+ fontSize: 48px
39
+ fontWeight: 300
40
+ lineHeight: 1.15
41
+ letterSpacing: -0.96px
42
+ fontFeature: ss01
43
+ display-lg:
44
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
45
+ fontSize: 32px
46
+ fontWeight: 300
47
+ lineHeight: 1.1
48
+ letterSpacing: -0.64px
49
+ fontFeature: ss01
50
+ display-md:
51
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
52
+ fontSize: 26px
53
+ fontWeight: 300
54
+ lineHeight: 1.12
55
+ letterSpacing: -0.26px
56
+ fontFeature: ss01
57
+ heading-lg:
58
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
59
+ fontSize: 22px
60
+ fontWeight: 300
61
+ lineHeight: 1.1
62
+ letterSpacing: -0.22px
63
+ fontFeature: ss01
64
+ heading-md:
65
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
66
+ fontSize: 20px
67
+ fontWeight: 300
68
+ lineHeight: 1.4
69
+ letterSpacing: -0.2px
70
+ fontFeature: ss01
71
+ heading-sm:
72
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
73
+ fontSize: 18px
74
+ fontWeight: 300
75
+ lineHeight: 1.4
76
+ letterSpacing: 0
77
+ fontFeature: ss01
78
+ body-lg:
79
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
80
+ fontSize: 16px
81
+ fontWeight: 300
82
+ lineHeight: 1.4
83
+ letterSpacing: 0
84
+ fontFeature: ss01
85
+ body-md:
86
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
87
+ fontSize: 15px
88
+ fontWeight: 300
89
+ lineHeight: 1.4
90
+ letterSpacing: 0
91
+ fontFeature: ss01
92
+ body-tabular:
93
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
94
+ fontSize: 14px
95
+ fontWeight: 300
96
+ lineHeight: 1.4
97
+ letterSpacing: -0.42px
98
+ fontFeature: tnum
99
+ button-md:
100
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
101
+ fontSize: 16px
102
+ fontWeight: 400
103
+ lineHeight: 1.0
104
+ letterSpacing: 0
105
+ fontFeature: ss01
106
+ button-sm:
107
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
108
+ fontSize: 14px
109
+ fontWeight: 400
110
+ lineHeight: 1.0
111
+ letterSpacing: 0
112
+ fontFeature: ss01
113
+ caption:
114
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
115
+ fontSize: 13px
116
+ fontWeight: 400
117
+ lineHeight: 1.4
118
+ letterSpacing: -0.39px
119
+ fontFeature: tnum
120
+ micro:
121
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
122
+ fontSize: 11px
123
+ fontWeight: 300
124
+ lineHeight: 1.4
125
+ letterSpacing: 0
126
+ fontFeature: ss01
127
+ micro-cap:
128
+ fontFamily: "sohne-var, 'SF Pro Display', system-ui, -apple-system, sans-serif"
129
+ fontSize: 10px
130
+ fontWeight: 400
131
+ lineHeight: 1.15
132
+ letterSpacing: 0.1px
133
+ fontFeature: ss01
134
+
135
+ rounded:
136
+ xs: 4px
137
+ sm: 6px
138
+ md: 8px
139
+ lg: 12px
140
+ xl: 16px
141
+ pill: 9999px
142
+
143
+ spacing:
144
+ xxs: 2px
145
+ xs: 4px
146
+ sm: 8px
147
+ md: 12px
148
+ lg: 16px
149
+ xl: 24px
150
+ xxl: 32px
151
+ huge: 64px
152
+
153
+ components:
154
+ button-primary-pill:
155
+ backgroundColor: "{colors.primary}"
156
+ textColor: "{colors.on-primary}"
157
+ typography: "{typography.button-md}"
158
+ rounded: "{rounded.pill}"
159
+ padding: 8px 16px
160
+ button-primary-pill-pressed:
161
+ backgroundColor: "{colors.primary-press}"
162
+ textColor: "{colors.on-primary}"
163
+ typography: "{typography.button-md}"
164
+ rounded: "{rounded.pill}"
165
+ padding: 8px 16px
166
+ button-secondary:
167
+ backgroundColor: "{colors.canvas}"
168
+ textColor: "{colors.primary}"
169
+ typography: "{typography.button-md}"
170
+ rounded: "{rounded.pill}"
171
+ padding: 8px 16px
172
+ button-on-dark:
173
+ backgroundColor: "{colors.brand-dark-900}"
174
+ textColor: "{colors.on-primary}"
175
+ typography: "{typography.button-md}"
176
+ rounded: "{rounded.pill}"
177
+ padding: 8px 16px
178
+ text-input:
179
+ backgroundColor: "{colors.canvas}"
180
+ textColor: "{colors.ink}"
181
+ typography: "{typography.body-md}"
182
+ rounded: "{rounded.sm}"
183
+ padding: 8px 12px
184
+ text-input-focused:
185
+ backgroundColor: "{colors.canvas}"
186
+ textColor: "{colors.ink}"
187
+ typography: "{typography.body-md}"
188
+ rounded: "{rounded.sm}"
189
+ padding: 8px 12px
190
+ card-feature-light:
191
+ backgroundColor: "{colors.canvas}"
192
+ textColor: "{colors.ink}"
193
+ typography: "{typography.body-md}"
194
+ rounded: "{rounded.lg}"
195
+ padding: 32px
196
+ card-pricing:
197
+ backgroundColor: "{colors.canvas}"
198
+ textColor: "{colors.ink}"
199
+ typography: "{typography.body-md}"
200
+ rounded: "{rounded.lg}"
201
+ padding: 32px
202
+ card-pricing-featured:
203
+ backgroundColor: "{colors.brand-dark-900}"
204
+ textColor: "{colors.on-primary}"
205
+ typography: "{typography.body-md}"
206
+ rounded: "{rounded.lg}"
207
+ padding: 32px
208
+ card-cream-band:
209
+ backgroundColor: "{colors.canvas-cream}"
210
+ textColor: "{colors.ink}"
211
+ typography: "{typography.body-md}"
212
+ rounded: "{rounded.lg}"
213
+ padding: 32px
214
+ card-dashboard-mockup:
215
+ backgroundColor: "{colors.canvas}"
216
+ textColor: "{colors.ink}"
217
+ typography: "{typography.body-tabular}"
218
+ rounded: "{rounded.lg}"
219
+ padding: 24px
220
+ pill-tag-soft:
221
+ backgroundColor: "{colors.primary-bg-subdued-hover}"
222
+ textColor: "{colors.primary-deep}"
223
+ typography: "{typography.micro-cap}"
224
+ rounded: "{rounded.pill}"
225
+ padding: 4px 8px
226
+ nav-bar-on-mesh:
227
+ backgroundColor: "{colors.canvas}"
228
+ textColor: "{colors.ink}"
229
+ typography: "{typography.body-md}"
230
+ rounded: "{rounded.xs}"
231
+ padding: 16px 24px
232
+ link-on-light:
233
+ backgroundColor: "{colors.canvas}"
234
+ textColor: "{colors.primary}"
235
+ typography: "{typography.body-md}"
236
+ rounded: "{rounded.xs}"
237
+ padding: 0px
238
+ footer-light:
239
+ backgroundColor: "{colors.canvas}"
240
+ textColor: "{colors.ink-mute}"
241
+ typography: "{typography.caption}"
242
+ rounded: "{rounded.xs}"
243
+ padding: 64px 24px
244
+ ---
245
+
246
+ ## Overview
247
+
248
+ Stripi's design language opens with the gradient mesh. A wide horizontal band of pastel cream, sherbet orange, lavender, electric indigo, and ruby pink occupies the upper third of nearly every marketing page — the brand's instantly-recognizable atmospheric backdrop. Type and product UI mockups float above it on `{colors.canvas}` (white), with the gradient acting as both decoration and visual anchor. The lower portion of the page returns to white, with feature explanations on `{colors.canvas-soft}` (a barely-tinted cool off-white) and dashboard product mockups composited as faux IDE/console panels in deep navy.
249
+
250
+ The color system has two primary roles. **Indigo** (`{colors.primary}` — `#533afd`) is the brand's signature CTA color, used sparingly: one filled pill per band. **Deep navy** (`{colors.ink}` — `#0d253d`) is the universal body text color and the fill of dashboard mockups, the featured pricing tier, and the dark-app surfaces on the dashboard track. Ruby (`{colors.ruby}`) and magenta (`{colors.magenta}`) appear inside the gradient mesh and as accent dots in product UI mockups; they are not used as button colors.
251
+
252
+ Typography is built around **Sohne** at weight 300 with negative letter-spacing — the brand's editorial-density display signature. Display sizes (32–56px) use -1.4px to -0.64px tracking; body sizes use 0; tabular caption sizes (where money and numerics matter) use the OpenType `tnum` feature plus a tightening -0.36 to -0.42px tracking. The `ss01` stylistic set is enabled across all roles.
253
+
254
+ **Key Characteristics:**
255
+ - Gradient-mesh backdrop on every marketing hero — cream/orange/lavender/indigo/ruby horizontally washed across the upper third of the page.
256
+ - Single-indigo CTA hierarchy: filled `{colors.primary}` pill is the only filled button on marketing surfaces.
257
+ - Sohne thin (weight 300) display tier with negative tracking from -1.4px to -0.2px depending on size.
258
+ - Tabular-figure body type (`tnum`) for any cell containing money or numerics — the brand's quiet financial-data signal.
259
+ - Dark-app dashboard track: deep navy product UI mockups sit composited above the white canvas, frequently with rendered code or dashboard tables inside.
260
+ - Pill-shaped buttons (`{rounded.pill}` 9999px) with tight `8px 16px` padding — short, decisive, transactional.
261
+ - Cream-band feature cards (`{colors.canvas-cream}`) introduce a warm interlude between blue/white sections without breaking the brand's chromatic logic.
262
+
263
+ ## Colors
264
+
265
+ > **Source pages:** home (`/`), `/payments`, `/pricing`, `dashboard.stripe.com/register/payments`.
266
+
267
+ ### Brand & Accent
268
+ - **Indigo** (`{colors.primary}` — `#533afd`): The brand's signature CTA color. Filled-pill button, link emphasis, gradient anchor.
269
+ - **Indigo Deep** (`{colors.primary-deep}` — `#4434d4`): A deeper indigo used in gradient mid-stops and as the press-state warmer alternative.
270
+ - **Indigo Press** (`{colors.primary-press}` — `#2e2b8c`): Pressed-state lift of the primary.
271
+ - **Indigo Soft** (`{colors.primary-soft}` — `#665efd`): A lighter indigo used in product-UI accents and chart highlights.
272
+ - **Indigo Subdued** (`{colors.primary-bg-subdued-hover}` — `#b9b9f9`): Pale indigo fill used as soft tag background.
273
+ - **Brand Dark 900** (`{colors.brand-dark-900}` — `#1c1e54`): The deep navy used on the featured pricing tier and dashboard chrome.
274
+ - **Ruby** (`{colors.ruby}` — `#ea2261`): Gradient accent and chart highlight; never a button.
275
+ - **Magenta** (`{colors.magenta}` — `#f96bee`): Brighter pink stop in gradient meshes.
276
+ - **Lemon** (`{colors.lemon}` — `#9b6829`): Warm sherbet stop in gradient backdrops.
277
+
278
+ ### Surface
279
+ - **Canvas** (`{colors.canvas}` — `#ffffff`): Default page background.
280
+ - **Canvas Soft** (`{colors.canvas-soft}` — `#f6f9fc`): Cool-tinted off-white used on feature bands beneath the gradient hero.
281
+ - **Canvas Cream** (`{colors.canvas-cream}` — `#f5e9d4`): Warm cream used as a feature-band fill — the brand's chromatic interlude.
282
+ - **Hairline** (`{colors.hairline}` — `#e3e8ee`): 1px borders on cards and tables.
283
+ - **Hairline Input** (`{colors.hairline-input}` — `#a8c3de`): Slightly cooler hairline used on form inputs.
284
+
285
+ ### Text
286
+ - **Ink** (`{colors.ink}` — `#0d253d`): Default body text color across the brand. Deep navy, never pure black.
287
+ - **Ink Secondary** (`{colors.ink-secondary}` — `#273951`): Secondary text on white.
288
+ - **Ink Mute** (`{colors.ink-mute}` — `#64748d`): Helper text, captions, table labels.
289
+ - **Ink Mute 2** (`{colors.ink-mute-2}` — `#61718a`): Near-equivalent to ink-mute used in nav.
290
+ - **On Primary** (`{colors.on-primary}` — `#ffffff`): Text on indigo / dark-navy surfaces.
291
+
292
+ ### Semantic
293
+ The brand does not use a separate semantic color palette in the marketing system — error / success states live in dashboard-product UI specifically.
294
+
295
+ ## Typography
296
+
297
+ ### Font Family
298
+
299
+ The display and UI tier is **Sohne** (proprietary, licensed from Klim Type Foundry) at weights 300 (thin) and 400 (regular). The variable font (`sohne-var`) is loaded with `font-feature-settings: "ss01"` enabled globally — the stylistic set substitutes a single-story `a` and other character variants that are part of the brand's typographic signature.
300
+
301
+ When Sohne is unavailable, fall back to **SF Pro Display** at thin weights, then system-ui. For maximum brand fidelity, **Inter** (open-source) at weight 300 with `font-feature-settings: "ss01"` and `letter-spacing: -1.4px` on display sizes approximates the rhythm closely.
302
+
303
+ ### Hierarchy
304
+
305
+ | Token | Size | Weight | Line Height | Letter Spacing | Use |
306
+ |---|---|---|---|---|---|
307
+ | `{typography.display-xxl}` | 56px | 300 | 1.03 | -1.4px | Hero headline |
308
+ | `{typography.display-xl}` | 48px | 300 | 1.15 | -0.96px | Section opener |
309
+ | `{typography.display-lg}` | 32px | 300 | 1.1 | -0.64px | Card title / sub-section |
310
+ | `{typography.display-md}` | 26px | 300 | 1.12 | -0.26px | Compact card title |
311
+ | `{typography.heading-lg}` | 22px | 300 | 1.1 | -0.22px | Pricing tier name |
312
+ | `{typography.heading-md}` | 20px | 300 | 1.4 | -0.2px | Section sub-heading |
313
+ | `{typography.heading-sm}` | 18px | 300 | 1.4 | 0 | Mini-section label |
314
+ | `{typography.body-lg}` | 16px | 300 | 1.4 | 0 | Marketing body lead |
315
+ | `{typography.body-md}` | 15px | 300 | 1.4 | 0 | Default UI body |
316
+ | `{typography.body-tabular}` | 14px | 300 | 1.4 | -0.42px | Money / numeric tables (uses `tnum`) |
317
+ | `{typography.button-md}` | 16px | 400 | 1.0 | 0 | Pill button label |
318
+ | `{typography.button-sm}` | 14px | 400 | 1.0 | 0 | Compact pill label |
319
+ | `{typography.caption}` | 13px | 400 | 1.4 | -0.39px | Helper, table labels |
320
+ | `{typography.micro}` | 11px | 300 | 1.4 | 0 | Fine print |
321
+ | `{typography.micro-cap}` | 10px | 400 | 1.15 | 0.1px | All-caps eyebrow |
322
+
323
+ ### Principles
324
+ - **Thin weight is the brand.** Display tiers always render at weight 300. Bumping to 400+ removes the brand's editorial air.
325
+ - **Negative tracking on display.** -1.4px at 56px, scaling proportionally down to -0.2px at 20px. The negative tracking is the brand's typographic signature.
326
+ - **Tabular figures for money.** Any cell rendering currency, transaction amounts, or numeric counts uses `font-feature-settings: "tnum"` plus a tightening tracking. The brand quietly signals its financial DNA through this micro-detail.
327
+ - **`ss01` globally.** Apply `font-feature-settings: "ss01"` to the body element so the stylistic-set substitution is on for every text role.
328
+
329
+ ### Note on Font Substitutes
330
+ Sohne is proprietary. Use **Inter** (open-source via Google Fonts) at weight 300 with `letter-spacing: -1.4px` and `font-feature-settings: "ss01"` for display tiers — Inter is the closest open-source analogue. For body sizes, Inter at 300 weight with `font-feature-settings: "tnum"` (where applicable) is the canonical substitute. Avoid Helvetica or system-ui defaults — they're heavier than the brand needs.
331
+
332
+ ## Layout
333
+
334
+ ### Spacing System
335
+ - **Base unit**: 8px (with 2 / 4 / 12 sub-tokens for fine work).
336
+ - **Tokens**: `{spacing.xxs}` 2px · `{spacing.xs}` 4px · `{spacing.sm}` 8px · `{spacing.md}` 12px · `{spacing.lg}` 16px · `{spacing.xl}` 24px · `{spacing.xxl}` 32px · `{spacing.huge}` 64px.
337
+ - **Section padding**: 64–96px on marketing surfaces; 32–48px on dashboard / product surfaces.
338
+ - **Card internal padding**: 32px on feature cards; 24px on dashboard mockups.
339
+
340
+ ### Grid & Container
341
+ - Marketing pages center in a ~1200px container with the gradient mesh extending edge-to-edge above.
342
+ - Pricing collapses 4-up → 2-up → 1-up at 1024 / 768 breakpoints.
343
+ - Dashboard product mockups use their own internal grids (12-col tables, 3-col card grids) rendered as static composites.
344
+
345
+ ### Whitespace Philosophy
346
+ The gradient mesh occupies the upper third of the page; the white canvas below is generously padded. Section gaps tend toward 96px, with content tightening to 32px on dashboard / pricing pages where users compare and act.
347
+
348
+ ## Elevation & Depth
349
+
350
+ | Level | Treatment | Use |
351
+ |---|---|---|
352
+ | 0 | Flat | Default surface |
353
+ | 1 | `box-shadow: rgba(0,55,112,0.08) 0 1px 3px` | Card lift on white |
354
+ | 2 | `box-shadow: rgba(0,55,112,0.08) 0 8px 24px, rgba(0,55,112,0.04) 0 2px 6px` | Floating panels, dashboard mockup chrome |
355
+ | 3 | Gradient mesh backdrop | The brand's primary depth medium — atmospheric color rather than literal shadow |
356
+
357
+ ### Decorative Depth
358
+ The gradient mesh IS the depth system. Implemented as a layered SVG or large background image rather than CSS gradients (the actual mesh has organic blob shapes that aren't CSS-renderable). The mesh provides the brand's signature lift; literal shadows are reserved for product-UI mockups and stay subtle.
359
+
360
+ ## Shapes
361
+
362
+ ### Border Radius Scale
363
+
364
+ | Token | Value | Use |
365
+ |---|---|---|
366
+ | `{rounded.xs}` | 4px | Hairline tags, table chrome |
367
+ | `{rounded.sm}` | 6px | Form inputs |
368
+ | `{rounded.md}` | 8px | Compact cards, alerts |
369
+ | `{rounded.lg}` | 12px | Pricing cards, feature cards |
370
+ | `{rounded.xl}` | 16px | Dashboard product mockup chrome |
371
+ | `{rounded.pill}` | 9999px | All buttons, tag pills |
372
+
373
+ ### Photography Geometry
374
+ The brand uses **product UI mockups** more than photography. Dashboard composites render as faux IDE/terminal/dashboard chrome inside `{rounded.lg}` 12px containers with a subtle `box-shadow`. Real photography appears in customer logo strips and the rare case-study card; treated as inset 4:3 with no shadow.
375
+
376
+ ## Components
377
+
378
+ ### Buttons
379
+
380
+ **`button-primary-pill`** — the dominant CTA system-wide.
381
+ - Background `{colors.primary}`, text `{colors.on-primary}`, type `{typography.button-md}`, padding `{spacing.sm} {spacing.lg}` (8px 16px), rounded `{rounded.pill}` 9999px.
382
+ - Pressed state `button-primary-pill-pressed` shifts background to `{colors.primary-press}`.
383
+
384
+ **`button-secondary`** — outline-style alternative.
385
+ - Background `{colors.canvas}`, text `{colors.primary}`, 1px solid `{colors.primary}` border, same pill geometry.
386
+
387
+ **`button-on-dark`** — used on dashboard / dark surfaces.
388
+ - Background `{colors.brand-dark-900}`, text `{colors.on-primary}`, same pill geometry.
389
+
390
+ ### Cards & Containers
391
+
392
+ **`card-feature-light`** — feature explanation card on white.
393
+ - Background `{colors.canvas}`, padding `{spacing.xxl}`, rounded `{rounded.lg}` 12px, 1px `{colors.hairline}` border, optional Level 1 shadow.
394
+
395
+ **`card-pricing`** — standard pricing tier.
396
+ - Background `{colors.canvas}`, padding `{spacing.xxl}`, rounded `{rounded.lg}`, 1px `{colors.hairline}` border. Title `{typography.heading-lg}`, price `{typography.display-md}`, body `{typography.body-md}`, CTA pinned bottom as `button-primary-pill`.
397
+
398
+ **`card-pricing-featured`** — the inverted dark featured tier.
399
+ - Background `{colors.brand-dark-900}`, text `{colors.on-primary}`, otherwise identical structure to `card-pricing`. The deep-navy fill is the brand's distinctive featured-tier choice.
400
+
401
+ **`card-cream-band`** — warm interlude card.
402
+ - Background `{colors.canvas-cream}`, text `{colors.ink}`, padding `{spacing.xxl}`, rounded `{rounded.lg}`. Used to break up the indigo / white rhythm with warmth.
403
+
404
+ **`card-dashboard-mockup`** — composited dashboard / product UI screenshot.
405
+ - Background `{colors.canvas}`, type `{typography.body-tabular}` (with `tnum`), padding `{spacing.xl}` 24px, rounded `{rounded.lg}` 12px, Level 2 shadow. Often contains nested mini-mockups: code preview + dashboard table + chart card.
406
+
407
+ ### Inputs & Forms
408
+
409
+ **`text-input`** — standard form field.
410
+ - Background `{colors.canvas}`, text `{colors.ink}`, type `{typography.body-md}`, padding `{spacing.sm} {spacing.md}` (8px 12px), rounded `{rounded.sm}` 6px, 1px `{colors.hairline-input}` border.
411
+ - Focus state `text-input-focused`: border swaps to `{colors.primary}`.
412
+
413
+ ### Navigation
414
+
415
+ **`nav-bar-on-mesh`** — top nav floating over the gradient hero.
416
+ - Background `{colors.canvas}` (or transparent depending on scroll), text `{colors.ink}`, padding `{spacing.lg} {spacing.xl}`. Logo wordmark on the left, primary nav center, sign-in + filled `button-primary-pill` on the right.
417
+
418
+ ### Pills, Tags, and Chips
419
+
420
+ **`pill-tag-soft`** — subdued indigo tag.
421
+ - Background `{colors.primary-bg-subdued-hover}`, text `{colors.primary-deep}`, type `{typography.micro-cap}`, padding `4px 8px`, rounded `{rounded.pill}`.
422
+
423
+ ### Signature Components
424
+
425
+ **Gradient Mesh Backdrop** — pastel cream → sherbet orange → lavender → indigo → ruby pink stops blurred horizontally across the upper third of the page. Implemented as SVG or a large background image — not a flat CSS gradient (the real mesh has organic blob shapes).
426
+
427
+ **Composited Dashboard Mockup** — multi-layer faux-product-UI compositions: an IDE panel on the left, a dashboard table center, a chart card on the right, all rendered at small scale inside `{rounded.lg}` containers with subtle Level 2 shadows. The composite is the brand's most-photographed feature.
428
+
429
+ **Tabular-Figure Money Type** — every number rendering money, count, or transaction value uses `font-feature-settings: "tnum"`. The brand's quiet signal that it's a financial-infrastructure platform.
430
+
431
+ **`link-on-light`** — inline links on light surfaces.
432
+ - Text `{colors.primary}` rendered in `{typography.body-md}`, no underline by default.
433
+
434
+ **`footer-light`** — site-wide footer.
435
+ - Background `{colors.canvas}`, text `{colors.ink-mute}`, type `{typography.caption}`, padding `{spacing.huge} {spacing.xl}` (64px 24px). Holds 4–6 columns of link groups, social icons, and a small legal row.
436
+
437
+ ## Do's and Don'ts
438
+
439
+ ### Do
440
+ - Reserve `{colors.primary}` for filled CTAs and inline link emphasis — it should appear sparingly, one filled button per band.
441
+ - Apply the gradient mesh to every marketing hero; bare-canvas heroes feel off-brand.
442
+ - Render display tiers at weight 300 with negative letter-spacing — the thin tracking is the typographic signature.
443
+ - Use `font-feature-settings: "tnum"` on every money / numeric cell.
444
+ - Apply `font-feature-settings: "ss01"` globally on the body element.
445
+ - Pair every feature explanation with a composited product UI mockup; the brand's argument is "look at the actual product."
446
+
447
+ ### Don't
448
+ - Don't bump display weight above 300 — at 400 the brand's editorial air collapses.
449
+ - Don't add new accent colors outside the documented gradient stops (cream / orange / lavender / indigo / ruby / magenta).
450
+ - Don't use the indigo `{colors.primary}` as a body-text color — it's a CTA and link color, not a type color at body size.
451
+ - Don't shrink button padding below `8px 16px` — the tight pill is part of the brand's transactional feel.
452
+ - Don't render money cells without `tnum` — it breaks the quiet financial-data signature.
453
+ - Don't replace the pill shape with rounded-rectangles for buttons.
454
+
455
+ ## Responsive Behavior
456
+
457
+ ### Breakpoints
458
+
459
+ | Name | Width | Key Changes |
460
+ |---|---|---|
461
+ | Wide | ≥ 1440px | Full gradient mesh edge-to-edge; dashboard composite at full scale |
462
+ | Desktop | 1024–1440px | Default content max-width; pricing 4-up |
463
+ | Tablet | 768–1023px | Pricing 2-up; dashboard composite simplifies to 2 panels |
464
+ | Mobile | < 768px | Pricing 1-up; hamburger nav; display drops 56 → 36px |
465
+
466
+ ### Touch Targets
467
+ - Pill buttons hit ≥ 40×40px on mobile via padding scaling. On smaller screens, buttons size up to 44×44px to maintain WCAG AAA.
468
+ - Form fields stay at 40px minimum height.
469
+
470
+ ### Collapsing Strategy
471
+ - Display tiers stair-step 56 → 48 → 32 → 26 → 22px through the breakpoints.
472
+ - Gradient mesh re-tiles on mobile to preserve the wash without disappearing.
473
+ - Dashboard composites simplify to single-panel mockups on mobile; the multi-layer composition only renders at desktop+.
474
+ - Pricing tiers stair-step 4-up → 2-up → 1-up.
475
+
476
+ ### Image Behavior
477
+ Product UI composites use `srcset` with art-direction crops at major breakpoints. Mobile crops focus on the most actionable inner panel; desktop crops show the full multi-layer composition.
478
+
479
+ ## Iteration Guide
480
+
481
+ 1. Focus on ONE component at a time.
482
+ 2. Reference component names and tokens directly (`{colors.primary}`, `{button-primary-pill}-pressed`, `{rounded.pill}`).
483
+ 3. Run `npx @google/design.md lint DESIGN.md` after edits.
484
+ 4. Add new variants as separate entries.
485
+ 5. Default body to `{typography.body-md}` (15px); use `{typography.body-tabular}` for any money / numeric cell.
486
+ 6. Apply `ss01` globally on the body; apply `tnum` per-element on numeric content.
487
+ 7. The gradient mesh is non-negotiable on marketing heroes — bare-canvas heroes break the brand.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # common_component_library_vue
2
+
3
+ **Vue 3 · TypeScript · Vite · DESIGN.md**
4
+
5
+ 一个由 [DESIGN.md](DESIGN.md) 驱动的通用组件库。视觉规范取自
6
+ [awesome-design-md](https://github.com/VoltAgent/awesome-design-md) 收录的 **Stripe** 设计语言分析
7
+ (靛蓝主色 `#533afd`、深海军蓝墨色 `#0d253d`、Sohne 300 细字重排版、胶囊按钮、渐变网格、tabular figures)。
8
+
9
+ > DESIGN.md 是 Google Stitch 提出的纯文本设计系统文档:把一份 markdown 放进项目根目录,
10
+ > 告诉 AI 代理 "build me a page that looks like this",即可生成视觉一致的高质量 UI。
11
+
12
+ ## 快速开始
13
+
14
+ ```bash
15
+ npm install
16
+ npm run dev # 启动组件演示页 (http://localhost:5173)
17
+ npm run build # 类型检查 + 构建演示页
18
+ npm run build:lib # 构建可发布的组件库 (dist-lib/, ESM + UMD)
19
+ npm run preview # 预览构建产物
20
+ ```
21
+
22
+ ## 项目结构
23
+
24
+ ```
25
+ common_component_library_vue/
26
+ ├── DESIGN.md # 设计规范(Stripe 风格,来自 awesome-design-md)
27
+ ├── index.html # 演示页入口
28
+ ├── vite.config.ts # 演示页构建
29
+ ├── vite.lib.config.ts # 组件库构建(lib mode)
30
+ └── src/
31
+ ├── main.ts # 演示页挂载
32
+ ├── App.vue # 组件展示页(色板/排版/全部组件)
33
+ ├── index.ts # 组件库导出入口(含 install 插件)
34
+ ├── styles/
35
+ │ ├── tokens.css # 设计令牌:颜色/字体/圆角/间距/阴影 → CSS 变量 --cc-*
36
+ │ └── base.css # 全局基础样式(ss01、tnum、类型角色工具类)
37
+ └── components/ # 15 个通用组件(前缀 Cc)
38
+ ```
39
+
40
+ ## 组件列表
41
+
42
+ | 组件 | 说明 | 对应 DESIGN.md token |
43
+ |---|---|---|
44
+ | `CcButton` | 胶囊按钮:primary / secondary / on-dark / ghost / link,sm·md·lg | `{button-primary-pill}`、`{button-secondary}`、`{button-on-dark}` |
45
+ | `CcInput` | 输入框:label / hint / error / prefix,聚焦换主色边框 | `{text-input}`、`{text-input-focused}` |
46
+ | `CcTextarea` | 多行文本域 | `{text-input}` 几何语言 |
47
+ | `CcSelect` | 原生 select 美化,自定义 chevron | `{text-input}` |
48
+ | `CcSwitch` | 胶囊开关 | 品牌胶囊几何 |
49
+ | `CcCheckbox` | 复选框 | 品牌色勾选 |
50
+ | `CcRadio` | 单选(共享 v-model 成组) | 品牌色圆点 |
51
+ | `CcCard` | feature / pricing / pricing-featured / cream / dashboard / plain | `{card-*}` 全套 |
52
+ | `CcTag` | 软标签 / 实心 / 深色 / 描边,支持 dot、closable | `{pill-tag-soft}` |
53
+ | `CcBadge` | 数字角标(tnum 数字,max 截断) | — |
54
+ | `CcAlert` | info / success / warning / error,可关闭 | 语义色(dashboard UI) |
55
+ | `CcModal` | 弹窗:Teleport、Esc 关闭、遮罩点击、过渡 | `{card-dashboard-mockup}` 深度 |
56
+ | `CcTooltip` | 悬浮提示:top / bottom / left / right,delay | 深海军蓝气泡 |
57
+ | `CcSpinner` | 加载指示器 | 品牌靛蓝 |
58
+ | `CcDivider` | 分割线,支持文本 | `{colors.hairline}` |
59
+
60
+ ## 使用组件库
61
+
62
+ ```ts
63
+ // 方式一:按需引入
64
+ import { CcButton, CcInput } from 'common_component_library_vue'
65
+ import 'common_component_library_vue/src/styles/tokens.css'
66
+
67
+ // 方式二:全量注册
68
+ import CcLibrary from 'common_component_library_vue'
69
+ app.use(CcLibrary)
70
+ ```
71
+
72
+ ## 设计令牌
73
+
74
+ 所有 DESIGN.md token 均映射为 CSS 自定义属性(`src/styles/tokens.css`):
75
+
76
+ - **颜色** `--cc-primary / --cc-ink / --cc-brand-dark-900 / --cc-hairline …`
77
+ - **排版** 类型层级以工具类提供:`.cc-text-display-xxl … .cc-text-micro-cap`
78
+ - **圆角** `--cc-radius-xs / sm / md / lg / xl / pill`
79
+ - **间距** `--cc-space-xxs … --cc-space-huge`(8px 基准)
80
+ - **阴影** `--cc-shadow-level-1 / level-2`
81
+
82
+ 关键品牌细节(来自 DESIGN.md 的 Do's & Don'ts):
83
+
84
+ 1. **细字重是品牌**:展示级文字一律 300,配负字距(-1.4px → -0.2px),不要升到 400+。
85
+ 2. **`ss01` 全局开启**,`tnum` 用在所有金额/数字单元格上。
86
+ 3. **靛蓝 `{colors.primary}` 只用于 CTA 和链接**,不做正文色。
87
+ 4. **按钮永远是胶囊**(`{rounded.pill}`),不要用圆角矩形替代;padding 不低于 `8px 16px`。
88
+ 5. **渐变网格是营销 hero 的标配**,裸白 hero 视为偏离品牌。
89
+
90
+ ## 字体说明
91
+
92
+ Sohne 是 Klim 的专有字体。按 DESIGN.md 的替代方案,本库使用开源的
93
+ [Inter](https://rsms.me/inter/)(Google Fonts 版)在 300 字重 + 负字距下近似品牌节奏,
94
+ 已通过 `@fontsource/inter` 打包,离线可用。
95
+
96
+ ## 许可与致谢
97
+
98
+ - DESIGN.md 由 [awesome-design-md](https://github.com/VoltAgent/awesome-design-md)(MIT)从 Stripe 公开站点提取,本库仅作学习与演示。
99
+ - 设计令牌来自公开可见的 CSS 值,不主张对 Stripe 视觉识别的所有权。
100
+ - 代码部分 MIT。
@@ -0,0 +1,2 @@
1
+ .cc-spinner[data-v-00c109fa]{color:var(--f2187a8a);animation:.8s linear infinite cc-spin-00c109fa}.cc-spinner__arc[data-v-00c109fa]{stroke:currentColor}@keyframes cc-spin-00c109fa{to{transform:rotate(360deg)}}.cc-btn[data-v-deb42261]{justify-content:center;align-items:center;gap:var(--cc-space-sm);border-radius:var(--cc-radius-pill);font-family:var(--cc-font-family);letter-spacing:0;cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;border:0;padding:8px 16px;font-size:16px;font-weight:400;line-height:1;text-decoration:none;transition:background-color .15s,border-color .15s,color .15s,box-shadow .15s,transform 50ms;display:inline-flex}.cc-btn[data-v-deb42261]:focus-visible{box-shadow:var(--cc-focus-ring);outline:none}.cc-btn[data-v-deb42261]:disabled{cursor:not-allowed;opacity:.55}.cc-btn--primary[data-v-deb42261]{background-color:var(--cc-primary);color:var(--cc-on-primary)}.cc-btn--primary[data-v-deb42261]:hover:not(:disabled){background-color:var(--cc-primary-deep)}.cc-btn--primary[data-v-deb42261]:active:not(:disabled){background-color:var(--cc-primary-press)}.cc-btn--secondary[data-v-deb42261]{background-color:var(--cc-canvas);color:var(--cc-primary);border:1px solid var(--cc-primary);padding:7px 15px}.cc-btn--secondary[data-v-deb42261]:hover:not(:disabled){background-color:var(--cc-primary);color:var(--cc-on-primary)}.cc-btn--secondary[data-v-deb42261]:active:not(:disabled){background-color:var(--cc-primary-press);border-color:var(--cc-primary-press)}.cc-btn--on-dark[data-v-deb42261]{background-color:var(--cc-brand-dark-900);color:var(--cc-on-primary)}.cc-btn--on-dark[data-v-deb42261]:hover:not(:disabled){background-color:#252866}.cc-btn--on-dark[data-v-deb42261]:active:not(:disabled){background-color:#13153f}.cc-btn--ghost[data-v-deb42261]{color:var(--cc-ink);background-color:#0000}.cc-btn--ghost[data-v-deb42261]:hover:not(:disabled){background-color:var(--cc-canvas-soft);color:var(--cc-ink)}.cc-btn--ghost[data-v-deb42261]:active:not(:disabled){background-color:var(--cc-hairline)}.cc-btn--link[data-v-deb42261]{color:var(--cc-primary);background-color:#0000;padding:2px 4px}.cc-btn--link[data-v-deb42261]:hover:not(:disabled){text-decoration:underline}.cc-btn--sm[data-v-deb42261]{padding:6px 12px;font-size:14px}.cc-btn--sm.cc-btn--secondary[data-v-deb42261]{padding:5px 11px}.cc-btn--lg[data-v-deb42261]{padding:12px 24px;font-size:16px}.cc-btn--lg.cc-btn--secondary[data-v-deb42261]{padding:11px 23px}.cc-btn--block[data-v-deb42261]{width:100%;display:flex}.cc-btn--loading[data-v-deb42261]{cursor:wait}.cc-btn__spinner[data-v-deb42261]{display:inline-flex}.cc-btn__content[data-v-deb42261]{align-items:center;display:inline-flex}.cc-input[data-v-4b6c01de]{gap:var(--cc-space-xs);font-family:var(--cc-font-family);flex-direction:column;display:flex}.cc-input__label[data-v-4b6c01de]{letter-spacing:-.39px;color:var(--cc-ink-secondary);font-size:13px;font-weight:400}.cc-input__field[data-v-4b6c01de]{min-height:var(--cc-input-height);background-color:var(--cc-canvas);border:1px solid var(--cc-hairline-input);border-radius:var(--cc-radius-sm);align-items:center;transition:border-color .15s,box-shadow .15s;display:flex}.cc-input__field[data-v-4b6c01de]:focus-within{border-color:var(--cc-primary);box-shadow:var(--cc-focus-ring)}.cc-input--error .cc-input__field[data-v-4b6c01de]{border-color:var(--cc-error)}.cc-input--error .cc-input__field[data-v-4b6c01de]:focus-within{box-shadow:0 0 0 3px #ea226126}.cc-input__control[data-v-4b6c01de]{min-width:0;color:var(--cc-ink);background:0 0;border:0;outline:none;flex:1;padding:8px 12px;font-family:inherit;font-size:15px;font-weight:300;line-height:1.4}.cc-input__control[data-v-4b6c01de]::placeholder{color:var(--cc-ink-mute);opacity:.75}.cc-input__control[data-v-4b6c01de]:disabled{cursor:not-allowed;background-color:var(--cc-canvas-soft);color:var(--cc-ink-mute)}.cc-input__prefix[data-v-4b6c01de]{color:var(--cc-ink-mute);padding-left:12px;font-size:15px;font-weight:300}.cc-input__field--prefix .cc-input__control[data-v-4b6c01de]{padding-left:6px}.cc-input__message[data-v-4b6c01de]{color:var(--cc-ink-mute);margin:0;font-size:12px;font-weight:400;line-height:1.4}.cc-input__message--error[data-v-4b6c01de]{color:var(--cc-error)}.cc-textarea[data-v-9840d15e]{gap:var(--cc-space-xs);font-family:var(--cc-font-family);flex-direction:column;display:flex}.cc-textarea__label[data-v-9840d15e]{letter-spacing:-.39px;color:var(--cc-ink-secondary);font-size:13px;font-weight:400}.cc-textarea__control[data-v-9840d15e]{resize:vertical;border:1px solid var(--cc-hairline-input);border-radius:var(--cc-radius-sm);background-color:var(--cc-canvas);min-height:96px;color:var(--cc-ink);outline:none;padding:8px 12px;font-family:inherit;font-size:15px;font-weight:300;line-height:1.5;transition:border-color .15s,box-shadow .15s}.cc-textarea__control[data-v-9840d15e]::placeholder{color:var(--cc-ink-mute);opacity:.75}.cc-textarea__control[data-v-9840d15e]:focus{border-color:var(--cc-primary);box-shadow:var(--cc-focus-ring)}.cc-textarea--error .cc-textarea__control[data-v-9840d15e]{border-color:var(--cc-error)}.cc-textarea__control[data-v-9840d15e]:disabled{cursor:not-allowed;background-color:var(--cc-canvas-soft);color:var(--cc-ink-mute)}.cc-textarea__message[data-v-9840d15e]{color:var(--cc-ink-mute);margin:0;font-size:12px;font-weight:400;line-height:1.4}.cc-textarea__message--error[data-v-9840d15e]{color:var(--cc-error)}.cc-select[data-v-0e1871e6]{gap:var(--cc-space-xs);font-family:var(--cc-font-family);flex-direction:column;display:flex}.cc-select__label[data-v-0e1871e6]{letter-spacing:-.39px;color:var(--cc-ink-secondary);font-size:13px;font-weight:400}.cc-select__wrap[data-v-0e1871e6]{align-items:center;display:flex;position:relative}.cc-select__control[data-v-0e1871e6]{appearance:none;width:100%;min-height:var(--cc-input-height);border:1px solid var(--cc-hairline-input);border-radius:var(--cc-radius-sm);background-color:var(--cc-canvas);color:var(--cc-ink);cursor:pointer;outline:none;padding:8px 36px 8px 12px;font-family:inherit;font-size:15px;font-weight:300;line-height:1.4;transition:border-color .15s,box-shadow .15s}.cc-select__control[data-v-0e1871e6]:focus{border-color:var(--cc-primary);box-shadow:var(--cc-focus-ring)}.cc-select__control[data-v-0e1871e6]:disabled{cursor:not-allowed;background-color:var(--cc-canvas-soft);color:var(--cc-ink-mute)}.cc-select--error .cc-select__control[data-v-0e1871e6]{border-color:var(--cc-error)}.cc-select__chevron[data-v-0e1871e6]{pointer-events:none;color:var(--cc-primary);position:absolute;right:12px}.cc-select__message[data-v-0e1871e6]{color:var(--cc-ink-mute);margin:0;font-size:12px;font-weight:400}.cc-select__message--error[data-v-0e1871e6]{color:var(--cc-error)}.cc-switch[data-v-cb8ad6ea]{align-items:center;gap:var(--cc-space-sm);font-family:var(--cc-font-family);cursor:pointer;-webkit-tap-highlight-color:transparent;background:0 0;border:0;padding:0;display:inline-flex}.cc-switch__track[data-v-cb8ad6ea]{border-radius:var(--cc-radius-pill);background-color:var(--cc-hairline);border:1px solid var(--cc-hairline-input);box-sizing:border-box;flex-shrink:0;align-items:center;width:40px;height:22px;transition:background-color .2s,border-color .2s;display:inline-flex;position:relative}.cc-switch--checked .cc-switch__track[data-v-cb8ad6ea]{background-color:var(--cc-primary);border-color:var(--cc-primary)}.cc-switch--sm .cc-switch__track[data-v-cb8ad6ea]{width:32px;height:18px}.cc-switch__knob[data-v-cb8ad6ea]{border-radius:var(--cc-radius-pill);background-color:var(--cc-canvas);width:16px;height:16px;margin-left:2px;transition:transform .2s;box-shadow:0 1px 2px #00377033}.cc-switch--sm .cc-switch__knob[data-v-cb8ad6ea]{width:12px;height:12px}.cc-switch--checked .cc-switch__knob[data-v-cb8ad6ea]{transform:translate(18px)}.cc-switch--sm.cc-switch--checked .cc-switch__knob[data-v-cb8ad6ea]{transform:translate(14px)}.cc-switch__label[data-v-cb8ad6ea]{color:var(--cc-ink);font-size:15px;font-weight:300}.cc-switch[data-v-cb8ad6ea]:focus-visible{outline:none}.cc-switch:focus-visible .cc-switch__track[data-v-cb8ad6ea]{box-shadow:var(--cc-focus-ring)}.cc-switch--disabled[data-v-cb8ad6ea]{cursor:not-allowed;opacity:.5}.cc-checkbox[data-v-bf838053]{align-items:center;gap:var(--cc-space-sm);font-family:var(--cc-font-family);cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;display:inline-flex}.cc-checkbox__native[data-v-bf838053]{opacity:0;width:0;height:0;position:absolute}.cc-checkbox__box[data-v-bf838053]{border:1px solid var(--cc-hairline-input);border-radius:var(--cc-radius-xs);background-color:var(--cc-canvas);color:#0000;flex-shrink:0;justify-content:center;align-items:center;width:18px;height:18px;transition:background-color .15s,border-color .15s,color .15s;display:inline-flex}.cc-checkbox__check[data-v-bf838053]{stroke:currentColor}.cc-checkbox__native:checked+.cc-checkbox__box[data-v-bf838053]{background-color:var(--cc-primary);border-color:var(--cc-primary);color:var(--cc-on-primary)}.cc-checkbox__native:focus-visible+.cc-checkbox__box[data-v-bf838053]{box-shadow:var(--cc-focus-ring)}.cc-checkbox__native:indeterminate+.cc-checkbox__box[data-v-bf838053]{background-color:var(--cc-primary);border-color:var(--cc-primary)}.cc-checkbox__label[data-v-bf838053]{color:var(--cc-ink);font-size:15px;font-weight:300}.cc-checkbox--disabled[data-v-bf838053]{cursor:not-allowed;opacity:.5}.cc-radio[data-v-0a6c4d47]{align-items:center;gap:var(--cc-space-sm);font-family:var(--cc-font-family);cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;display:inline-flex}.cc-radio__native[data-v-0a6c4d47]{opacity:0;width:0;height:0;position:absolute}.cc-radio__dot[data-v-0a6c4d47]{border:1px solid var(--cc-hairline-input);border-radius:var(--cc-radius-pill);background-color:var(--cc-canvas);flex-shrink:0;justify-content:center;align-items:center;width:18px;height:18px;transition:border-color .15s,box-shadow .15s;display:inline-flex}.cc-radio__dot[data-v-0a6c4d47]:after{content:"";border-radius:var(--cc-radius-pill);background-color:var(--cc-primary);width:8px;height:8px;transition:transform .15s;transform:scale(0)}.cc-radio__native:checked+.cc-radio__dot[data-v-0a6c4d47]{border-color:var(--cc-primary)}.cc-radio__native:checked+.cc-radio__dot[data-v-0a6c4d47]:after{transform:scale(1)}.cc-radio__native:focus-visible+.cc-radio__dot[data-v-0a6c4d47]{box-shadow:var(--cc-focus-ring)}.cc-radio__label[data-v-0a6c4d47]{color:var(--cc-ink);font-size:15px;font-weight:300}.cc-radio--disabled[data-v-0a6c4d47]{cursor:not-allowed;opacity:.5}.cc-card[data-v-7f39ac3e]{border-radius:var(--cc-radius-lg);padding:var(--cc-space-xxl);font-family:var(--cc-font-family);gap:var(--cc-space-lg);flex-direction:column;display:flex;position:relative}.cc-card--flush[data-v-7f39ac3e]{padding:0}.cc-card--feature[data-v-7f39ac3e],.cc-card--pricing[data-v-7f39ac3e]{background-color:var(--cc-canvas);color:var(--cc-ink);border:1px solid var(--cc-hairline);box-shadow:var(--cc-shadow-level-1)}.cc-card--pricing-featured[data-v-7f39ac3e]{background-color:var(--cc-brand-dark-900);color:var(--cc-on-primary);box-shadow:var(--cc-shadow-level-2);border:1px solid #0000}.cc-card--cream[data-v-7f39ac3e]{background-color:var(--cc-canvas-cream);color:var(--cc-ink);border:1px solid #0000}.cc-card--dashboard[data-v-7f39ac3e]{background-color:var(--cc-canvas);color:var(--cc-ink);border:1px solid var(--cc-hairline);box-shadow:var(--cc-shadow-level-2);font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}.cc-card--plain[data-v-7f39ac3e]{background-color:var(--cc-canvas);color:var(--cc-ink);border:1px solid var(--cc-hairline)}.cc-card__header[data-v-7f39ac3e]{gap:var(--cc-space-xs);flex-direction:column;display:flex}.cc-card__title[data-v-7f39ac3e]{letter-spacing:-.22px;color:inherit;font-size:22px;font-weight:300;line-height:1.1}.cc-card--pricing-featured .cc-card__title[data-v-7f39ac3e]{color:var(--cc-on-primary)}.cc-card__desc[data-v-7f39ac3e]{color:var(--cc-ink-mute);font-size:15px;font-weight:300;line-height:1.4}.cc-card--pricing-featured .cc-card__desc[data-v-7f39ac3e]{color:#ffffffb8}.cc-card__body[data-v-7f39ac3e]{flex:1}.cc-card--dashboard .cc-card__body[data-v-7f39ac3e]{letter-spacing:-.42px;font-size:14px;line-height:1.4}.cc-card__footer[data-v-7f39ac3e]{align-items:center;gap:var(--cc-space-md);padding-top:var(--cc-space-lg);display:flex}.cc-tag[data-v-858b2086]{align-items:center;gap:var(--cc-space-xs);border-radius:var(--cc-radius-pill);letter-spacing:.1px;text-transform:uppercase;white-space:nowrap;vertical-align:middle;padding:4px 8px;font-size:10px;font-weight:400;line-height:1.15;display:inline-flex}.cc-tag--sm[data-v-858b2086]{padding:2px 6px;font-size:9px}.cc-tag--soft[data-v-858b2086]{background-color:var(--cc-primary-subdued);color:var(--cc-primary-deep)}.cc-tag--outline[data-v-858b2086]{color:var(--cc-ink-mute);border:1px solid var(--cc-hairline);background-color:#0000;padding:3px 7px}.cc-tag--dark[data-v-858b2086]{background-color:var(--cc-brand-dark-900);color:var(--cc-on-primary)}.cc-tag--solid[data-v-858b2086]{background-color:var(--cc-primary);color:var(--cc-on-primary)}.cc-tag__dot[data-v-858b2086]{border-radius:var(--cc-radius-pill);opacity:.8;background-color:currentColor;width:5px;height:5px}.cc-tag__close[data-v-858b2086]{color:inherit;cursor:pointer;opacity:.7;background:0 0;border:0;justify-content:center;align-items:center;padding:0;transition:opacity .15s;display:inline-flex}.cc-tag__close[data-v-858b2086]:hover{opacity:1}.cc-badge[data-v-466a4bd0]{border-radius:var(--cc-radius-pill);vertical-align:middle;justify-content:center;align-items:center;min-width:18px;height:18px;padding:0 6px;font-size:11px;font-weight:400;line-height:1;display:inline-flex}.cc-badge--soft[data-v-466a4bd0]{background-color:var(--cc-primary-subdued);color:var(--cc-primary-deep)}.cc-badge--solid[data-v-466a4bd0]{background-color:var(--cc-primary);color:var(--cc-on-primary)}.cc-badge--dot[data-v-466a4bd0]{background-color:var(--cc-ruby);color:var(--cc-on-primary)}.cc-badge--dot-only[data-v-466a4bd0]{background-color:var(--cc-ruby);width:8px;min-width:8px;height:8px;padding:0}.cc-badge--dot-only .cc-badge__text[data-v-466a4bd0]{display:none}.cc-alert[data-v-8671adaf]{align-items:flex-start;gap:var(--cc-space-md);border:1px solid var(--cc-hairline);border-radius:var(--cc-radius-md);background-color:var(--cc-canvas-soft);padding:var(--cc-space-lg);font-family:var(--cc-font-family);display:flex}.cc-alert__icon[data-v-8671adaf]{flex-shrink:0;margin-top:1px;display:inline-flex}.cc-alert__content[data-v-8671adaf]{flex:1;min-width:0}.cc-alert__title[data-v-8671adaf]{color:var(--cc-ink);font-size:15px;font-weight:400;line-height:1.4}.cc-alert__desc[data-v-8671adaf]{color:var(--cc-ink-mute);margin-top:2px;font-size:13px;font-weight:300;line-height:1.4}.cc-alert__close[data-v-8671adaf]{color:var(--cc-ink-mute);cursor:pointer;border-radius:var(--cc-radius-xs);background:0 0;border:0;justify-content:center;align-items:center;padding:4px;transition:color .15s,background-color .15s;display:inline-flex}.cc-alert__close[data-v-8671adaf]:hover{color:var(--cc-ink);background-color:var(--cc-hairline)}.cc-modal[data-v-d2a6d4fd]{z-index:1000;padding:var(--cc-space-xl);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);background-color:#0d253d73;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.cc-modal__panel[data-v-d2a6d4fd]{background-color:var(--cc-canvas);border-radius:var(--cc-radius-lg);width:100%;box-shadow:var(--cc-shadow-level-2);padding:var(--cc-space-xl);gap:var(--cc-space-lg);outline:none;flex-direction:column;max-height:calc(100vh - 64px);display:flex;overflow-y:auto}.cc-modal__header[data-v-d2a6d4fd]{justify-content:space-between;align-items:flex-start;gap:var(--cc-space-lg);display:flex}.cc-modal__title[data-v-d2a6d4fd]{letter-spacing:-.22px;color:var(--cc-ink);font-size:22px;font-weight:300;line-height:1.1}.cc-modal__close[data-v-d2a6d4fd]{color:var(--cc-ink-mute);cursor:pointer;border-radius:var(--cc-radius-pill);background:0 0;border:0;flex-shrink:0;justify-content:center;align-items:center;padding:6px;transition:color .15s,background-color .15s;display:inline-flex}.cc-modal__close[data-v-d2a6d4fd]:hover{color:var(--cc-ink);background-color:var(--cc-canvas-soft)}.cc-modal__body[data-v-d2a6d4fd]{color:var(--cc-ink);font-size:15px;font-weight:300;line-height:1.5}.cc-modal__footer[data-v-d2a6d4fd]{justify-content:flex-end;align-items:center;gap:var(--cc-space-md);padding-top:var(--cc-space-md);display:flex}.cc-modal-enter-active[data-v-d2a6d4fd],.cc-modal-leave-active[data-v-d2a6d4fd]{transition:opacity .2s}.cc-modal-enter-active .cc-modal__panel[data-v-d2a6d4fd],.cc-modal-leave-active .cc-modal__panel[data-v-d2a6d4fd]{transition:transform .2s}.cc-modal-enter-from[data-v-d2a6d4fd],.cc-modal-leave-to[data-v-d2a6d4fd]{opacity:0}.cc-modal-enter-from .cc-modal__panel[data-v-d2a6d4fd],.cc-modal-leave-to .cc-modal__panel[data-v-d2a6d4fd]{transform:translateY(8px)scale(.98)}.cc-tooltip[data-v-2befb04b]{display:inline-flex;position:relative}.cc-tooltip__bubble[data-v-2befb04b]{z-index:900;border-radius:var(--cc-radius-sm);background-color:var(--cc-brand-dark-900);max-width:240px;color:var(--cc-on-primary);letter-spacing:-.24px;white-space:nowrap;pointer-events:none;box-shadow:var(--cc-shadow-level-2);padding:6px 10px;font-size:12px;font-weight:400;line-height:1.4;position:absolute}.cc-tooltip--top[data-v-2befb04b]{bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.cc-tooltip--bottom[data-v-2befb04b]{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.cc-tooltip--left[data-v-2befb04b]{top:50%;right:calc(100% + 6px);transform:translateY(-50%)}.cc-tooltip--right[data-v-2befb04b]{top:50%;left:calc(100% + 6px);transform:translateY(-50%)}.cc-tooltip__bubble[data-v-2befb04b]:after{content:"";background-color:var(--cc-brand-dark-900);width:6px;height:6px;position:absolute;transform:rotate(45deg)}.cc-tooltip--top[data-v-2befb04b]:after{margin:-3px 0 0 -3px;top:100%;left:50%}.cc-tooltip--bottom[data-v-2befb04b]:after{margin:0 0 -3px -3px;bottom:100%;left:50%}.cc-tooltip--left[data-v-2befb04b]:after{margin:-3px 0 0 -3px;top:50%;left:100%}.cc-tooltip--right[data-v-2befb04b]:after{margin:-3px -3px 0 0;top:50%;right:100%}.cc-divider[data-v-c42961cd]{align-items:center;width:100%;margin:0;display:flex}.cc-divider--horizontal[data-v-c42961cd]{background-color:var(--cc-hairline);height:1px}.cc-divider--horizontal.cc-divider[data-v-c42961cd]:has(.cc-divider__label){background-color:#0000}.cc-divider__label[data-v-c42961cd]{justify-content:center;align-items:center;gap:var(--cc-space-lg);color:var(--cc-ink-mute);letter-spacing:-.39px;white-space:nowrap;font-size:13px;font-weight:400;display:inline-flex}.cc-divider__label[data-v-c42961cd]:before,.cc-divider__label[data-v-c42961cd]:after{content:"";background-color:var(--cc-hairline);width:48px;height:1px}.cc-divider--vertical[data-v-c42961cd]{background-color:var(--cc-hairline);align-self:stretch;width:1px;height:100%}:root{--cc-primary:#533afd;--cc-primary-deep:#4434d4;--cc-primary-press:#2e2b8c;--cc-primary-soft:#665efd;--cc-primary-subdued:#b9b9f9;--cc-brand-dark-900:#1c1e54;--cc-ruby:#ea2261;--cc-magenta:#f96bee;--cc-lemon:#9b6829;--cc-canvas:#fff;--cc-canvas-soft:#f6f9fc;--cc-canvas-cream:#f5e9d4;--cc-hairline:#e3e8ee;--cc-hairline-input:#a8c3de;--cc-ink:#0d253d;--cc-ink-secondary:#273951;--cc-ink-mute:#64748d;--cc-ink-mute-2:#61718a;--cc-on-primary:#fff;--cc-success:#0a9f6e;--cc-success-soft:#e3f5ee;--cc-warning:#9b6829;--cc-warning-soft:#faf0e0;--cc-error:#ea2261;--cc-error-soft:#fde7ef;--cc-info:#533afd;--cc-shadow-blue:#003770;--cc-shadow-level-1:#00377014 0 1px 3px;--cc-shadow-level-2:#00377014 0 8px 24px, #0037700a 0 2px 6px;--cc-focus-ring:0 0 0 3px #533afd2e;--cc-font-family:"Inter", "SF Pro Display", system-ui, -apple-system, "Segoe UI", sans-serif;--cc-font-mono:ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;--cc-text-display-xxl:56px / 1.03 300 -1.4px;--cc-text-display-xl:48px / 1.15 300 -.96px;--cc-text-display-lg:32px / 1.1 300 -.64px;--cc-text-display-md:26px / 1.12 300 -.26px;--cc-text-heading-lg:22px / 1.1 300 -.22px;--cc-text-heading-md:20px / 1.4 300 -.2px;--cc-text-heading-sm:18px / 1.4 300 0;--cc-text-body-lg:16px / 1.4 300 0;--cc-text-body-md:15px / 1.4 300 0;--cc-text-body-tabular:14px / 1.4 300 -.42px;--cc-text-button-md:16px / 1 400 0;--cc-text-button-sm:14px / 1 400 0;--cc-text-caption:13px / 1.4 400 -.39px;--cc-text-micro:11px / 1.4 300 0;--cc-text-micro-cap:10px / 1.15 400 .1px;--cc-radius-xs:4px;--cc-radius-sm:6px;--cc-radius-md:8px;--cc-radius-lg:12px;--cc-radius-xl:16px;--cc-radius-pill:9999px;--cc-space-xxs:2px;--cc-space-xs:4px;--cc-space-sm:8px;--cc-space-md:12px;--cc-space-lg:16px;--cc-space-xl:24px;--cc-space-xxl:32px;--cc-space-huge:64px;--cc-container-max:1200px;--cc-input-height:40px}*,:before,:after{box-sizing:border-box}html{-webkit-text-size-adjust:100%}body{font-family:var(--cc-font-family);color:var(--cc-ink);background-color:var(--cc-canvas);font-feature-settings:"ss01";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;font-size:15px;font-weight:300;line-height:1.4}h1,h2,h3,h4,h5,h6{color:var(--cc-ink);margin:0;font-weight:300}p{margin:0}a{color:var(--cc-primary);text-decoration:none}a:hover{text-decoration:underline}::selection{background-color:var(--cc-ink);color:#f2f2f2}.tnum,.tnum *{font-feature-settings:"tnum";font-variant-numeric:tabular-nums}.cc-text-display-xxl{letter-spacing:-1.4px;font-size:56px;font-weight:300;line-height:1.03}.cc-text-display-xl{letter-spacing:-.96px;font-size:48px;font-weight:300;line-height:1.15}.cc-text-display-lg{letter-spacing:-.64px;font-size:32px;font-weight:300;line-height:1.1}.cc-text-display-md{letter-spacing:-.26px;font-size:26px;font-weight:300;line-height:1.12}.cc-text-heading-lg{letter-spacing:-.22px;font-size:22px;font-weight:300;line-height:1.1}.cc-text-heading-md{letter-spacing:-.2px;font-size:20px;font-weight:300;line-height:1.4}.cc-text-heading-sm{font-size:18px;font-weight:300;line-height:1.4}.cc-text-body-lg{font-size:16px;font-weight:300;line-height:1.4}.cc-text-body-md{font-size:15px;font-weight:300;line-height:1.4}.cc-text-caption{letter-spacing:-.39px;font-feature-settings:"tnum";font-size:13px;font-weight:400;line-height:1.4}.cc-text-micro{font-size:11px;font-weight:300;line-height:1.4}.cc-text-micro-cap{letter-spacing:.1px;text-transform:uppercase;font-size:10px;font-weight:400;line-height:1.15}
2
+ /*$vite$:1*/