@gemboss/website-ui 0.0.0-stage → 0.2.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/AGENTS.md +191 -0
- package/CHANGELOG.md +47 -0
- package/README.md +118 -2
- package/bin/gemboss-website.mjs +78 -0
- package/bin/lib/check.mjs +695 -0
- package/bin/lib/gap.mjs +189 -0
- package/bin/lib/init.mjs +99 -0
- package/bin/lib/upgrade.mjs +155 -0
- package/bin/lib/util.mjs +147 -0
- package/css/base.css +107 -0
- package/css/components.css +324 -0
- package/css/footer.css +53 -0
- package/css/header.css +231 -0
- package/css/layout.css +59 -0
- package/css/prose.css +119 -0
- package/css/sections.css +173 -0
- package/css/tokens.css +200 -0
- package/demo/index.html +703 -0
- package/demo/theme-example.html +133 -0
- package/docs/components.md +407 -0
- package/docs/markup-contract.md +148 -0
- package/docs/philosophy.md +69 -0
- package/docs/theming.md +96 -0
- package/js/website.js +186 -0
- package/package.json +50 -4
- package/skill/SKILL.md +49 -0
- package/system.json +122 -0
- package/templates/footer.html +40 -0
- package/templates/header.html +60 -0
- package/templates/page.html +134 -0
- package/templates/sections/cta.html +15 -0
- package/templates/sections/faq.html +24 -0
- package/templates/sections/features.html +32 -0
- package/templates/sections/hero.html +27 -0
- package/templates/sections/logos.html +15 -0
- package/templates/sections/pricing.html +51 -0
- package/templates/sections/prose.html +36 -0
- package/templates/sections/quote.html +13 -0
- package/templates/sections/showcase.html +25 -0
- package/templates/sections/split.html +27 -0
- package/templates/sections/stats.html +26 -0
- package/templates/sections/steps.html +17 -0
- package/website.css +1274 -0
- package/website.min.css +1 -0
package/css/header.css
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/* header: announcement, a flat 64px bar with one hairline, mega menu, mobile menu below 1080px.
|
|
2
|
+
Not a floating pill: no radius, no blur, no shadow on the bar. Nothing tucks under it. */
|
|
3
|
+
.gw-announce {
|
|
4
|
+
padding: 8px var(--gw-gutter);
|
|
5
|
+
border-bottom: 1px solid var(--gw-line);
|
|
6
|
+
background: var(--gw-bg-soft);
|
|
7
|
+
color: var(--gw-ink-2);
|
|
8
|
+
font-size: 13px;
|
|
9
|
+
line-height: 1.5;
|
|
10
|
+
text-align: center;
|
|
11
|
+
}
|
|
12
|
+
.gw-announce a { color: var(--gw-ink); font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }
|
|
13
|
+
|
|
14
|
+
.gw-header {
|
|
15
|
+
position: sticky;
|
|
16
|
+
top: 0;
|
|
17
|
+
z-index: 50;
|
|
18
|
+
border-bottom: 1px solid var(--gw-line);
|
|
19
|
+
background: var(--gw-surface);
|
|
20
|
+
}
|
|
21
|
+
.gw-header.is-scrolled { border-bottom-color: var(--gw-line-strong); }
|
|
22
|
+
.gw-header__bar { display: flex; align-items: center; gap: 16px; height: var(--gw-header-height); }
|
|
23
|
+
|
|
24
|
+
.gw-brand {
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 8px;
|
|
28
|
+
flex: none;
|
|
29
|
+
min-height: 44px;
|
|
30
|
+
color: var(--gw-ink);
|
|
31
|
+
font-size: 18px;
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
letter-spacing: -0.01em;
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
}
|
|
36
|
+
.gw-brand__mark { flex: none; width: 26px; height: 26px; }
|
|
37
|
+
.gw-brand__name { line-height: 1.2; }
|
|
38
|
+
|
|
39
|
+
/* desktop nav */
|
|
40
|
+
.gw-nav { display: none; }
|
|
41
|
+
.gw-nav__list { display: flex; align-items: center; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
42
|
+
.gw-nav__trigger,
|
|
43
|
+
.gw-nav__link {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: 6px;
|
|
47
|
+
height: 40px;
|
|
48
|
+
padding: 0 12px;
|
|
49
|
+
border: 0;
|
|
50
|
+
border-radius: var(--gw-radius-action);
|
|
51
|
+
background: transparent;
|
|
52
|
+
color: var(--gw-ink-2);
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
line-height: 1.4;
|
|
56
|
+
white-space: nowrap;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
}
|
|
59
|
+
.gw-nav__trigger:hover,
|
|
60
|
+
.gw-nav__link:hover,
|
|
61
|
+
.gw-nav__item.is-open > .gw-nav__trigger { background: var(--gw-bg-soft); color: var(--gw-ink); }
|
|
62
|
+
/* the chevron: the site's own 24px path, drawn as a mask so it takes currentColor */
|
|
63
|
+
.gw-nav__trigger::after,
|
|
64
|
+
.gw-mobile-menu__group > summary::after {
|
|
65
|
+
content: "";
|
|
66
|
+
flex: none;
|
|
67
|
+
width: 12px;
|
|
68
|
+
height: 12px;
|
|
69
|
+
background: currentColor;
|
|
70
|
+
opacity: 0.6;
|
|
71
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 9l6 6 6-6' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 12px no-repeat;
|
|
72
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 9l6 6 6-6' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 12px no-repeat;
|
|
73
|
+
transition: transform 0.18s var(--gw-ease);
|
|
74
|
+
}
|
|
75
|
+
.gw-nav__trigger[aria-expanded="true"]::after,
|
|
76
|
+
.gw-mobile-menu__group[open] > summary::after { transform: rotate(180deg); }
|
|
77
|
+
.gw-nav__link[aria-current="page"] {
|
|
78
|
+
color: var(--gw-ink);
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
text-decoration: underline;
|
|
81
|
+
text-decoration-color: var(--gw-accent);
|
|
82
|
+
text-decoration-thickness: 2px;
|
|
83
|
+
text-underline-offset: 8px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* mega menu: a floating card centred under the bar, as on gemboss.ai (Chris 24/10/2026): one hairline, radius 20,
|
|
87
|
+
the raised shadow (it is a popover), 32px inside. The bridge (::before) keeps the pointer inside while it crosses
|
|
88
|
+
the 8px gap from the trigger. */
|
|
89
|
+
.gw-mega {
|
|
90
|
+
position: absolute;
|
|
91
|
+
top: calc(100% + 8px);
|
|
92
|
+
left: 50%;
|
|
93
|
+
width: min(960px, calc(100vw - 40px));
|
|
94
|
+
max-height: calc(100vh - var(--gw-header-height) - 24px);
|
|
95
|
+
overflow-y: auto;
|
|
96
|
+
transform: translateX(-50%);
|
|
97
|
+
border: 1px solid var(--gw-line);
|
|
98
|
+
border-radius: 20px;
|
|
99
|
+
background: var(--gw-surface);
|
|
100
|
+
box-shadow: var(--gw-shadow-raised);
|
|
101
|
+
}
|
|
102
|
+
.gw-mega::before { content: ""; position: absolute; top: -12px; left: 0; right: 0; height: 12px; }
|
|
103
|
+
.gw-mega:not([hidden]) { animation: gw-mega-in 0.16s var(--gw-ease); }
|
|
104
|
+
@keyframes gw-mega-in { from { opacity: 0; transform: translateX(-50%) translateY(8px); } }
|
|
105
|
+
@media (prefers-reduced-motion: reduce) { .gw-mega:not([hidden]) { animation: none; } }
|
|
106
|
+
.gw-mega > .gw-wrap { width: auto; margin: 0; }
|
|
107
|
+
.gw-mega__grid { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 32px; padding: 32px; }
|
|
108
|
+
.gw-mega__col { display: flex; flex-direction: column; gap: 2px; }
|
|
109
|
+
.gw-mega__heading { padding: 0 8px 8px; color: var(--gw-muted); font-size: 12px; font-weight: 500; }
|
|
110
|
+
.gw-mega__link {
|
|
111
|
+
display: grid;
|
|
112
|
+
grid-template-columns: 32px minmax(0, 1fr);
|
|
113
|
+
align-items: start;
|
|
114
|
+
gap: 12px;
|
|
115
|
+
padding: 8px;
|
|
116
|
+
border-radius: var(--gw-radius-action);
|
|
117
|
+
color: var(--gw-ink);
|
|
118
|
+
}
|
|
119
|
+
.gw-mega__link:hover { background: var(--gw-bg-soft); }
|
|
120
|
+
.gw-mega__link b { display: block; font-size: 14px; font-weight: 500; line-height: 20px; }
|
|
121
|
+
.gw-mega__link i { display: block; margin-top: 2px; color: var(--gw-muted); font-size: 13px; font-style: normal; line-height: 18px; }
|
|
122
|
+
.gw-mega__link[aria-current="page"] b { color: var(--gw-accent-strong); font-weight: 600; }
|
|
123
|
+
.gw-mega__icon {
|
|
124
|
+
display: grid;
|
|
125
|
+
place-items: center;
|
|
126
|
+
width: 32px;
|
|
127
|
+
height: 32px;
|
|
128
|
+
border: 1px solid var(--gw-line);
|
|
129
|
+
border-radius: var(--gw-radius-action);
|
|
130
|
+
background: var(--gw-surface);
|
|
131
|
+
color: var(--gw-muted);
|
|
132
|
+
}
|
|
133
|
+
.gw-mega__icon svg { width: 16px; height: 16px; }
|
|
134
|
+
.gw-mega__link:hover .gw-mega__icon { border-color: var(--gw-accent-soft); background: var(--gw-accent-soft); color: var(--gw-accent-strong); }
|
|
135
|
+
/* the feature card is the Stage (the house illustration recipe, Chris 22/10/2026): a night ground lit with the accent
|
|
136
|
+
from two corners, white words. An illustration may light itself, so its glows are gradients, not chrome shadows. */
|
|
137
|
+
.gw-mega__feature {
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
justify-content: flex-end;
|
|
141
|
+
gap: 4px;
|
|
142
|
+
min-height: 216px;
|
|
143
|
+
padding: 24px;
|
|
144
|
+
border-radius: var(--gw-radius-panel);
|
|
145
|
+
background:
|
|
146
|
+
radial-gradient(360px 260px at 12% 112%, color-mix(in srgb, var(--gw-accent) 78%, transparent), transparent 62%),
|
|
147
|
+
radial-gradient(300px 220px at 92% -14%, color-mix(in srgb, var(--gw-wash-violet) 44%, transparent), transparent 70%),
|
|
148
|
+
var(--gw-night);
|
|
149
|
+
color: var(--gw-on-night);
|
|
150
|
+
}
|
|
151
|
+
.gw-mega__feature b { font-size: 18px; font-weight: 650; line-height: 1.25; }
|
|
152
|
+
.gw-mega__feature i { color: var(--gw-on-night); font-size: 13px; font-style: normal; line-height: 1.5; opacity: 0.9; }
|
|
153
|
+
.gw-mega__feature .gw-link--arrow { margin-top: 16px; color: var(--gw-on-night); font-size: 13px; font-weight: 600; }
|
|
154
|
+
|
|
155
|
+
/* actions on the right */
|
|
156
|
+
.gw-header__actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
|
|
157
|
+
.gw-header__signin { display: none; }
|
|
158
|
+
.gw-header__actions > .gw-btn { display: none; }
|
|
159
|
+
.gw-theme-toggle,
|
|
160
|
+
.gw-menu-toggle {
|
|
161
|
+
display: inline-flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
flex: none;
|
|
165
|
+
width: 40px;
|
|
166
|
+
height: 40px;
|
|
167
|
+
padding: 0;
|
|
168
|
+
border: 0;
|
|
169
|
+
border-radius: var(--gw-radius-action);
|
|
170
|
+
background: transparent;
|
|
171
|
+
color: var(--gw-ink);
|
|
172
|
+
}
|
|
173
|
+
.gw-theme-toggle:hover,
|
|
174
|
+
.gw-menu-toggle:hover { background: var(--gw-bg-soft); }
|
|
175
|
+
.gw-theme-toggle svg,
|
|
176
|
+
.gw-menu-toggle svg { width: 20px; height: 20px; }
|
|
177
|
+
.gw-menu-toggle[aria-expanded="true"] .gw-menu-toggle__open,
|
|
178
|
+
.gw-menu-toggle:not([aria-expanded="true"]) .gw-menu-toggle__close { display: none; }
|
|
179
|
+
|
|
180
|
+
/* mobile menu: a full-height sheet under the bar; html.is-menu-open locks the page */
|
|
181
|
+
.gw-mobile-menu {
|
|
182
|
+
position: fixed;
|
|
183
|
+
top: calc(var(--gw-header-height) + 1px);
|
|
184
|
+
left: 0;
|
|
185
|
+
right: 0;
|
|
186
|
+
bottom: 0;
|
|
187
|
+
overflow-y: auto;
|
|
188
|
+
overscroll-behavior: contain;
|
|
189
|
+
padding-block: 8px 32px;
|
|
190
|
+
background: var(--gw-bg);
|
|
191
|
+
}
|
|
192
|
+
html.is-menu-open { overflow: hidden; }
|
|
193
|
+
html.is-menu-open .gw-header { position: fixed; top: 0; left: 0; right: 0; }
|
|
194
|
+
.gw-mobile-menu__group > summary,
|
|
195
|
+
.gw-mobile-menu__top {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: space-between;
|
|
199
|
+
min-height: 48px;
|
|
200
|
+
padding-block: 8px;
|
|
201
|
+
border-bottom: 1px solid var(--gw-line);
|
|
202
|
+
color: var(--gw-ink);
|
|
203
|
+
font-size: 18px;
|
|
204
|
+
font-weight: 500;
|
|
205
|
+
list-style: none;
|
|
206
|
+
cursor: pointer;
|
|
207
|
+
}
|
|
208
|
+
.gw-mobile-menu__group > summary::-webkit-details-marker { display: none; }
|
|
209
|
+
.gw-mobile-menu__list { margin: 0; padding: 8px 0 16px; list-style: none; }
|
|
210
|
+
.gw-mobile-menu__link { display: flex; align-items: center; min-height: 44px; color: var(--gw-ink-2); font-size: 16px; }
|
|
211
|
+
.gw-mobile-menu__link[aria-current="page"],
|
|
212
|
+
.gw-mobile-menu__top[aria-current="page"] { color: var(--gw-accent-strong); font-weight: 600; }
|
|
213
|
+
.gw-mobile-menu__actions { display: grid; gap: 8px; margin-top: 24px; }
|
|
214
|
+
|
|
215
|
+
@media (min-width: 480px) {
|
|
216
|
+
.gw-header__actions > .gw-btn:not(.gw-btn--secondary) { display: inline-flex; }
|
|
217
|
+
}
|
|
218
|
+
@media (min-width: 768px) {
|
|
219
|
+
.gw-header__actions > .gw-btn--secondary { display: inline-flex; }
|
|
220
|
+
}
|
|
221
|
+
@media (min-width: 1080px) {
|
|
222
|
+
.gw-header__bar { gap: 32px; }
|
|
223
|
+
.gw-nav { display: block; }
|
|
224
|
+
.gw-header__signin { display: inline-flex; }
|
|
225
|
+
.gw-menu-toggle, .gw-mobile-menu { display: none !important; }
|
|
226
|
+
html.is-menu-open { overflow: visible; }
|
|
227
|
+
html.is-menu-open .gw-header { position: sticky; }
|
|
228
|
+
}
|
|
229
|
+
@media (max-width: 768px), (pointer: coarse) {
|
|
230
|
+
.gw-theme-toggle, .gw-menu-toggle { width: var(--gw-tap-min); height: var(--gw-tap-min); }
|
|
231
|
+
}
|
package/css/layout.css
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* layout: widths, section rhythm, grids, night band. Breakpoints 480 / 768 / 1080 (system.json). */
|
|
2
|
+
.gw-wrap,
|
|
3
|
+
.gw-wrap--narrow {
|
|
4
|
+
width: min(100% - 2 * var(--gw-gutter), var(--gw-wrap));
|
|
5
|
+
margin-inline: auto;
|
|
6
|
+
}
|
|
7
|
+
.gw-wrap--narrow { max-width: var(--gw-wrap-narrow); }
|
|
8
|
+
|
|
9
|
+
.gw-section { padding-block: var(--gw-space-section); }
|
|
10
|
+
.gw-section--soft { background: var(--gw-bg-soft); }
|
|
11
|
+
.gw-section--tight { padding-block: 40px; }
|
|
12
|
+
@media (min-width: 768px) { .gw-section--tight { padding-block: 64px; } }
|
|
13
|
+
|
|
14
|
+
/* label + h2 + one or two lines; the vertical flow of every text block in the kit */
|
|
15
|
+
.gw-section__head { max-width: 660px; }
|
|
16
|
+
.gw-section__head--center { margin-inline: auto; text-align: center; }
|
|
17
|
+
.gw-section__head--center .gw-lead { margin-inline: auto; }
|
|
18
|
+
.gw-section__head:not(:last-child) { margin-bottom: 40px; }
|
|
19
|
+
@media (min-width: 768px) { .gw-section__head:not(:last-child) { margin-bottom: 48px; } }
|
|
20
|
+
|
|
21
|
+
:where(.gw-section__head, .gw-hero > .gw-wrap, .gw-split > :not(.gw-window), .gw-cta, .gw-card, .gw-feature, .gw-plan) > * + * { margin-top: 16px; }
|
|
22
|
+
:where(.gw-section__head, .gw-hero > .gw-wrap, .gw-split > :not(.gw-window), .gw-cta, .gw-card, .gw-plan) > :is(.gw-actions, .gw-segmented) { margin-top: 32px; }
|
|
23
|
+
:where(.gw-section__head, .gw-hero > .gw-wrap, .gw-split > :not(.gw-window), .gw-cta, .gw-card, .gw-plan) > .gw-list--check { margin-top: 24px; }
|
|
24
|
+
|
|
25
|
+
/* a row of actions: one .gw-btn, then a secondary or a link */
|
|
26
|
+
.gw-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
|
|
27
|
+
|
|
28
|
+
/* grids: one column on phones */
|
|
29
|
+
.gw-grid,
|
|
30
|
+
.gw-grid--2,
|
|
31
|
+
.gw-grid--3,
|
|
32
|
+
.gw-grid--4 {
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-columns: minmax(0, 1fr);
|
|
35
|
+
gap: 16px;
|
|
36
|
+
}
|
|
37
|
+
@media (min-width: 480px) {
|
|
38
|
+
.gw-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
39
|
+
}
|
|
40
|
+
@media (min-width: 768px) {
|
|
41
|
+
.gw-grid, .gw-grid--2, .gw-grid--3, .gw-grid--4 { gap: 24px; }
|
|
42
|
+
.gw-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
43
|
+
.gw-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
44
|
+
}
|
|
45
|
+
@media (min-width: 1080px) {
|
|
46
|
+
.gw-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* night band: the dark palette (tokens.css) on the night ground, lit from the top edge.
|
|
50
|
+
At most three on a page, never two in a row. */
|
|
51
|
+
.gw-band--night,
|
|
52
|
+
.gw-showcase {
|
|
53
|
+
position: relative;
|
|
54
|
+
isolation: isolate;
|
|
55
|
+
color: var(--gw-ink);
|
|
56
|
+
background:
|
|
57
|
+
radial-gradient(800px 360px at 50% 0%, color-mix(in srgb, var(--gw-accent) 22%, transparent), transparent 72%),
|
|
58
|
+
var(--gw-night);
|
|
59
|
+
}
|
package/css/prose.css
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* prose: long-form reading (a blog post, a docs page, terms and privacy) inside one wrapper, .gw-prose. The plain HTML a
|
|
2
|
+
CMS or a markdown renderer writes is styled as it comes: headings, paragraphs, lists, quotes, code, tables, images
|
|
3
|
+
and captions, on the kit's scales. The rules sit at :where() weight and reach bare elements only (lists without a
|
|
4
|
+
class, the wrapper's own headings, quotes and tables), so a kit component placed inside the prose (.gw-table,
|
|
5
|
+
.gw-window, .gw-list--check, .gw-quote, .gw-btn) keeps its own look. --sm: a 16px body for docs and legal. */
|
|
6
|
+
.gw-prose {
|
|
7
|
+
max-width: 68ch;
|
|
8
|
+
min-width: 0;
|
|
9
|
+
color: var(--gw-ink);
|
|
10
|
+
font-size: var(--gw-body-size);
|
|
11
|
+
line-height: var(--gw-body-leading);
|
|
12
|
+
overflow-wrap: break-word;
|
|
13
|
+
}
|
|
14
|
+
.gw-prose--sm { font-size: 16px; }
|
|
15
|
+
|
|
16
|
+
/* the flow: each block 20px below the one before it (16px in --sm); more air around headings and large blocks */
|
|
17
|
+
:where(.gw-prose) > * + * { margin-top: 20px; }
|
|
18
|
+
:where(.gw-prose--sm) > * + * { margin-top: 16px; }
|
|
19
|
+
:where(.gw-prose) > * + :where(figure, img, video, pre, table, hr, .gw-table, .gw-window),
|
|
20
|
+
:where(.gw-prose) > :where(figure, img, video, pre, table, hr, .gw-table, .gw-window) + * { margin-top: 32px; }
|
|
21
|
+
:where(.gw-prose) > * + h2 { margin-top: 48px; }
|
|
22
|
+
:where(.gw-prose) > * + h3 { margin-top: 40px; }
|
|
23
|
+
:where(.gw-prose) > * + h4 { margin-top: 32px; }
|
|
24
|
+
:where(.gw-prose--sm) > * + h2 { margin-top: 40px; }
|
|
25
|
+
:where(.gw-prose--sm) > * + h3 { margin-top: 32px; }
|
|
26
|
+
:where(.gw-prose--sm) > * + h4 { margin-top: 24px; }
|
|
27
|
+
:where(.gw-prose) > h1 + * { margin-top: 24px; }
|
|
28
|
+
:where(.gw-prose) > :is(h2, h3, h4) + * { margin-top: 12px; }
|
|
29
|
+
|
|
30
|
+
/* headings: the article's own steps of the type scale, not the page's display sizes (an h2 in a post is not a
|
|
31
|
+
section headline); h1 is the article's title at the section-headline size */
|
|
32
|
+
:where(.gw-prose) > :is(h1, h2, h3, h4) {
|
|
33
|
+
color: var(--gw-ink);
|
|
34
|
+
font-weight: var(--gw-heading-weight);
|
|
35
|
+
letter-spacing: var(--gw-heading-tracking);
|
|
36
|
+
line-height: 1.25;
|
|
37
|
+
}
|
|
38
|
+
:where(.gw-prose) > h1 { font-size: var(--gw-display-h2); font-weight: var(--gw-display-weight); letter-spacing: var(--gw-display-tracking); line-height: var(--gw-heading-leading); }
|
|
39
|
+
:where(.gw-prose) > h2 { font-size: 30px; line-height: 1.2; }
|
|
40
|
+
:where(.gw-prose) > h3 { font-size: 24px; }
|
|
41
|
+
:where(.gw-prose) > h4 { font-size: 20px; }
|
|
42
|
+
:where(.gw-prose--sm) > h2 { font-size: 24px; }
|
|
43
|
+
:where(.gw-prose--sm) > h3 { font-size: 20px; }
|
|
44
|
+
:where(.gw-prose--sm) > h4 { font-size: 18px; }
|
|
45
|
+
|
|
46
|
+
/* lists without a class: plain bullets and numbers, the markers muted */
|
|
47
|
+
:where(.gw-prose :is(ul, ol):not([class])) { padding-left: 24px; }
|
|
48
|
+
:where(.gw-prose ul:not([class])) { list-style: disc; }
|
|
49
|
+
:where(.gw-prose ol:not([class])) { list-style: decimal; }
|
|
50
|
+
:where(.gw-prose :is(ul, ol):not([class]) > li + li),
|
|
51
|
+
:where(.gw-prose :is(ul, ol):not([class]) > li > * + *),
|
|
52
|
+
:where(.gw-prose :is(ul, ol):not([class]) > li > :is(ul, ol)) { margin-top: 8px; }
|
|
53
|
+
:where(.gw-prose :is(ul, ol):not([class]) > li)::marker { color: var(--gw-muted); font-variant-numeric: tabular-nums; }
|
|
54
|
+
|
|
55
|
+
/* a quotation: a rule on its left and muted words, as the dashboard's reader draws it */
|
|
56
|
+
:where(.gw-prose) > blockquote { padding-left: 20px; border-left: 3px solid var(--gw-line-strong); color: var(--gw-muted); }
|
|
57
|
+
:where(.gw-prose) > blockquote > * + * { margin-top: 12px; }
|
|
58
|
+
|
|
59
|
+
:where(.gw-prose) > hr { height: 0; border: 0; border-top: 1px solid var(--gw-line); }
|
|
60
|
+
:where(.gw-prose) :is(sup, sub) { line-height: 0; }
|
|
61
|
+
|
|
62
|
+
/* code: inline, a tint chip that wraps on a phone; a block scrolls inside its own box */
|
|
63
|
+
:where(.gw-prose) :is(pre, code, kbd, samp) { font-family: var(--gw-font-mono); }
|
|
64
|
+
:where(.gw-prose) code {
|
|
65
|
+
padding: 2px 6px;
|
|
66
|
+
border-radius: var(--gw-radius-6);
|
|
67
|
+
background: color-mix(in srgb, var(--gw-ink) 8%, transparent);
|
|
68
|
+
color: var(--gw-ink);
|
|
69
|
+
font-size: 16px;
|
|
70
|
+
overflow-wrap: anywhere;
|
|
71
|
+
-webkit-box-decoration-break: clone;
|
|
72
|
+
box-decoration-break: clone;
|
|
73
|
+
}
|
|
74
|
+
:where(.gw-prose--sm) code { font-size: 14px; }
|
|
75
|
+
:where(.gw-prose) :is(h1, h2, h3, h4) code { font-size: inherit; }
|
|
76
|
+
:where(.gw-prose) figcaption code { font-size: 13px; }
|
|
77
|
+
/* in a table a name stays whole: the table scrolls instead */
|
|
78
|
+
:where(.gw-prose) :is(th, td) code { font-size: 13px; overflow-wrap: normal; white-space: nowrap; }
|
|
79
|
+
:where(.gw-prose) pre {
|
|
80
|
+
overflow-x: auto;
|
|
81
|
+
padding: 16px 20px;
|
|
82
|
+
border: 1px solid var(--gw-line);
|
|
83
|
+
border-radius: var(--gw-radius-card);
|
|
84
|
+
background: var(--gw-bg-soft);
|
|
85
|
+
color: var(--gw-ink);
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
line-height: 1.6;
|
|
88
|
+
tab-size: 2;
|
|
89
|
+
}
|
|
90
|
+
:where(.gw-prose) pre code { padding: 0; border-radius: 0; background: none; font-size: inherit; overflow-wrap: normal; }
|
|
91
|
+
|
|
92
|
+
/* images and captions (an image inside a .gw-window keeps the window's square edges) */
|
|
93
|
+
:where(.gw-prose) > :is(img, video),
|
|
94
|
+
:where(.gw-prose) > :is(p, figure) > :is(img, video) { border-radius: var(--gw-radius-card); }
|
|
95
|
+
:where(.gw-prose) figcaption { margin-top: 12px; color: var(--gw-muted); font-size: 14px; line-height: 1.5; }
|
|
96
|
+
|
|
97
|
+
/* a table straight from markdown scrolls inside its own box, never the page. When you write the markup, the .gw-table
|
|
98
|
+
wrapper (a region with a name and tabindex="0") is the better choice. */
|
|
99
|
+
:where(.gw-prose) > table {
|
|
100
|
+
display: block;
|
|
101
|
+
width: max-content;
|
|
102
|
+
max-width: 100%;
|
|
103
|
+
overflow-x: auto;
|
|
104
|
+
border: 1px solid var(--gw-line);
|
|
105
|
+
border-radius: var(--gw-radius-card);
|
|
106
|
+
background: var(--gw-surface);
|
|
107
|
+
border-collapse: collapse;
|
|
108
|
+
font-size: 14px;
|
|
109
|
+
line-height: 1.5;
|
|
110
|
+
-webkit-overflow-scrolling: touch;
|
|
111
|
+
}
|
|
112
|
+
:where(.gw-prose) > table :is(th, td) { padding: 12px 16px; border-bottom: 1px solid var(--gw-line); text-align: left; vertical-align: top; }
|
|
113
|
+
:where(.gw-prose) > table thead th { background: var(--gw-bg-soft); color: var(--gw-ink); font-size: 13px; font-weight: 600; white-space: nowrap; }
|
|
114
|
+
:where(.gw-prose) > table tbody th { font-weight: 500; }
|
|
115
|
+
:where(.gw-prose) > table td { color: var(--gw-ink-2); font-variant-numeric: tabular-nums; }
|
|
116
|
+
:where(.gw-prose) > table tbody tr:last-child > * { border-bottom: 0; }
|
|
117
|
+
:where(.gw-prose) > table caption { padding: 12px 16px; color: var(--gw-muted); font-size: 13px; text-align: left; }
|
|
118
|
+
/* on a phone a cell keeps room for a few words a line: the table scrolls further instead of squeezing its text */
|
|
119
|
+
@media (max-width: 767px) { :where(.gw-prose) > table td { min-width: 160px; } }
|
package/css/sections.css
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/* sections: hero, logos, stats, features, split, showcase, steps, quote, pricing, CTA. */
|
|
2
|
+
|
|
3
|
+
/* hero: the first screen. __wash is the one place the wash hues may appear. */
|
|
4
|
+
.gw-hero { position: relative; isolation: isolate; padding-block: 48px 64px; }
|
|
5
|
+
.gw-hero__wash {
|
|
6
|
+
position: absolute;
|
|
7
|
+
inset: 0;
|
|
8
|
+
z-index: -1;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
background:
|
|
11
|
+
radial-gradient(640px 460px at 88% -10%, color-mix(in srgb, var(--gw-accent) 16%, transparent), transparent 62%),
|
|
12
|
+
radial-gradient(560px 480px at 6% 108%, color-mix(in srgb, var(--gw-wash-violet) 12%, transparent), transparent 62%),
|
|
13
|
+
radial-gradient(420px 320px at 52% 118%, color-mix(in srgb, var(--gw-wash-mint) 10%, transparent), transparent 62%);
|
|
14
|
+
}
|
|
15
|
+
.gw-hero h1 .gw-dim { display: block; }
|
|
16
|
+
.gw-hero > .gw-wrap > .gw-window { margin-top: 48px; }
|
|
17
|
+
.gw-hero--center { text-align: center; }
|
|
18
|
+
.gw-hero--center > .gw-wrap > * { margin-inline: auto; }
|
|
19
|
+
.gw-hero--center .gw-actions { justify-content: center; }
|
|
20
|
+
.gw-hero--compact { padding-block: 40px 48px; }
|
|
21
|
+
.gw-hero--compact h1 { font-size: var(--gw-display-h2); }
|
|
22
|
+
@media (min-width: 768px) {
|
|
23
|
+
.gw-hero { padding-block: 80px 96px; }
|
|
24
|
+
.gw-hero--compact { padding-block: 64px; }
|
|
25
|
+
.gw-hero .gw-lead { font-size: 20px; }
|
|
26
|
+
.gw-hero > .gw-wrap > .gw-window { margin-top: 64px; }
|
|
27
|
+
}
|
|
28
|
+
@media (max-width: 479px) {
|
|
29
|
+
:is(.gw-hero, .gw-cta) .gw-actions > .gw-btn { flex: 1 1 100%; }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* logos: a proof strip of real logos or wordmarks */
|
|
33
|
+
.gw-logos { padding-block: 40px; border-block: 1px solid var(--gw-line); }
|
|
34
|
+
.gw-logos p { color: var(--gw-muted); font-size: 13px; text-align: center; }
|
|
35
|
+
.gw-logos ul {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-wrap: wrap;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
gap: 16px 40px;
|
|
41
|
+
margin-top: 20px;
|
|
42
|
+
padding: 0;
|
|
43
|
+
list-style: none;
|
|
44
|
+
}
|
|
45
|
+
.gw-logos li { color: var(--gw-muted); font-size: 22px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
|
|
46
|
+
.gw-logos img { width: auto; height: 28px; }
|
|
47
|
+
|
|
48
|
+
/* stats: three or four facts, each with its source */
|
|
49
|
+
.gw-stats { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; margin: 0; padding: 0; list-style: none; }
|
|
50
|
+
.gw-stats__value { font-size: var(--gw-display-h2); font-weight: 600; letter-spacing: -0.03em; line-height: 1.1; font-variant-numeric: tabular-nums; }
|
|
51
|
+
.gw-stats__label { margin-top: 8px; max-width: 28ch; color: var(--gw-muted); font-size: 14px; }
|
|
52
|
+
.gw-stats__source { margin-top: 8px; color: var(--gw-muted); font-size: 12px; }
|
|
53
|
+
@media (min-width: 480px) { .gw-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
54
|
+
@media (min-width: 1080px) {
|
|
55
|
+
.gw-stats { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 0; }
|
|
56
|
+
.gw-stats__item { padding: 4px 24px; border-left: 1px solid var(--gw-line); }
|
|
57
|
+
.gw-stats__item:first-child { padding-left: 0; border-left: 0; }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* features: icon, title, one or two lines (inside .gw-grid--2|3|4) */
|
|
61
|
+
.gw-features { row-gap: 40px; }
|
|
62
|
+
.gw-feature .gw-icon { width: 40px; height: 40px; border: 1px solid var(--gw-line); border-radius: var(--gw-radius-action); background: var(--gw-surface); color: var(--gw-accent); }
|
|
63
|
+
|
|
64
|
+
/* split: text beside a figure; stacks on phones, text first */
|
|
65
|
+
.gw-split { display: grid; grid-template-columns: minmax(0, 1fr); align-items: center; gap: 40px; }
|
|
66
|
+
@media (min-width: 768px) {
|
|
67
|
+
.gw-split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
68
|
+
.gw-split--reverse > :first-child { order: 2; }
|
|
69
|
+
}
|
|
70
|
+
.gw-split h2 { font-size: 30px; }
|
|
71
|
+
@media (min-width: 1080px) { .gw-split { gap: 64px; } }
|
|
72
|
+
|
|
73
|
+
/* showcase: a night band with a large screen and two or three points */
|
|
74
|
+
.gw-showcase .gw-window { max-width: 960px; margin-inline: auto; }
|
|
75
|
+
.gw-showcase .gw-window + * { margin-top: 48px; }
|
|
76
|
+
|
|
77
|
+
/* steps: numbered, how it works */
|
|
78
|
+
.gw-steps {
|
|
79
|
+
display: grid;
|
|
80
|
+
grid-template-columns: minmax(0, 1fr);
|
|
81
|
+
gap: 32px 24px;
|
|
82
|
+
margin: 0;
|
|
83
|
+
padding: 0;
|
|
84
|
+
list-style: none;
|
|
85
|
+
counter-reset: gw-step;
|
|
86
|
+
}
|
|
87
|
+
.gw-steps > li { counter-increment: gw-step; }
|
|
88
|
+
.gw-steps > li::before {
|
|
89
|
+
content: counter(gw-step, decimal-leading-zero);
|
|
90
|
+
display: block;
|
|
91
|
+
margin-bottom: 16px;
|
|
92
|
+
padding-bottom: 12px;
|
|
93
|
+
border-bottom: 1px solid var(--gw-line);
|
|
94
|
+
color: var(--gw-accent-strong);
|
|
95
|
+
font-size: 13px;
|
|
96
|
+
font-weight: 600;
|
|
97
|
+
font-variant-numeric: tabular-nums;
|
|
98
|
+
}
|
|
99
|
+
.gw-steps h3 { font-size: 20px; }
|
|
100
|
+
.gw-steps p { margin-top: 8px; color: var(--gw-muted); font-size: 16px; }
|
|
101
|
+
@media (min-width: 768px) { .gw-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
102
|
+
@media (min-width: 1080px) { .gw-steps { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); } }
|
|
103
|
+
|
|
104
|
+
/* quote: one real testimonial, with name, role and company */
|
|
105
|
+
.gw-quote {
|
|
106
|
+
max-width: 880px;
|
|
107
|
+
margin-inline: auto;
|
|
108
|
+
padding: 40px 24px;
|
|
109
|
+
border: 1px solid var(--gw-line);
|
|
110
|
+
border-radius: var(--gw-radius-panel);
|
|
111
|
+
background: var(--gw-surface);
|
|
112
|
+
text-align: center;
|
|
113
|
+
}
|
|
114
|
+
.gw-quote::before {
|
|
115
|
+
content: "";
|
|
116
|
+
display: block;
|
|
117
|
+
width: 32px;
|
|
118
|
+
height: 24px;
|
|
119
|
+
margin: 0 auto 24px;
|
|
120
|
+
background: var(--gw-accent);
|
|
121
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 24'%3E%3Cpath d='M0 24V14C0 6 4 1 12 0l1 4c-4 1-6 4-6 8h5v12zm19 0V14c0-8 4-13 12-14l1 4c-4 1-6 4-6 8h5v12z'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
122
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 24'%3E%3Cpath d='M0 24V14C0 6 4 1 12 0l1 4c-4 1-6 4-6 8h5v12zm19 0V14c0-8 4-13 12-14l1 4c-4 1-6 4-6 8h5v12z'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
123
|
+
}
|
|
124
|
+
.gw-quote blockquote { font-size: 24px; font-weight: 500; line-height: 1.4; letter-spacing: -0.01em; text-wrap: balance; }
|
|
125
|
+
.gw-quote figcaption { margin-top: 24px; color: var(--gw-muted); font-size: 14px; }
|
|
126
|
+
.gw-quote figcaption b { color: var(--gw-ink); }
|
|
127
|
+
.gw-quote figcaption img { width: 40px; height: 40px; margin: 0 auto 12px; border-radius: var(--gw-radius-chip); }
|
|
128
|
+
@media (min-width: 768px) {
|
|
129
|
+
.gw-quote { padding: 64px; }
|
|
130
|
+
.gw-quote blockquote { font-size: 30px; }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* pricing: plan cards; the featured one has a hairline in the accent, never a fill */
|
|
134
|
+
.gw-pricing { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); align-items: start; gap: 16px; }
|
|
135
|
+
.gw-plan {
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
padding: 24px;
|
|
139
|
+
border: 1px solid var(--gw-line);
|
|
140
|
+
border-radius: var(--gw-radius-panel);
|
|
141
|
+
background: var(--gw-surface);
|
|
142
|
+
box-shadow: var(--gw-shadow);
|
|
143
|
+
}
|
|
144
|
+
.gw-plan--featured { border-color: var(--gw-accent); }
|
|
145
|
+
.gw-plan { position: relative; }
|
|
146
|
+
.gw-plan > .gw-badge { align-self: flex-start; }
|
|
147
|
+
.gw-plan > .gw-badge:first-child { position: absolute; top: -12px; left: 24px; }
|
|
148
|
+
.gw-plan > .gw-badge:first-child + * { margin-top: 0; }
|
|
149
|
+
.gw-plan h3 { font-size: 20px; }
|
|
150
|
+
:where(.gw-plan) p { color: var(--gw-muted); font-size: 14px; }
|
|
151
|
+
.gw-plan__price {
|
|
152
|
+
display: flex;
|
|
153
|
+
flex-wrap: wrap;
|
|
154
|
+
align-items: baseline;
|
|
155
|
+
gap: 6px;
|
|
156
|
+
color: var(--gw-ink);
|
|
157
|
+
font-size: var(--gw-display-h2);
|
|
158
|
+
font-weight: 600;
|
|
159
|
+
letter-spacing: -0.03em;
|
|
160
|
+
line-height: 1.1;
|
|
161
|
+
font-variant-numeric: tabular-nums;
|
|
162
|
+
}
|
|
163
|
+
.gw-plan__price small { color: var(--gw-muted); font-size: 14px; font-weight: 500; letter-spacing: 0; }
|
|
164
|
+
.gw-plan .gw-list--check { font-size: 14px; }
|
|
165
|
+
@media (min-width: 768px) {
|
|
166
|
+
.gw-plan { padding: 32px; }
|
|
167
|
+
.gw-plan > .gw-badge:first-child { left: 32px; }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* CTA: the closing call to action, centred; put it in a night band or a soft section */
|
|
171
|
+
.gw-cta { max-width: 780px; margin-inline: auto; text-align: center; }
|
|
172
|
+
.gw-cta .gw-lead { margin-inline: auto; }
|
|
173
|
+
.gw-cta .gw-actions { justify-content: center; }
|