@gemboss/website-ui 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +67 -25
- package/CHANGELOG.md +60 -0
- package/README.md +21 -12
- package/bin/lib/check.mjs +129 -7
- package/bin/lib/contrast.mjs +67 -0
- package/css/base.css +3 -3
- package/css/components.css +93 -3
- package/css/header.css +37 -5
- package/css/layout.css +1 -1
- package/css/prose.css +120 -0
- package/css/tokens.css +21 -0
- package/demo/brand-profiles.html +199 -0
- package/demo/index.html +83 -9
- package/docs/components.md +136 -13
- package/docs/markup-contract.md +51 -7
- package/docs/philosophy.md +14 -9
- package/docs/theming.md +88 -31
- package/js/website.js +39 -2
- package/package.json +1 -1
- package/skill/SKILL.md +5 -2
- package/system.json +34 -8
- package/templates/header.html +3 -1
- package/templates/page.html +2 -0
- package/templates/sections/hero.html +3 -1
- package/templates/sections/pricing.html +15 -3
- package/templates/sections/prose.html +36 -0
- package/templates/sections/showcase.html +3 -2
- package/templates/sections/split.html +3 -1
- package/website.css +277 -13
- package/website.min.css +1 -1
package/demo/index.html
CHANGED
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
@media (min-width: 480px) { .demo-metrics b { font-size: 18px; } }
|
|
23
23
|
.demo-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
|
|
24
24
|
.demo-ask { margin-left: auto; max-width: 320px; padding: 8px 12px; border-radius: var(--gw-radius-card); background: var(--gw-bg-soft); color: var(--gw-ink); }
|
|
25
|
-
.demo-illus { margin-top: 12px; color: var(--gw-muted); font-size: 12px; }
|
|
26
25
|
.demo-mt { margin-top: 16px; }
|
|
27
26
|
.demo-specimen + .demo-specimen { margin-top: 48px; }
|
|
28
27
|
.demo-specimen > h3 { margin-bottom: 16px; font-size: 20px; }
|
|
@@ -170,8 +169,8 @@
|
|
|
170
169
|
<div class="demo-row"><span><small>Product page</small><b>The Radiance Serum</b></span><span class="gw-badge gw-badge--success">Live</span></div>
|
|
171
170
|
<div class="demo-row"><span><small>Offer</small><b>Build a box, save 25%</b></span><span class="gw-badge">Draft</span></div>
|
|
172
171
|
</div>
|
|
173
|
-
<p class="demo-illus">GemBoss-built demo pages for Vital Glow. Illustrative.</p>
|
|
174
172
|
</div>
|
|
173
|
+
<p class="gw-window__caption">Illustrative data. Vital Glow is a GemBoss demo brand.</p>
|
|
175
174
|
</div>
|
|
176
175
|
</div>
|
|
177
176
|
</section>
|
|
@@ -287,8 +286,8 @@
|
|
|
287
286
|
<p><b>0.004</b>CLS</p>
|
|
288
287
|
<p><b>0.05 s</b>TTFB</p>
|
|
289
288
|
</div>
|
|
290
|
-
<p class="demo-illus">Measured on a live GemBoss store: mobile, simulated 4G, median of 8 Lighthouse runs, 10 Oct 2026.</p>
|
|
291
289
|
</div>
|
|
290
|
+
<p class="gw-window__caption">Measured on a live GemBoss store: mobile, simulated 4G, median of 8 Lighthouse runs, 10 Oct 2026.</p>
|
|
292
291
|
</div>
|
|
293
292
|
</div>
|
|
294
293
|
</section>
|
|
@@ -315,8 +314,8 @@
|
|
|
315
314
|
<div class="demo-row"><span><b>What dermatologists check first</b><small>Solution aware · ingredient readers</small></span><span class="gw-badge">Drafted</span></div>
|
|
316
315
|
<div class="demo-row"><span><b>A gift that looks after her</b><small>Product aware · gift buyers</small></span><span class="gw-badge">Drafted</span></div>
|
|
317
316
|
</div>
|
|
318
|
-
<p class="demo-illus">GemBoss-built demo pages for Vital Glow. Illustrative.</p>
|
|
319
317
|
</div>
|
|
318
|
+
<p class="gw-window__caption">Illustrative data. Vital Glow is a GemBoss demo brand.</p>
|
|
320
319
|
</div>
|
|
321
320
|
</div>
|
|
322
321
|
</section>
|
|
@@ -339,8 +338,8 @@
|
|
|
339
338
|
<li>Checked the render on desktop and phone</li>
|
|
340
339
|
</ul>
|
|
341
340
|
<div class="demo-head demo-mt"><span>The change waits on the canvas until you publish it.</span><span class="gw-badge gw-badge--accent">Draft</span></div>
|
|
342
|
-
<p class="demo-illus">Vital Glow is a GemBoss demo store. Illustrative.</p>
|
|
343
341
|
</div>
|
|
342
|
+
<p class="gw-window__caption">Illustrative data. Vital Glow is a GemBoss demo store.</p>
|
|
344
343
|
</div>
|
|
345
344
|
<div class="gw-features gw-grid--3">
|
|
346
345
|
<div class="gw-feature"><h3>Ask in plain words</h3><p>"Add a trust row under the buy box" is enough.</p></div>
|
|
@@ -383,12 +382,17 @@
|
|
|
383
382
|
<p class="gw-label">Pricing</p>
|
|
384
383
|
<h2 id="pricing-h"><span class="gw-dim">Every angle gets its own funnel.</span> Pay for the traffic you send it.</h2>
|
|
385
384
|
<p class="gw-lead">Build as many funnels as you like on every plan, and try it free for 14 days.</p>
|
|
385
|
+
<div class="gw-segmented" role="radiogroup" aria-label="Billing period" data-gw-segmented="billing">
|
|
386
|
+
<button type="button" role="radio" aria-checked="true" value="monthly">Monthly</button>
|
|
387
|
+
<button type="button" role="radio" aria-checked="false" value="yearly">Yearly –20%</button>
|
|
388
|
+
</div>
|
|
386
389
|
</div>
|
|
387
390
|
<div class="gw-pricing">
|
|
388
391
|
<div class="gw-plan">
|
|
389
392
|
<h3>Starter</h3>
|
|
390
393
|
<p>Find your first winning angle.</p>
|
|
391
|
-
<p class="gw-plan__price">$49 <small>/ month</small></p>
|
|
394
|
+
<p class="gw-plan__price"><span data-gw-show="billing:monthly">$49</span><span data-gw-show="billing:yearly" hidden>$39</span> <small>/ month</small></p>
|
|
395
|
+
<p><span data-gw-show="billing:monthly">Billed monthly through Shopify</span><span data-gw-show="billing:yearly" hidden>Billed $470.40 a year through Shopify</span></p>
|
|
392
396
|
<a class="gw-btn gw-btn--secondary gw-btn--block" href="https://admin.gemboss.ai/signup">Start 14-day free trial</a>
|
|
393
397
|
<ul class="gw-list--check">
|
|
394
398
|
<li>10,000 funnel sessions a month</li>
|
|
@@ -401,7 +405,8 @@
|
|
|
401
405
|
<span class="gw-badge gw-badge--accent">Recommended for $10k–50k</span>
|
|
402
406
|
<h3>Growth</h3>
|
|
403
407
|
<p>Test new angles every week.</p>
|
|
404
|
-
<p class="gw-plan__price">$149 <small>/ month</small></p>
|
|
408
|
+
<p class="gw-plan__price"><span data-gw-show="billing:monthly">$149</span><span data-gw-show="billing:yearly" hidden>$119</span> <small>/ month</small></p>
|
|
409
|
+
<p><span data-gw-show="billing:monthly">Billed monthly through Shopify</span><span data-gw-show="billing:yearly" hidden>Billed $1,430.40 a year through Shopify</span></p>
|
|
405
410
|
<a class="gw-btn gw-btn--block" href="https://admin.gemboss.ai/signup">Start 14-day free trial</a>
|
|
406
411
|
<ul class="gw-list--check">
|
|
407
412
|
<li>50,000 funnel sessions a month</li>
|
|
@@ -413,7 +418,8 @@
|
|
|
413
418
|
<div class="gw-plan">
|
|
414
419
|
<h3>Scale</h3>
|
|
415
420
|
<p>Run many angles at once.</p>
|
|
416
|
-
<p class="gw-plan__price">$399 <small>/ month</small></p>
|
|
421
|
+
<p class="gw-plan__price"><span data-gw-show="billing:monthly">$399</span><span data-gw-show="billing:yearly" hidden>$319</span> <small>/ month</small></p>
|
|
422
|
+
<p><span data-gw-show="billing:monthly">Billed monthly through Shopify</span><span data-gw-show="billing:yearly" hidden>Billed $3,830.40 a year through Shopify</span></p>
|
|
417
423
|
<a class="gw-btn gw-btn--secondary gw-btn--block" href="https://admin.gemboss.ai/signup">Start 14-day free trial</a>
|
|
418
424
|
<ul class="gw-list--check">
|
|
419
425
|
<li>200,000 funnel sessions a month</li>
|
|
@@ -450,7 +456,7 @@
|
|
|
450
456
|
<tr><th scope="col">Plan</th><th scope="col">Starter</th><th scope="col">Growth</th><th scope="col">Scale</th><th scope="col">Enterprise</th></tr>
|
|
451
457
|
</thead>
|
|
452
458
|
<tbody>
|
|
453
|
-
<tr><th scope="row">Price a month</th><td>$49</td><td>$149</td><td>$399</td><td>from $999</td></tr>
|
|
459
|
+
<tr><th scope="row">Price a month</th><td><span data-gw-show="billing:monthly">$49</span><span data-gw-show="billing:yearly" hidden>$39</span></td><td><span data-gw-show="billing:monthly">$149</span><span data-gw-show="billing:yearly" hidden>$119</span></td><td><span data-gw-show="billing:monthly">$399</span><span data-gw-show="billing:yearly" hidden>$319</span></td><td>from $999</td></tr>
|
|
454
460
|
<tr><th scope="row">Funnel sessions a month</th><td>10,000</td><td>50,000</td><td>200,000</td><td>Custom</td></tr>
|
|
455
461
|
<tr><th scope="row">Funnels live at once</th><td>3</td><td>15</td><td>Unlimited</td><td>Unlimited</td></tr>
|
|
456
462
|
<tr><th scope="row">A/B tests at once</th><td>2</td><td>5</td><td>20</td><td>Unlimited</td></tr>
|
|
@@ -480,6 +486,20 @@
|
|
|
480
486
|
<a class="gw-btn gw-btn--sm" href="https://admin.gemboss.ai/signup">Start free</a>
|
|
481
487
|
<a class="gw-btn gw-btn--lg" href="https://admin.gemboss.ai/signup">Start 14-day free trial</a>
|
|
482
488
|
</div>
|
|
489
|
+
<div class="gw-actions demo-mt">
|
|
490
|
+
<button class="gw-btn" type="button" data-demo-busy>Send the request</button>
|
|
491
|
+
<button class="gw-btn gw-btn--secondary" type="button" data-demo-busy>Run the audit</button>
|
|
492
|
+
</div>
|
|
493
|
+
<p class="gw-note demo-mt">Press one: it waits two seconds, keeps its width and ignores a second press.</p>
|
|
494
|
+
</div>
|
|
495
|
+
<div class="demo-specimen">
|
|
496
|
+
<h3>Segmented control</h3>
|
|
497
|
+
<div class="gw-segmented" role="radiogroup" aria-label="How you want to work" data-gw-segmented="work">
|
|
498
|
+
<button type="button" role="radio" aria-checked="true" value="self">Run it yourself</button>
|
|
499
|
+
<button type="button" role="radio" aria-checked="false" value="managed">We run it for you</button>
|
|
500
|
+
</div>
|
|
501
|
+
<p class="demo-mt" data-gw-show="work:self">Self-serve plans from $49 a month. You build, test and promote the funnels.</p>
|
|
502
|
+
<p class="demo-mt" data-gw-show="work:managed" hidden>Managed from $690 a month. A dedicated operator builds and tests the funnels you approve.</p>
|
|
483
503
|
</div>
|
|
484
504
|
<div class="demo-specimen">
|
|
485
505
|
<h3>Links</h3>
|
|
@@ -521,6 +541,51 @@
|
|
|
521
541
|
</div>
|
|
522
542
|
</section>
|
|
523
543
|
|
|
544
|
+
<!-- prose -->
|
|
545
|
+
<section class="gw-section" aria-labelledby="prose-h">
|
|
546
|
+
<div class="gw-wrap gw-wrap--narrow">
|
|
547
|
+
<div class="gw-section__head">
|
|
548
|
+
<p class="gw-label">Prose</p>
|
|
549
|
+
<h2 id="prose-h"><span class="gw-dim">Blog, docs and legal.</span> Plain HTML, easy to read.</h2>
|
|
550
|
+
<p class="gw-lead">A bare article inside .gw-prose: no class on its headings, lists, quote, code or table.</p>
|
|
551
|
+
</div>
|
|
552
|
+
<article class="gw-prose" aria-label="Why the kit looks the way it does">
|
|
553
|
+
<h2>One language for the site and the product</h2>
|
|
554
|
+
<p>A visitor crosses from the website into the product in one click. If the two disagree, a cream site and a white app, a purple button outside and a black one inside, the seam is exactly where trust is decided. So the website uses the product's language: <a href="https://gemboss.ai/">white canvas, ink actions, one accent</a>, hairlines, almost no shadow.</p>
|
|
555
|
+
<h3>Scales instead of eyeballing</h3>
|
|
556
|
+
<p>On gemboss.ai, before the scales, the four most common paddings were 9, 5, 12 and 15 pixels, and 1,291 of 2,076 spacing values belonged to no scale. The scales make "a bit more space" a choice between two real values:</p>
|
|
557
|
+
<ul>
|
|
558
|
+
<li>Spacing: 0 2 4 6 8 12 16 20 24 32 40 48 64 80 96 120 (px)</li>
|
|
559
|
+
<li>Type: 11 12 13 14 16 18 20 22 24 30, plus the two display sizes</li>
|
|
560
|
+
<li>Radii: 8 for actions, 12 for cards, 16 for panels, fully round for chips</li>
|
|
561
|
+
</ul>
|
|
562
|
+
<blockquote><p>A made-up number or a fake testimonial is found out, and then every other claim on the page is doubted.</p></blockquote>
|
|
563
|
+
<h3>Check before you hand it over</h3>
|
|
564
|
+
<p>Run <code>npx gemboss-website check</code> in the site; <code>--fix-list</code> prints the same findings as a to-do list. Then look at the page at 320px and 1366px.</p>
|
|
565
|
+
<figure>
|
|
566
|
+
<pre><code>npx gemboss-website check
|
|
567
|
+
npx gemboss-website check --fix-list</code></pre>
|
|
568
|
+
<figcaption>The check exits 1 on an error, so it can run in the site's CI too.</figcaption>
|
|
569
|
+
</figure>
|
|
570
|
+
<h3>What a brand changes</h3>
|
|
571
|
+
<table>
|
|
572
|
+
<thead><tr><th scope="col">Variable</th><th scope="col">What it is</th><th scope="col">GemBoss</th></tr></thead>
|
|
573
|
+
<tbody>
|
|
574
|
+
<tr><th scope="row"><code>--gw-accent-light</code></th><td>Links, focus ring, active item, label square</td><td><code>#5661f5</code></td></tr>
|
|
575
|
+
<tr><th scope="row"><code>--gw-accent-strong-light</code></th><td>Accent as text, and on its own tint</td><td><code>#3a44de</code></td></tr>
|
|
576
|
+
<tr><th scope="row"><code>--gw-accent-soft-light</code></th><td>The tint: active chip, chosen option</td><td><code>#eef0fe</code></td></tr>
|
|
577
|
+
<tr><th scope="row"><code>--gw-on-accent-light</code></th><td>Text on a solid accent</td><td><code>#ffffff</code></td></tr>
|
|
578
|
+
</tbody>
|
|
579
|
+
</table>
|
|
580
|
+
<ol>
|
|
581
|
+
<li>Set the eight accent variables once, in a <code>:root</code> block after the kit.</li>
|
|
582
|
+
<li>Check the contrast of the accent as text on white and on the soft ground.</li>
|
|
583
|
+
<li>Look at the site in light and dark, at 320px and 1366px.</li>
|
|
584
|
+
</ol>
|
|
585
|
+
</article>
|
|
586
|
+
</div>
|
|
587
|
+
</section>
|
|
588
|
+
|
|
524
589
|
<!-- faq -->
|
|
525
590
|
<section class="gw-section" aria-labelledby="faq-h">
|
|
526
591
|
<div class="gw-wrap gw-wrap--narrow">
|
|
@@ -625,5 +690,14 @@
|
|
|
625
690
|
</footer>
|
|
626
691
|
|
|
627
692
|
<script src="../js/website.js" defer></script>
|
|
693
|
+
<script>
|
|
694
|
+
// demo only: what a site's own code does while a request is on its way
|
|
695
|
+
document.addEventListener('click', function (e) {
|
|
696
|
+
var b = e.target.closest('[data-demo-busy]');
|
|
697
|
+
if (!b || b.getAttribute('aria-busy') === 'true') return;
|
|
698
|
+
b.setAttribute('aria-busy', 'true');
|
|
699
|
+
setTimeout(function () { b.removeAttribute('aria-busy'); }, 2000);
|
|
700
|
+
});
|
|
701
|
+
</script>
|
|
628
702
|
</body>
|
|
629
703
|
</html>
|
package/docs/components.md
CHANGED
|
@@ -8,6 +8,10 @@ Conventions: kit classes start with `gw-`, variants are `--name`, parts are `__n
|
|
|
8
8
|
`is-*`. Never style a `.gw-*` class in your site's CSS: if the kit's version is wrong for you, that is a gap
|
|
9
9
|
(`AGENTS.md` section 9).
|
|
10
10
|
|
|
11
|
+
Radii and the button fill follow the site's brand profiles (`docs/theming.md`): below, "radius 8 / 12 / 16" is the
|
|
12
|
+
default `tight` profile, and `soft` makes them 12 / 20 / 24; "ink fill" is the default `ink` action profile, and
|
|
13
|
+
`data-gw-action="accent"` makes it the accent.
|
|
14
|
+
|
|
11
15
|
Spacing between the children of text blocks is automatic: inside `.gw-section__head`, the hero, a split column,
|
|
12
16
|
`.gw-cta`, `.gw-card`, `.gw-feature` and `.gw-plan`, each child is 16px below the previous one, a `.gw-actions` row
|
|
13
17
|
32px, a `.gw-list--check` 24px. Do not add margins to fix rhythm; reorder or remove content instead.
|
|
@@ -86,7 +90,8 @@ Don't: more than three night bands on a page (the closing CTA does not count), o
|
|
|
86
90
|
|
|
87
91
|
### Buttons `.gw-btn`
|
|
88
92
|
|
|
89
|
-
40px tall, radius 8, 14px/600, sentence case,
|
|
93
|
+
40px tall, the action radius (8, 12 in `soft`), 14px/600, sentence case, the action colour as fill: ink, or the
|
|
94
|
+
brand's accent with `--gw-on-accent` words under `data-gw-action="accent"` (one colour on the whole site). Variants: `--secondary` (hairline, transparent), `--ghost`
|
|
90
95
|
(no frame), `--on-night` (light fill for a dark surface that is not a `.gw-band--night`), `--sm` (36px, with a 44px
|
|
91
96
|
hit area), `--lg` (48px, 16px type), `--block` (full width). On touch screens every button is at least 44px tall and
|
|
92
97
|
its label may wrap. Inside a night band the default button turns light by itself.
|
|
@@ -98,8 +103,30 @@ its label may wrap. Inside a night band the default button turns light by itself
|
|
|
98
103
|
</div>
|
|
99
104
|
```
|
|
100
105
|
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
Pressed (`:active`): the fill one step stronger (the hover fill: the darker ink, or `--gw-accent-strong`), and
|
|
107
|
+
nothing moves; `--secondary` takes the soft tint and
|
|
108
|
+
`--ghost` the hairline tint.
|
|
109
|
+
|
|
110
|
+
**Loading.** While a `<button>` waits on the network (a form sent, an audit started), set `aria-busy="true"` on it and
|
|
111
|
+
remove it when the answer comes. The label stays in the markup, so the button keeps its width and its accessible name,
|
|
112
|
+
but it is not painted: a 16px ring in the button's own ink turns in its place, and under `prefers-reduced-motion` it is
|
|
113
|
+
a still ellipsis. `website.js` ignores presses on a busy button, by mouse or keyboard, so nothing is sent twice. When
|
|
114
|
+
the wait ends, say what happened in words (a `.gw-note` or a `role="status"` line next to it).
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<button class="gw-btn" type="submit" aria-busy="true">Send the request</button>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
button.setAttribute('aria-busy', 'true'); // the request leaves
|
|
122
|
+
button.removeAttribute('aria-busy'); // the answer came
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Don't: a fill of your own (the accent comes only from the action profile, set on `<html>`), a gradient or a wash; a
|
|
126
|
+
raised or inset shadow; pill-shaped buttons; uppercase; two filled buttons side by side (one
|
|
127
|
+
`.gw-btn` per view, the second is `--secondary` or a link); a `<div>` with a click handler instead of `<a>`/`<button>`;
|
|
128
|
+
a loading class, your own spinner or `disabled` on a waiting button (`check` reports `busy-button`: `disabled` throws
|
|
129
|
+
the keyboard focus to the top of the page); a "Loading…" label in place of the real one.
|
|
103
130
|
|
|
104
131
|
### Chips `.gw-chip`
|
|
105
132
|
|
|
@@ -112,6 +139,37 @@ hairline on accent-soft). As a `<button>`, `<a>` or `<label>` it is 44px tall on
|
|
|
112
139
|
|
|
113
140
|
Don't: use a chip as the page's action; square it; more than about six in a row.
|
|
114
141
|
|
|
142
|
+
### Segmented control `.gw-segmented`
|
|
143
|
+
|
|
144
|
+
One choice out of two to four, shown as one group: Monthly / Yearly on a pricing page, Run it yourself / We run it for
|
|
145
|
+
you. It is a radio group: one Tab stop, the arrow keys (and Home, End) move and choose, a click or Space chooses. The
|
|
146
|
+
look is the dashboard's (`@gemboss/ui` `.ui-seg`): one hairline group, the action radius, a hairline between options, the chosen
|
|
147
|
+
option on the accent tint, so it follows a brand's accent. 40px tall; on touch screens every option is at least 44px
|
|
148
|
+
and its label may wrap. `--block` stretches it to the row and shares the width equally.
|
|
149
|
+
|
|
150
|
+
What an option shows: any element with `data-gw-show="group:value"` (the group's `data-gw-segmented` name, the option's
|
|
151
|
+
`value`) is hidden unless that option is chosen. Put every version in the markup and `hidden` on all but the chosen
|
|
152
|
+
one's: without the script the page reads with the default choice, with it `website.js` swaps them. An element may
|
|
153
|
+
belong to several options (`data-gw-show="billing:monthly billing:quarterly"`). A choice also fires `gw:segmented` on
|
|
154
|
+
the group (it bubbles; `detail` is `{ name, value }`) for the page's own script, for example to move a "Recommended"
|
|
155
|
+
badge.
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<div class="gw-segmented" role="radiogroup" aria-label="Billing period" data-gw-segmented="billing">
|
|
159
|
+
<button type="button" role="radio" aria-checked="true" value="monthly">Monthly</button>
|
|
160
|
+
<button type="button" role="radio" aria-checked="false" value="yearly">Yearly –20%</button>
|
|
161
|
+
</div>
|
|
162
|
+
<p class="gw-plan__price"><span data-gw-show="billing:monthly">$49</span><span data-gw-show="billing:yearly" hidden>$39</span> <small>/ month</small></p>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Labels: one to three words, as short in every language as in English (gemboss.ai: "Tháng / Năm –20%", "按月 / 按年
|
|
166
|
+
–20%"). The chosen label does not change weight, so nothing moves. A discount in a label is the one billing gives.
|
|
167
|
+
|
|
168
|
+
Don't: links dressed as a segmented control (to go to another page, use links); panels of one page that the reader
|
|
169
|
+
should be able to see side by side; more than four options (use chips); a choice that changes nothing visible; two
|
|
170
|
+
groups with the same name on one page; the old `role="group"` with `aria-pressed` buttons (`check` reports
|
|
171
|
+
`segmented-markup`).
|
|
172
|
+
|
|
115
173
|
### Badges `.gw-badge`
|
|
116
174
|
|
|
117
175
|
Small status, a pill, 12px. Variants: `--accent` (a test, the recommended plan), `--success` and `--warning` (state:
|
|
@@ -125,7 +183,7 @@ Don't: make a badge clickable; write a sentence in it; use success or warning fo
|
|
|
125
183
|
|
|
126
184
|
### Cards `.gw-card`
|
|
127
185
|
|
|
128
|
-
A white box with a 1px hairline, radius 12, the resting shadow `--gw-shadow` (as the dashboard's cards), 24px padding
|
|
186
|
+
A white box with a 1px hairline, the card radius (12, 20 in `soft`), the resting shadow `--gw-shadow` (as the dashboard's cards), 24px padding
|
|
129
187
|
(32px from 768px). It sits: no hover lift. `--soft` is a tint and has no shadow.
|
|
130
188
|
Variants: `--soft` (on `--gw-bg-soft`), `--link` (the whole card is one `<a>`; the border darkens on hover).
|
|
131
189
|
|
|
@@ -137,22 +195,32 @@ Variants: `--soft` (on `--gw-bg-soft`), `--link` (the whole card is one `<a>`; t
|
|
|
137
195
|
</a>
|
|
138
196
|
```
|
|
139
197
|
|
|
140
|
-
Don't: put links or buttons inside a `--link` card (one card, one destination); a bigger shadow or a hover lift;
|
|
141
|
-
|
|
198
|
+
Don't: put links or buttons inside a `--link` card (one card, one destination); a bigger shadow or a hover lift; a
|
|
199
|
+
radius of your own (cards take the card radius, plans and the quote the panel radius, both from the profile).
|
|
142
200
|
|
|
143
201
|
### Window `.gw-window`
|
|
144
202
|
|
|
145
|
-
A framed screen: `__bar` (three dots and where the screen lives)
|
|
146
|
-
`<img>`)
|
|
203
|
+
A framed screen: `__bar` (three dots and where the screen lives), `__body` (16px padding, none around a single
|
|
204
|
+
`<img>`) and `__caption`. Use it around real product screenshots, or around a drawn mock-up built in the site's CSS with
|
|
205
|
+
the tokens.
|
|
206
|
+
|
|
207
|
+
`__caption` says what the numbers in the window are: 12px, muted, at the end of the window, the last child after
|
|
208
|
+
`__body` (a `<figcaption>` when the window is a `<figure>`). Under a drawn mock-up whose numbers are made up it says
|
|
209
|
+
**"Illustrative data."**, in exactly these words: vi "Dữ liệu minh hoạ.", zh "示意数据。". Add a second sentence only when
|
|
210
|
+
the mock-up shows a demo brand ("Vital Glow is a GemBoss demo brand."). Under real numbers it names their source
|
|
211
|
+
("Measured on a live GemBoss store, 10 Oct 2026."). `check` warns about a drawn window with numbers and no caption
|
|
212
|
+
(`illustrative-caption`).
|
|
147
213
|
|
|
148
214
|
```html
|
|
149
215
|
<div class="gw-window">
|
|
150
216
|
<div class="gw-window__bar">Funnels / Radiance Serum</div>
|
|
151
217
|
<div class="gw-window__body"><img src="/img/funnels.webp" alt="The funnel list with four steps" width="1200" height="750"></div>
|
|
218
|
+
<p class="gw-window__caption">Illustrative data. Vital Glow is a GemBoss demo brand.</p>
|
|
152
219
|
</div>
|
|
153
220
|
```
|
|
154
221
|
|
|
155
|
-
Don't: put interactive controls inside a mock-up; show made-up numbers without
|
|
222
|
+
Don't: put interactive controls inside a mock-up; show made-up numbers without the caption; write the caption in
|
|
223
|
+
other words ("Sample", "Demo numbers") or leave it in English on a translated page.
|
|
156
224
|
|
|
157
225
|
### Icon `.gw-icon`
|
|
158
226
|
|
|
@@ -177,7 +245,7 @@ Don't: more than five or six items; full paragraphs as items.
|
|
|
177
245
|
|
|
178
246
|
### Table `.gw-table`
|
|
179
247
|
|
|
180
|
-
A wrapper around a plain `<table>`: hairline, radius
|
|
248
|
+
A wrapper around a plain `<table>`: hairline, the card radius, and it scrolls inside its own box when the table is wider
|
|
181
249
|
than the screen. `--compare`: centred values, a 640px minimum width and a sticky first column, for plan comparisons.
|
|
182
250
|
Give the wrapper `role="region"`, an accessible name and `tabindex="0"` so keyboard users can scroll it.
|
|
183
251
|
|
|
@@ -204,7 +272,7 @@ Native `<details class="gw-faq__item">` with a `<summary>`, no script. The + tur
|
|
|
204
272
|
|
|
205
273
|
Don't: hide content a reader needs to decide (prices, terms) only inside a closed answer; more than eight questions.
|
|
206
274
|
|
|
207
|
-
### Not in
|
|
275
|
+
### Not in the kit yet
|
|
208
276
|
|
|
209
277
|
`.gw-tabs` does not exist yet. If a page needs tabs, build a stopgap (`kitgap-tabs`) and report the gap.
|
|
210
278
|
|
|
@@ -214,10 +282,11 @@ Don't: hide content a reader needs to decide (prices, terms) only inside a close
|
|
|
214
282
|
|---|---|
|
|
215
283
|
| `.gw-announce` | optional one-sentence bar above the header, with one link |
|
|
216
284
|
| `.gw-header` (`data-gw-header`) | the sticky, flat 64px bar with one hairline; `.is-scrolled` darkens the hairline |
|
|
285
|
+
| `.gw-header--float` | with `.gw-header`, a brand's header profile: from 1080px the same bar as an inset card (panel radius, the surface at 85% over a blur, one hairline, the raised shadow, 16px from the top); the flat bar below 1080px; solid under `prefers-reduced-transparency` |
|
|
217
286
|
| `.gw-header__bar` | the row inside (`.gw-wrap gw-header__bar`) |
|
|
218
287
|
| `.gw-brand`, `__mark`, `__name` | logo (26px) and name, linking home |
|
|
219
288
|
| `.gw-nav`, `__list`, `__item`, `__trigger`, `__link` | the desktop nav (from 1080px); `__trigger` opens a mega panel, `__link` is a plain link; `aria-current="page"` underlines it in the accent |
|
|
220
|
-
| `.gw-mega`, `__grid`, `__col`, `__heading`, `__link`, `__icon`, `__feature` | a floating card centred under the bar (radius 20, raised shadow, as on gemboss.ai): columns of links with an icon and one line each, and at most one feature card |
|
|
289
|
+
| `.gw-mega`, `__grid`, `__col`, `__heading`, `__link`, `__icon`, `__feature` | a floating card centred under the bar (the popover radius: 20, 24 in `soft`; raised shadow, as on gemboss.ai): columns of links with an icon and one line each, and at most one feature card |
|
|
221
290
|
| `.gw-header__actions` | theme toggle, Sign in, Book a demo, Start free, menu button |
|
|
222
291
|
| `.gw-header__signin` | with `.gw-nav__link`: hidden below 1080px (it moves into the mobile menu) |
|
|
223
292
|
| `.gw-theme-toggle` | icon button (`data-gw-theme-toggle`), 40px, 44px on touch |
|
|
@@ -231,7 +300,8 @@ Don't: hide content a reader needs to decide (prices, terms) only inside a close
|
|
|
231
300
|
Header buttons: the secondary one shows from 768px, the primary one from 480px; below that they live in the mobile
|
|
232
301
|
menu. Full markup: `templates/header.html`.
|
|
233
302
|
|
|
234
|
-
Don't: a floating, rounded or blurred header
|
|
303
|
+
Don't: a floating, rounded or blurred header of your own (the one floating header is `.gw-header--float`, chosen
|
|
304
|
+
for the whole site); more than five top-level items; a second filled button in the bar; a
|
|
235
305
|
hero pulled up under the header.
|
|
236
306
|
|
|
237
307
|
## Footer
|
|
@@ -282,6 +352,48 @@ One snippet per section, with its limits in a comment, is in `templates/sections
|
|
|
282
352
|
Don't: a number without a source; logos or quotes you do not have permission for; a filled button on every plan
|
|
283
353
|
(only the featured one); a hero without a real first line of content above the fold on a 390px phone.
|
|
284
354
|
|
|
355
|
+
## Prose
|
|
356
|
+
|
|
357
|
+
| class | for |
|
|
358
|
+
|---|---|
|
|
359
|
+
| `.gw-prose` | a page that is read rather than scanned (a blog post, a docs page, terms, privacy): the article's own HTML inside it, 18px body, 68ch measure |
|
|
360
|
+
| `.gw-prose--sm` | the same at a 16px body, for docs and legal pages |
|
|
361
|
+
|
|
362
|
+
The HTML a CMS or a markdown renderer writes needs no classes. Inside `.gw-prose`:
|
|
363
|
+
|
|
364
|
+
| element | look |
|
|
365
|
+
|---|---|
|
|
366
|
+
| `h1` | the article title, at the section-headline size (`--gw-display-h2`) |
|
|
367
|
+
| `h2`, `h3`, `h4` | 30, 24, 20px (24, 20, 18px in `--sm`), weight 650; 48, 40, 32px of air above, 12px below |
|
|
368
|
+
| `p`, `ul`, `ol` | 20px between blocks (16px in `--sm`); bullets and numbers with muted markers, 8px between items |
|
|
369
|
+
| `blockquote` | a 3px rule on its left, muted words (the dashboard's reader quote) |
|
|
370
|
+
| `code` | a tint chip in `--gw-font-mono` (16px, 14px in `--sm`) that wraps on a phone; in a table it stays whole |
|
|
371
|
+
| `pre` | a soft box, 14px mono, that scrolls sideways inside itself |
|
|
372
|
+
| `table` | as a direct child: the `.gw-table` look, and it scrolls inside its own box when it is wider than the column |
|
|
373
|
+
| `img`, `figure`, `figcaption` | images take the card radius; a caption 14px muted, 12px under its figure |
|
|
374
|
+
| `hr`, `a` | a hairline with 32px of air; links in the accent, underlined |
|
|
375
|
+
|
|
376
|
+
Kit components inside the prose keep their own look (`.gw-table`, `.gw-window`, `.gw-list--check`, `.gw-quote`,
|
|
377
|
+
`.gw-btn`). Prefer the `.gw-table` wrapper (`role="region"`, a name, `tabindex="0"`) when you write the markup: a
|
|
378
|
+
keyboard can scroll it.
|
|
379
|
+
|
|
380
|
+
```html
|
|
381
|
+
<section class="gw-section">
|
|
382
|
+
<div class="gw-wrap gw-wrap--narrow">
|
|
383
|
+
<article class="gw-prose">
|
|
384
|
+
<h1>Why the kit looks the way it does</h1>
|
|
385
|
+
<p>Each rule came from measuring real pages, not from taste alone.</p>
|
|
386
|
+
<h2>One language for the site and the product</h2>
|
|
387
|
+
<p>A visitor crosses from the website into the product in one click. …</p>
|
|
388
|
+
<ul><li>…</li></ul>
|
|
389
|
+
</article>
|
|
390
|
+
</div>
|
|
391
|
+
</section>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Don't: marketing sections inside the prose (end the article, then the section); headings chosen for their size (keep
|
|
395
|
+
them in order); a page without `.gw-prose` that styles its articles in site CSS (that was the stopgap of gap #46).
|
|
396
|
+
|
|
285
397
|
## Motion
|
|
286
398
|
|
|
287
399
|
| class | for |
|
|
@@ -291,6 +403,17 @@ Don't: a number without a source; logos or quotes you do not have permission for
|
|
|
291
403
|
Put it on a block (a grid, a list, a window), not on each card in a grid. Don't use it on the hero or anything in
|
|
292
404
|
the first screen, and don't animate anything but `transform` and `opacity`.
|
|
293
405
|
|
|
406
|
+
## Additions to the markup contract in 0.3.0
|
|
407
|
+
|
|
408
|
+
The brand profiles: `data-gw-action="ink|accent"` and `data-gw-radius="tight|soft"` on `<html>`, and
|
|
409
|
+
`.gw-header--float` on the header (`docs/theming.md`). Tokens: `--gw-radius-popover` (the mega menu), `--gw-radius-24`,
|
|
410
|
+
`--gw-header-gap`, `--gw-header-surface`, `--gw-header-blur`. No markup of 0.2.0 changes.
|
|
411
|
+
|
|
412
|
+
## Additions to the markup contract in 0.2.0
|
|
413
|
+
|
|
414
|
+
The button states (`:active`, `[aria-busy="true"]`), `.gw-segmented` (+ `--block`) with its `data-gw-segmented` /
|
|
415
|
+
`data-gw-show` hooks, `.gw-window__caption` and `.gw-prose` (+ `--sm`). Two tokens: `--gw-font-mono` and `--gw-spin-ms`.
|
|
416
|
+
|
|
294
417
|
## Additions to the markup contract in 0.1.0
|
|
295
418
|
|
|
296
419
|
The contract names the classes the script relies on; these CSS-only helpers were added with it: `.gw-page`
|
package/docs/markup-contract.md
CHANGED
|
@@ -12,7 +12,9 @@ BEM-ish: `.gw-block`, `.gw-block__part`, `.gw-block--variant`.
|
|
|
12
12
|
## Page
|
|
13
13
|
|
|
14
14
|
```html
|
|
15
|
-
<html lang="en" data-theme?="light|dark"
|
|
15
|
+
<html lang="en" data-theme?="light|dark" data-gw-action?="accent" data-gw-radius?="soft">
|
|
16
|
+
<!-- data-theme absent = follow the system; the toggle sets it. data-gw-action, data-gw-radius: brand profiles (0.3.0),
|
|
17
|
+
absent = ink, tight -->
|
|
16
18
|
<body class="gw-page">
|
|
17
19
|
<a class="gw-skip" href="#main">Skip to content</a>
|
|
18
20
|
<div class="gw-announce" role="region" aria-label="Announcement">…<a href="…">…</a></div> <!-- optional -->
|
|
@@ -25,7 +27,7 @@ BEM-ish: `.gw-block`, `.gw-block__part`, `.gw-block--variant`.
|
|
|
25
27
|
## Header
|
|
26
28
|
|
|
27
29
|
```html
|
|
28
|
-
<header class="gw-header" data-gw-header>
|
|
30
|
+
<header class="gw-header gw-header--float?" data-gw-header> <!-- --float: a brand's header profile (0.3.0) -->
|
|
29
31
|
<div class="gw-wrap gw-header__bar">
|
|
30
32
|
<a class="gw-brand" href="/"><img class="gw-brand__mark" src="…" alt="" width="26" height="26"><span class="gw-brand__name">GemBoss</span></a>
|
|
31
33
|
<nav class="gw-nav" aria-label="Main">
|
|
@@ -73,27 +75,69 @@ Script behaviour:
|
|
|
73
75
|
2.5s, or if IntersectionObserver is missing, all get `.is-in`. Under `prefers-reduced-motion` the CSS shows them
|
|
74
76
|
without motion.
|
|
75
77
|
- **Header**: `.is-scrolled` on `[data-gw-header]` once the page scrolled more than 8px (the CSS may use it for the
|
|
76
|
-
hairline only; the bar does not change height or colour).
|
|
78
|
+
hairline only; the bar does not change height or colour). The floating header needs nothing more from the script:
|
|
79
|
+
it is the same element with one more class.
|
|
77
80
|
- **Current page**: the script marks `aria-current="page"` on `.gw-nav__link` / `.gw-mega__link` whose `href`
|
|
78
81
|
pathname equals `location.pathname` (when the markup did not already).
|
|
79
82
|
|
|
83
|
+
## Brand profiles (0.3.0)
|
|
84
|
+
|
|
85
|
+
- `data-gw-action` and `data-gw-radius` sit on `<html>` only, with a name from `system.json` `profiles` (`ink` or
|
|
86
|
+
`accent`, `tight` or `soft`); absent means the first. The CSS reads them (`css/tokens.css`), the script does not.
|
|
87
|
+
- `.gw-header--float` sits on the `<header class="gw-header">` itself, next to `gw-header`.
|
|
88
|
+
- `check` reports any other name or place (`profile-unknown`, `header-float-markup`) and, with `accent`, words on the
|
|
89
|
+
button below 4.5:1 (`action-contrast`).
|
|
90
|
+
|
|
91
|
+
## Segmented control (0.2.0)
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<div class="gw-segmented" role="radiogroup" aria-label="Billing period" data-gw-segmented="billing">
|
|
95
|
+
<button type="button" role="radio" aria-checked="true" value="monthly">Monthly</button>
|
|
96
|
+
<button type="button" role="radio" aria-checked="false" value="yearly">Yearly –20%</button>
|
|
97
|
+
</div>
|
|
98
|
+
…
|
|
99
|
+
<span data-gw-show="billing:monthly">$49</span><span data-gw-show="billing:yearly" hidden>$39</span>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- The group: `.gw-segmented` (+ `--block`), `role="radiogroup"`, a name (`aria-label` or `aria-labelledby`) and
|
|
103
|
+
`data-gw-segmented="<name>"`, unique on the page. Two to four `<button type="button" role="radio">` children, each
|
|
104
|
+
with a `value` and `aria-checked`, exactly one `"true"`: the choice the page shows without the script.
|
|
105
|
+
- Content: any element with `data-gw-show="<name>:<value>"` (several tokens, space-separated, for several options) is
|
|
106
|
+
shown only while that option is chosen. The markup sets `hidden` on every version but the default's.
|
|
107
|
+
- Script behaviour: on load the checked option (or the first) is chosen again, which corrects `hidden` on the content
|
|
108
|
+
and sets the roving `tabindex` (`0` on the chosen option, `-1` on the others: one Tab stop). A click chooses;
|
|
109
|
+
ArrowRight / ArrowDown and ArrowLeft / ArrowUp move to the next and previous option, wrapping, Home and End to the
|
|
110
|
+
first and last, and the moved-to option is chosen and focused (the radio-group pattern). Each choice made by the
|
|
111
|
+
reader fires `gw:segmented` on the group (`bubbles: true`, `detail: { name, value }`); loading does not.
|
|
112
|
+
|
|
113
|
+
## Busy button (0.2.0)
|
|
114
|
+
|
|
115
|
+
- Markup: `aria-busy="true"` on a `<button class="gw-btn">` while it waits; the page's own script sets and removes it.
|
|
116
|
+
No `disabled` at the same time, no loading class, no spinner element: the CSS draws the ring (`::before`; `--sm`
|
|
117
|
+
keeps `::after` for its hit area).
|
|
118
|
+
- Script behaviour: one click listener on the document, in the capture phase, cancels a click on a
|
|
119
|
+
`.gw-btn[aria-busy="true"]` (or inside one) before the page's handlers see it: `preventDefault` and
|
|
120
|
+
`stopPropagation`. A form is not submitted twice, by mouse, Enter or Space, and the button keeps the focus.
|
|
121
|
+
|
|
80
122
|
## Components (CSS only)
|
|
81
123
|
|
|
82
124
|
| class | what |
|
|
83
125
|
|---|---|
|
|
84
|
-
| `.gw-btn` (+ `--secondary`, `--ghost`, `--on-night`, `--sm`, `--lg`, `--block`) | actions; rectangle
|
|
126
|
+
| `.gw-btn` (+ `--secondary`, `--ghost`, `--on-night`, `--sm`, `--lg`, `--block`) | actions; a rectangle with the action radius, the action colour as fill (ink, or the accent under `data-gw-action="accent"`); `:active` pressed, `[aria-busy="true"]` loading (script above) |
|
|
85
127
|
| `.gw-link` (+ `--arrow`) | inline text link in the accent; `--arrow` adds → that moves 2px on hover |
|
|
86
128
|
| `.gw-label` | the label above a heading: 13px muted, 8px accent square before it |
|
|
87
129
|
| `.gw-dim` | the muted first sentence inside a headline |
|
|
88
130
|
| `.gw-chip` (+ `.is-active`) | selectable token, pill |
|
|
131
|
+
| `.gw-segmented` (+ `--block`) | one choice out of two to four (script above) |
|
|
89
132
|
| `.gw-badge` (+ `--accent`, `--success`, `--warning`) | small status, pill |
|
|
90
|
-
| `.gw-card` (+ `--soft`, `--link`) | white box, 1px hairline, radius
|
|
91
|
-
| `.gw-window` (+ `__bar`, `__body`) | a framed screenshot/mock-up, like a browser or app window |
|
|
133
|
+
| `.gw-card` (+ `--soft`, `--link`) | white box, 1px hairline, the card radius; `--link` makes the whole card an `<a>` |
|
|
134
|
+
| `.gw-window` (+ `__bar`, `__body`, `__caption`) | a framed screenshot/mock-up, like a browser or app window; `__caption` (last child) says what its numbers are: "Illustrative data." or their source |
|
|
92
135
|
| `.gw-icon` | 20px inline stroke SVG wrapper |
|
|
93
136
|
| `.gw-list--check` | list with check marks |
|
|
94
137
|
| `.gw-table` (+ `--compare`) | data / comparison table; scrolls inside its box on phones |
|
|
95
138
|
| `.gw-faq` (`<details class="gw-faq__item"><summary>`) | FAQ accordion with no script |
|
|
96
|
-
| `.gw-
|
|
139
|
+
| `.gw-prose` (+ `--sm`) | long-form reading: an article's own HTML, no classes inside |
|
|
140
|
+
| `.gw-tabs` (`role="tablist"`) | NOT in the kit yet (a reported gap would add it) |
|
|
97
141
|
|
|
98
142
|
## Sections
|
|
99
143
|
|
package/docs/philosophy.md
CHANGED
|
@@ -7,26 +7,31 @@ spirit. Each rule came from measuring real pages, not from taste alone.
|
|
|
7
7
|
|
|
8
8
|
A visitor crosses from the website into the product in one click. If the two disagree (a cream site and a white app,
|
|
9
9
|
a purple button outside and a black one inside), the seam is exactly where trust is decided. So the website uses the
|
|
10
|
-
product's language: white canvas,
|
|
10
|
+
product's language: white canvas, the product's action colour, one accent, hairlines, almost no shadow.
|
|
11
11
|
|
|
12
|
-
## The thing you click is
|
|
12
|
+
## The thing you click is one colour: the product's
|
|
13
13
|
|
|
14
|
-
A page has one thing it wants you to do
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
A page has one thing it wants you to do, and the button that does it looks the same on every page. For GemBoss that
|
|
15
|
+
is near-black ink, as in its dashboard: the strongest mark on white, readable in every light. Since 0.3.0 a brand
|
|
16
|
+
whose product clicks in its accent (GemPages' product uses blue primary buttons) may do the same on its site, with
|
|
17
|
+
the `accent` action profile: the site and the product still speak one language. It is a mode, not a colour picked
|
|
18
|
+
per button; its words must reach 4.5:1 on it, and it never gains a shadow or a gradient. Everywhere else the accent
|
|
19
|
+
marks where you are and what is interactive in text: links, focus, the active item, the small square before a
|
|
20
|
+
label. It never colours the words of a heading or a whole section band: that makes a page louder, not clearer.
|
|
18
21
|
|
|
19
22
|
## Shapes carry meaning
|
|
20
23
|
|
|
21
24
|
Rectangles act, pills choose. When every button is a rectangle and every chip is a pill, people stop reading the
|
|
22
|
-
shape and read the words. A
|
|
23
|
-
the kind of drift that makes a page feel
|
|
25
|
+
shape and read the words. A site has one set of corners, a named profile (`tight` for GemBoss, `soft` for GemPages,
|
|
26
|
+
as in each product), so two cards side by side never differ by 2px, which is the kind of drift that makes a page feel
|
|
27
|
+
assembled rather than designed. Profiles, not free values: a brand can look like itself without inventing a radius.
|
|
24
28
|
|
|
25
29
|
## Separation by line and space, light only at rest
|
|
26
30
|
|
|
27
31
|
A shadow says "this floats above". Cards on a page do not float; they sit on it. A 1px hairline and the dashboard's
|
|
28
32
|
resting shadow (two faint pixels) separate a card and keep the page calm; nothing lifts on hover. Larger light is
|
|
29
|
-
spent where it means something: a popover such as the mega menu,
|
|
33
|
+
spent where it means something: a popover such as the mega menu, the floating header a brand may choose (it does
|
|
34
|
+
float), an illustration that lights itself.
|
|
30
35
|
|
|
31
36
|
## Scales instead of eyeballing
|
|
32
37
|
|