@ciderpress/ui 1.0.0-rc.10 → 1.0.0-rc.11
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/dist/head/css/loader-apple.css +1 -1
- package/dist/head/css/loader-dots.css +1 -1
- package/dist/head/css/themes/amber.css +1 -1
- package/dist/head/css/themes/arcade.css +1 -1
- package/dist/head/css/themes/grannysmith.css +1 -1
- package/dist/head/css/themes/honeycrisp.css +1 -1
- package/dist/head/css/themes/midnight.css +1 -1
- package/dist/head/css/themes/mulled.css +1 -1
- package/dist/node.mjs +408 -15
- package/dist/theme/components/home/cta.css +15 -0
- package/dist/theme/components/home/cta.tsx +10 -2
- package/dist/theme/components/home/feature-card.css +1 -1
- package/dist/theme/components/home/feature-card.tsx +3 -2
- package/dist/theme/components/home/feature.tsx +34 -31
- package/dist/theme/components/home/hero-demo.css +11 -0
- package/dist/theme/components/home/home-visual.tsx +226 -0
- package/dist/theme/components/home/layout.tsx +350 -171
- package/dist/theme/components/home/split.css +46 -19
- package/dist/theme/components/home/split.tsx +28 -8
- package/dist/theme/components/home/tabs.css +299 -0
- package/dist/theme/components/home/tabs.tsx +351 -0
- package/dist/theme/components/home/trust-strip.css +41 -0
- package/dist/theme/components/home/trust-strip.tsx +168 -11
- package/dist/theme/components/home/workspaces.tsx +171 -69
- package/dist/theme/components/workspaces/card.css +4 -0
- package/dist/theme/components/workspaces/card.tsx +3 -3
- package/dist/theme/components/workspaces/grid.tsx +18 -6
- package/dist/theme/index.tsx +5 -0
- package/dist/theme/lib/rich-text-parse.ts +740 -0
- package/dist/theme/lib/rich-text.test.tsx +342 -0
- package/dist/theme/lib/rich-text.tsx +86 -0
- package/dist/theme/styles/overrides/fonts.css +7 -4
- package/dist/theme/styles/overrides/home.css +11 -2
- package/dist/theme/styles/overrides/rspress.css +10 -5
- package/dist/theme/styles/overrides/tokens.css +41 -23
- package/dist/theme/styles/rich-text.css +106 -0
- package/dist/theme/styles/themes/amber.css +32 -2
- package/dist/theme/styles/themes/arcade.css +16 -1
- package/dist/theme/styles/themes/grannysmith.css +32 -2
- package/dist/theme/styles/themes/honeycrisp.css +37 -7
- package/dist/theme/styles/themes/midnight.css +16 -1
- package/dist/theme/styles/themes/mulled.css +54 -9
- package/package.json +3 -3
- package/src/theme/components/home/cta.css +15 -0
- package/src/theme/components/home/cta.tsx +10 -2
- package/src/theme/components/home/feature-card.css +1 -1
- package/src/theme/components/home/feature-card.tsx +3 -2
- package/src/theme/components/home/feature.tsx +34 -31
- package/src/theme/components/home/hero-demo.css +11 -0
- package/src/theme/components/home/home-visual.tsx +226 -0
- package/src/theme/components/home/layout.tsx +350 -171
- package/src/theme/components/home/split.css +46 -19
- package/src/theme/components/home/split.tsx +28 -8
- package/src/theme/components/home/tabs.css +299 -0
- package/src/theme/components/home/tabs.tsx +351 -0
- package/src/theme/components/home/trust-strip.css +41 -0
- package/src/theme/components/home/trust-strip.tsx +168 -11
- package/src/theme/components/home/workspaces.tsx +171 -69
- package/src/theme/components/workspaces/card.css +4 -0
- package/src/theme/components/workspaces/card.tsx +3 -3
- package/src/theme/components/workspaces/grid.tsx +18 -6
- package/src/theme/index.tsx +5 -0
- package/src/theme/lib/rich-text-parse.ts +740 -0
- package/src/theme/lib/rich-text.test.tsx +342 -0
- package/src/theme/lib/rich-text.tsx +86 -0
- package/src/theme/styles/overrides/fonts.css +7 -4
- package/src/theme/styles/overrides/home.css +11 -2
- package/src/theme/styles/overrides/rspress.css +10 -5
- package/src/theme/styles/overrides/tokens.css +41 -23
- package/src/theme/styles/rich-text.css +106 -0
- package/src/theme/styles/themes/amber.css +32 -2
- package/src/theme/styles/themes/arcade.css +16 -1
- package/src/theme/styles/themes/grannysmith.css +32 -2
- package/src/theme/styles/themes/honeycrisp.css +37 -7
- package/src/theme/styles/themes/midnight.css +16 -1
- package/src/theme/styles/themes/mulled.css +54 -9
- package/dist/theme/components/home/hero-demo-custom.tsx +0 -116
- package/dist/theme/components/home/split-visual-custom.tsx +0 -26
- package/src/theme/components/home/hero-demo-custom.tsx +0 -116
- package/src/theme/components/home/split-visual-custom.tsx +0 -26
|
@@ -24,6 +24,24 @@
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/* Copy-only band — no visual to sit beside, so the copy owns the row. */
|
|
28
|
+
.cp-split__inner--full {
|
|
29
|
+
grid-template-columns: 1fr;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Reverse layout — visual first, copy second. Scoped to the two-column
|
|
33
|
+
grid: the narrow single-column stack always leads with the copy, so a
|
|
34
|
+
reversed band doesn't push its image above the headline. */
|
|
35
|
+
@media (min-width: 881px) {
|
|
36
|
+
.cp-split__inner--reverse .cp-split__copy {
|
|
37
|
+
order: 2;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cp-split__inner--reverse .cp-split__visual {
|
|
41
|
+
order: 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
27
45
|
.cp-split__copy {
|
|
28
46
|
min-width: 0;
|
|
29
47
|
}
|
|
@@ -33,10 +51,16 @@
|
|
|
33
51
|
font-size: var(--cp-fs-eyebrow);
|
|
34
52
|
text-transform: uppercase;
|
|
35
53
|
letter-spacing: var(--cp-letter-eyebrow);
|
|
36
|
-
|
|
54
|
+
/* Same shade pair as `.cp-accent` — `--cp-c-brand-1` is a fill colour and
|
|
55
|
+
misses 4.5:1 at this size on several themes. See styles/rich-text.css. */
|
|
56
|
+
color: var(--cp-c-brand-2, var(--cp-c-brand-1));
|
|
37
57
|
margin-bottom: var(--cp-s-12);
|
|
38
58
|
}
|
|
39
59
|
|
|
60
|
+
html[data-cp-variant='dark'] .cp-split__eyebrow {
|
|
61
|
+
color: var(--cp-c-brand-light, var(--cp-c-brand-1));
|
|
62
|
+
}
|
|
63
|
+
|
|
40
64
|
.cp-split__title {
|
|
41
65
|
font-size: var(--cp-fs-split-title);
|
|
42
66
|
font-weight: 600;
|
|
@@ -115,7 +139,7 @@
|
|
|
115
139
|
border-color: var(--cp-c-brand-2);
|
|
116
140
|
}
|
|
117
141
|
|
|
118
|
-
/*
|
|
142
|
+
/* Visual frame — wraps a native code block, an image, or a window child */
|
|
119
143
|
.cp-split__visual {
|
|
120
144
|
border: 1px solid var(--cp-c-border);
|
|
121
145
|
border-radius: var(--cp-radius-lg);
|
|
@@ -123,26 +147,29 @@
|
|
|
123
147
|
background: var(--cp-code-block-bg);
|
|
124
148
|
}
|
|
125
149
|
|
|
126
|
-
|
|
150
|
+
/* Native Rspress code block (Shiki) fills the frame — strip its own
|
|
151
|
+
margin and rounded corners so the frame owns the chrome. */
|
|
152
|
+
.cp-split__visual .rp-codeblock {
|
|
127
153
|
margin: 0;
|
|
128
|
-
|
|
129
|
-
font-family: var(--cp-font-family-mono);
|
|
130
|
-
font-size: var(--cp-fs-code);
|
|
131
|
-
line-height: var(--cp-lh-code);
|
|
132
|
-
white-space: pre;
|
|
133
|
-
overflow-x: auto;
|
|
134
|
-
color: var(--cp-c-text-1);
|
|
154
|
+
border-radius: 0;
|
|
135
155
|
}
|
|
136
156
|
|
|
137
|
-
.cp-split__visual .
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
.cp-split__visual .tok-str {
|
|
141
|
-
color: var(--cp-c-syntax-str);
|
|
157
|
+
.cp-split__visual .rp-codeblock pre {
|
|
158
|
+
overflow-x: auto;
|
|
142
159
|
}
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
|
|
161
|
+
/* Terminal visual reuses the hero demo chrome; the split frame already
|
|
162
|
+
owns the border, radius, and shadow, so flatten the inner shell. */
|
|
163
|
+
.cp-split__visual .cp-hero-demo {
|
|
164
|
+
max-width: none;
|
|
165
|
+
border: 0;
|
|
166
|
+
border-radius: 0;
|
|
167
|
+
box-shadow: none;
|
|
145
168
|
}
|
|
146
|
-
|
|
147
|
-
|
|
169
|
+
|
|
170
|
+
/* Image visual fills the frame width, preserving aspect ratio. */
|
|
171
|
+
.cp-split__img {
|
|
172
|
+
display: block;
|
|
173
|
+
width: 100%;
|
|
174
|
+
height: auto;
|
|
148
175
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { match } from 'massaman/match'
|
|
1
|
+
import { match, P } from 'massaman/match'
|
|
2
2
|
import type React from 'react'
|
|
3
3
|
|
|
4
|
+
import { renderRichText } from '../../lib/rich-text.tsx'
|
|
4
5
|
import { RouteLink } from '../../lib/route-link.tsx'
|
|
5
6
|
import { safeUrl } from '../../lib/safe-url.ts'
|
|
6
7
|
|
|
@@ -43,9 +44,16 @@ export interface SplitProps {
|
|
|
43
44
|
*/
|
|
44
45
|
readonly action?: SplitAction
|
|
45
46
|
/**
|
|
46
|
-
*
|
|
47
|
+
* Visual content — typically a code preview or screenshot. Omit (or
|
|
48
|
+
* pass `null`) for a copy-only band; the visual column collapses
|
|
49
|
+
* instead of painting an empty frame.
|
|
47
50
|
*/
|
|
48
|
-
readonly visual
|
|
51
|
+
readonly visual?: React.ReactNode
|
|
52
|
+
/**
|
|
53
|
+
* Flip the column order — visual first, copy second. Defaults to
|
|
54
|
+
* `false` (copy first, visual second).
|
|
55
|
+
*/
|
|
56
|
+
readonly reverse?: boolean
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
/**
|
|
@@ -56,17 +64,25 @@ export interface SplitProps {
|
|
|
56
64
|
* @returns React element.
|
|
57
65
|
*/
|
|
58
66
|
export function HomeSplit(props: SplitProps): React.ReactElement {
|
|
59
|
-
const { eyebrow, title, body, bullets, action, visual } = props
|
|
67
|
+
const { eyebrow, title, body, bullets, action, visual, reverse } = props
|
|
60
68
|
const list = bullets ?? []
|
|
69
|
+
// Without a visual the band is a single column — the two-column grid
|
|
70
|
+
// would otherwise leave half the row empty.
|
|
71
|
+
const layoutClass = match(visual)
|
|
72
|
+
.with(P.nullish, () => 'cp-split__inner cp-split__inner--full')
|
|
73
|
+
.otherwise(() => 'cp-split__inner')
|
|
74
|
+
const innerClass = match(reverse ?? false)
|
|
75
|
+
.with(true, () => `${layoutClass} cp-split__inner--reverse`)
|
|
76
|
+
.otherwise(() => layoutClass)
|
|
61
77
|
|
|
62
78
|
return (
|
|
63
79
|
<section className="cp-split">
|
|
64
|
-
<div className=
|
|
80
|
+
<div className={innerClass}>
|
|
65
81
|
<div className="cp-split__copy">
|
|
66
82
|
{match(eyebrow)
|
|
67
83
|
.with(undefined, () => null)
|
|
68
84
|
.otherwise((e) => (
|
|
69
|
-
<div className="cp-split__eyebrow">{e}</div>
|
|
85
|
+
<div className="cp-split__eyebrow">{renderRichText(e)}</div>
|
|
70
86
|
))}
|
|
71
87
|
<h2 className="cp-split__title">{title}</h2>
|
|
72
88
|
{match(body)
|
|
@@ -81,7 +97,7 @@ export function HomeSplit(props: SplitProps): React.ReactElement {
|
|
|
81
97
|
{list.map((bullet) => (
|
|
82
98
|
<li key={bullet}>
|
|
83
99
|
<span className="cp-split__check">✓</span>
|
|
84
|
-
<span>{bullet}</span>
|
|
100
|
+
<span>{renderRichText(bullet)}</span>
|
|
85
101
|
</li>
|
|
86
102
|
))}
|
|
87
103
|
</ul>
|
|
@@ -100,7 +116,11 @@ export function HomeSplit(props: SplitProps): React.ReactElement {
|
|
|
100
116
|
)
|
|
101
117
|
})}
|
|
102
118
|
</div>
|
|
103
|
-
|
|
119
|
+
{match(visual)
|
|
120
|
+
.with(P.nullish, () => null)
|
|
121
|
+
.otherwise((v) => (
|
|
122
|
+
<div className="cp-split__visual">{v}</div>
|
|
123
|
+
))}
|
|
104
124
|
</div>
|
|
105
125
|
</section>
|
|
106
126
|
)
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
.cp-tabs {
|
|
2
|
+
padding: var(--cp-s-96) var(--cp-s-32);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@media (max-width: 720px) {
|
|
6
|
+
.cp-tabs {
|
|
7
|
+
padding: var(--cp-s-64) var(--cp-s-20);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.cp-tabs__inner {
|
|
12
|
+
max-width: var(--cp-size-split-max);
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* ── Vertical band — strip beside the panel ──────────────────── */
|
|
17
|
+
.cp-tabs--vertical .cp-tabs__inner {
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-columns: minmax(220px, 320px) minmax(0, 1fr);
|
|
20
|
+
gap: var(--cp-s-48);
|
|
21
|
+
align-items: start;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Reverse — panel left, strip right. Scoped to the two-column grid so
|
|
25
|
+
the narrow stack always leads with the tabs.
|
|
26
|
+
|
|
27
|
+
The TRACKS swap, not the items. `order` changes which track each item
|
|
28
|
+
lands in but leaves the track sizes where they are, so ordering alone
|
|
29
|
+
put the panel — headline, body, bullets and its visual — into the
|
|
30
|
+
220-320px strip column and stretched the tab labels across the 1fr
|
|
31
|
+
remainder. The idiom was borrowed from split.css, where the columns are
|
|
32
|
+
a symmetric `1fr 1fr` and reordering is equivalent. */
|
|
33
|
+
@media (min-width: 881px) {
|
|
34
|
+
.cp-tabs--vertical.cp-tabs--reverse .cp-tabs__inner {
|
|
35
|
+
grid-template-columns: minmax(0, 1fr) minmax(220px, 320px);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cp-tabs--vertical.cp-tabs--reverse .cp-tabs__list {
|
|
39
|
+
order: 2;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.cp-tabs--vertical.cp-tabs--reverse .cp-tabs__panel {
|
|
43
|
+
order: 1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@media (max-width: 880px) {
|
|
48
|
+
.cp-tabs--vertical .cp-tabs__inner {
|
|
49
|
+
grid-template-columns: 1fr;
|
|
50
|
+
gap: var(--cp-s-32);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.cp-tabs--vertical .cp-tabs__list {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
gap: var(--cp-s-4);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cp-tabs--vertical .cp-tabs__tab[data-selected] {
|
|
61
|
+
box-shadow: inset 2px 0 0 var(--cp-c-brand-1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.cp-tabs--vertical .cp-tabs__panel {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: var(--cp-s-24);
|
|
68
|
+
min-width: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* ── Horizontal band — strip above the panel ─────────────────── */
|
|
72
|
+
.cp-tabs--horizontal .cp-tabs__inner {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
gap: var(--cp-s-40);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cp-tabs--horizontal .cp-tabs__list {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-wrap: wrap;
|
|
81
|
+
gap: var(--cp-s-8);
|
|
82
|
+
border-bottom: 1px solid var(--cp-c-border);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.cp-tabs--horizontal .cp-tabs__tab {
|
|
86
|
+
border-radius: var(--cp-radius-md) var(--cp-radius-md) 0 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.cp-tabs--horizontal .cp-tabs__tab[data-selected] {
|
|
90
|
+
box-shadow: inset 0 -2px 0 var(--cp-c-brand-1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.cp-tabs--horizontal .cp-tabs__panel {
|
|
94
|
+
display: grid;
|
|
95
|
+
grid-template-columns: 1fr 1fr;
|
|
96
|
+
gap: var(--cp-s-48);
|
|
97
|
+
align-items: center;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@media (max-width: 880px) {
|
|
101
|
+
.cp-tabs--horizontal .cp-tabs__panel {
|
|
102
|
+
grid-template-columns: 1fr;
|
|
103
|
+
gap: var(--cp-s-32);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Copy-only tab — no visual to sit beside, so the copy owns the row. */
|
|
108
|
+
.cp-tabs--horizontal .cp-tabs__panel--full {
|
|
109
|
+
grid-template-columns: 1fr;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* ── Tab ─────────────────────────────────────────────────────── */
|
|
113
|
+
.cp-tabs__tab {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
gap: var(--cp-s-12);
|
|
117
|
+
padding: var(--cp-s-12) var(--cp-s-16);
|
|
118
|
+
border-radius: var(--cp-radius-md);
|
|
119
|
+
font-size: var(--cp-fs-body);
|
|
120
|
+
color: var(--cp-c-text-2);
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
transition:
|
|
123
|
+
background var(--cp-duration-fast) var(--cp-ease-base),
|
|
124
|
+
color var(--cp-duration-fast) var(--cp-ease-base);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.cp-tabs__tab[data-hovered] {
|
|
128
|
+
background: var(--cp-c-bg-soft);
|
|
129
|
+
color: var(--cp-c-text-1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.cp-tabs__tab[data-selected] {
|
|
133
|
+
background: var(--cp-c-brand-soft);
|
|
134
|
+
color: var(--cp-c-text-1);
|
|
135
|
+
font-weight: 600;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.cp-tabs__tab[data-focus-visible] {
|
|
139
|
+
outline: var(--cp-size-focus-ring) solid var(--cp-c-brand-1);
|
|
140
|
+
outline-offset: var(--cp-size-focus-ring-offset);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Shrink the shared card icon chip to strip scale. */
|
|
144
|
+
.cp-tabs__tab .cp-card__icon {
|
|
145
|
+
width: var(--cp-size-icon-box-sm);
|
|
146
|
+
height: var(--cp-size-icon-box-sm);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.cp-tabs__tab .cp-card__icon svg {
|
|
150
|
+
width: var(--cp-size-icon-svg-sm);
|
|
151
|
+
height: var(--cp-size-icon-svg-sm);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.cp-tabs__tab-label {
|
|
155
|
+
min-width: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* ── Panel copy ──────────────────────────────────────────────── */
|
|
159
|
+
.cp-tabs__copy {
|
|
160
|
+
min-width: 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.cp-tabs__title {
|
|
164
|
+
font-size: clamp(20px, 2.2vw, 26px);
|
|
165
|
+
font-weight: 600;
|
|
166
|
+
letter-spacing: var(--cp-letter-display);
|
|
167
|
+
line-height: var(--cp-lh-display);
|
|
168
|
+
margin: 0 0 var(--cp-s-12);
|
|
169
|
+
color: var(--cp-c-text-1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.cp-tabs__body {
|
|
173
|
+
font-size: var(--cp-fs-body);
|
|
174
|
+
line-height: var(--cp-lh-relaxed);
|
|
175
|
+
color: var(--cp-c-text-2);
|
|
176
|
+
margin: 0 0 var(--cp-s-20);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.cp-tabs__bullets {
|
|
180
|
+
list-style: none;
|
|
181
|
+
margin: 0 0 var(--cp-s-20);
|
|
182
|
+
padding: 0;
|
|
183
|
+
display: flex;
|
|
184
|
+
flex-direction: column;
|
|
185
|
+
gap: var(--cp-s-12);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.cp-tabs__bullets li {
|
|
189
|
+
display: flex;
|
|
190
|
+
gap: var(--cp-s-12);
|
|
191
|
+
font-size: var(--cp-fs-bullet);
|
|
192
|
+
color: var(--cp-c-text-1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* The glyph is real text (`✓`), so contrast rules apply to it. Against the
|
|
196
|
+
near-transparent `--cp-c-brand-soft` chip it is effectively brand-on-page,
|
|
197
|
+
which measured 2.27:1 on mulled/dark and under 4:1 on four other combos —
|
|
198
|
+
legible as a smudge at best. `--cp-c-text-1` on the same chip is the
|
|
199
|
+
pairing already used by `.cp-mark`, and clears 12.7:1 everywhere. */
|
|
200
|
+
.cp-tabs__check {
|
|
201
|
+
width: var(--cp-size-check);
|
|
202
|
+
height: var(--cp-size-check);
|
|
203
|
+
border-radius: 50%;
|
|
204
|
+
background: var(--cp-c-brand-soft);
|
|
205
|
+
color: var(--cp-c-text-1);
|
|
206
|
+
display: grid;
|
|
207
|
+
place-items: center;
|
|
208
|
+
font-size: var(--cp-fs-check);
|
|
209
|
+
flex-shrink: 0;
|
|
210
|
+
margin-top: var(--cp-s-2);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* On the vertical axis the CTA is a panel-level child rendered after the
|
|
215
|
+
* visual, so it closes the panel instead of splitting the body copy from
|
|
216
|
+
* the visual. Horizontal keeps its CTA inside the copy column, where the
|
|
217
|
+
* side-by-side columns already put it in the right place.
|
|
218
|
+
*/
|
|
219
|
+
.cp-tabs--vertical .cp-tabs__panel > .cp-tabs__actions {
|
|
220
|
+
display: flex;
|
|
221
|
+
justify-content: flex-start;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.cp-tabs__btn {
|
|
225
|
+
display: inline-flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
gap: var(--cp-s-8);
|
|
228
|
+
padding: var(--cp-s-10) var(--cp-s-18);
|
|
229
|
+
font-size: var(--cp-fs-btn);
|
|
230
|
+
font-weight: 500;
|
|
231
|
+
border-radius: var(--cp-radius-pill);
|
|
232
|
+
border: 1px solid var(--cp-c-border);
|
|
233
|
+
background: transparent;
|
|
234
|
+
color: var(--cp-c-text-1);
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
/* Named rather than `all`: `all` would animate any layout property added
|
|
237
|
+
later, turning a padding tweak into an unintended reflow animation. */
|
|
238
|
+
transition:
|
|
239
|
+
background var(--cp-duration-fast) var(--cp-ease-base),
|
|
240
|
+
border-color var(--cp-duration-fast) var(--cp-ease-base),
|
|
241
|
+
color var(--cp-duration-fast) var(--cp-ease-base);
|
|
242
|
+
text-decoration: none;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.cp-tabs__btn:hover {
|
|
246
|
+
background: var(--cp-c-bg-soft);
|
|
247
|
+
border-color: var(--cp-c-border);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Matches the ring on `.cp-tabs__tab` — without it the CTA fell back to the
|
|
251
|
+
UA default outline, which is nearly invisible on the dark themes and read
|
|
252
|
+
as a different focus treatment inside one component. */
|
|
253
|
+
.cp-tabs__btn:focus-visible {
|
|
254
|
+
outline: var(--cp-size-focus-ring) solid var(--cp-c-brand-1);
|
|
255
|
+
outline-offset: var(--cp-size-focus-ring-offset);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.cp-tabs__btn--primary {
|
|
259
|
+
background: var(--cp-c-brand-1);
|
|
260
|
+
color: var(--cp-c-brand-fg);
|
|
261
|
+
border-color: var(--cp-c-brand-1);
|
|
262
|
+
font-weight: 600;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.cp-tabs__btn--primary:hover {
|
|
266
|
+
background: var(--cp-c-brand-2);
|
|
267
|
+
border-color: var(--cp-c-brand-2);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* ── Panel visual — same frame as the split band ─────────────── */
|
|
271
|
+
.cp-tabs__visual {
|
|
272
|
+
border: 1px solid var(--cp-c-border);
|
|
273
|
+
border-radius: var(--cp-radius-lg);
|
|
274
|
+
overflow: hidden;
|
|
275
|
+
background: var(--cp-code-block-bg);
|
|
276
|
+
min-width: 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.cp-tabs__visual .rp-codeblock {
|
|
280
|
+
margin: 0;
|
|
281
|
+
border-radius: 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.cp-tabs__visual .rp-codeblock pre {
|
|
285
|
+
overflow-x: auto;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.cp-tabs__visual .cp-hero-demo {
|
|
289
|
+
max-width: none;
|
|
290
|
+
border: 0;
|
|
291
|
+
border-radius: 0;
|
|
292
|
+
box-shadow: none;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.cp-tabs__img {
|
|
296
|
+
display: block;
|
|
297
|
+
width: 100%;
|
|
298
|
+
height: auto;
|
|
299
|
+
}
|