@gemboss/website-ui 0.10.0 → 0.12.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/CHANGELOG.md +99 -0
- package/README.md +2 -2
- package/bin/lib/check.mjs +7 -2
- package/css/base.css +25 -19
- package/css/components.css +22 -9
- package/css/effects.css +1 -1
- package/css/forms.css +1 -1
- package/css/header.css +374 -120
- package/css/layout.css +7 -3
- package/css/sections.css +1 -1
- package/css/tokens.css +33 -3
- package/demo/article.html +58 -70
- package/demo/blog.html +58 -70
- package/demo/brand-profiles.html +57 -27
- package/demo/footer.html +58 -70
- package/demo/forms.html +58 -70
- package/demo/header.html +59 -109
- package/demo/index.html +58 -70
- package/demo/spotlight.html +58 -71
- package/demo/theme-example.html +1 -1
- package/docs/components.md +37 -26
- package/docs/markup-contract.md +54 -24
- package/docs/theming.md +1 -1
- package/js/website.js +315 -48
- package/js/website.mjs +350 -51
- package/package.json +1 -1
- package/system.json +47 -8
- package/templates/header.html +49 -25
- package/templates/page.html +55 -21
- package/website.css +465 -158
- package/website.min.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,105 @@ Every release lists what changed for a site that uses the kit. A release that ad
|
|
|
4
4
|
says so with `Closes gap #N` (the GitHub issue number), so `npx gemboss-website upgrade` can tell that site which
|
|
5
5
|
stopgap (`kitgap-*`) it can now delete.
|
|
6
6
|
|
|
7
|
+
## 0.12.0 (2026-10-26)
|
|
8
|
+
|
|
9
|
+
The grammar of every page, 1:1 with gemboss.ai: the announcement bar, the skip link, the button, the type (headings,
|
|
10
|
+
lead, label, the dim first sentence), a section, its head, the wrap, and the scroll reveal. After the footer (0.10.0)
|
|
11
|
+
and the header (0.11.0), this is the first step of the pages' own bodies onto the kit (Chris, 26/10/2026: every value in
|
|
12
|
+
the kit, so that GemPages, Gemians and GemX inherit them). gemboss.ai's 83 pages now draw these parts with the kit's
|
|
13
|
+
classes, and were measured against the pages before, in Chromium: the computed style of every one of these parts (2,300
|
|
14
|
+
of them) at 320, 390, 768, 1080, 1366 and 1920px, light and dark, and every page pixel by pixel at 390 and 1366px; the
|
|
15
|
+
reveal's delays and counts, a hovered button, the focused skip link.
|
|
16
|
+
|
|
17
|
+
A minor version: a site on 0.11.0 sees these values change (below), none of the markup.
|
|
18
|
+
|
|
19
|
+
- The announcement bar (`.gw-announce`): gemboss.ai's, on its own ground in both themes, from the new tokens
|
|
20
|
+
`--gw-announce-*` (`system.json` `color.announce`: ground, words, hairline, the pill, the link and its underline). A
|
|
21
|
+
small pill may lead the sentence (`.gw-announce__tag`, new); the link's underline is a hairline that brightens on
|
|
22
|
+
hover. 12px words in a slimmer bar up to 520px.
|
|
23
|
+
- The skip link (`.gw-skip`): an accent tab out of the top left corner (was an ink button 8px in).
|
|
24
|
+
- The button (`.gw-btn`): on hover the filled one rises 1px onto the rest shadow (was a darker fill); a framed or
|
|
25
|
+
frameless one does not move. Its face is the new `--gw-font-action` (`type.button.family`, the brand face alone, as
|
|
26
|
+
gemboss.ai names it: a glyph Inter's web subset lacks, the arrow, is then the system's own, the width gemboss.ai's
|
|
27
|
+
buttons have). Its line height is its surroundings'. A label wider than needed stays at the start (centred only in
|
|
28
|
+
`--block`, a phone's row of actions in a hero or CTA, an inline form). An arrow after the label is
|
|
29
|
+
`.gw-btn__arrow` (new): 3px further on hover. Up to 768px every button is at least 44px tall, by the width only (it was
|
|
30
|
+
also by a coarse pointer); a label wraps only up to 480px and only in `<main>`, at 1.35 lines (was up to 768px,
|
|
31
|
+
balanced).
|
|
32
|
+
- Type: h1 at line height 1.1 and h2 at 1.06 (new tokens `--gw-display-h1-leading`, `--gw-display-h2-leading`; at 1.02
|
|
33
|
+
the descenders of a first line touched the capitals of the second). h3 and `.gw-h3` 20px / 600, tracking −0.02em,
|
|
34
|
+
1.2 lines, as every h3 on gemboss.ai (was 24px / 650). The lead at most 58ch (was 60ch). The label's square is ink
|
|
35
|
+
with 2px corners (was the accent, square) and its line height its surroundings'; the input `--gw-label-mark` (new, on
|
|
36
|
+
the label or anything around it) paints the square another colour, a gradient too.
|
|
37
|
+
- A section's head (`.gw-section__head`) up to 760px (was 660px). A lead under a heading 20px below it (in a head, a
|
|
38
|
+
split column, a CTA; 16px in the hero). What follows a head starts 40px below it, 48px from 768px, as a top margin
|
|
39
|
+
of the next thing at no specificity, so a block that brings its own keeps it (was the head's bottom margin).
|
|
40
|
+
- The scroll reveal: 20px (new token `--gw-reveal-distance`, was 24px), once 12% of it is in view with the bottom 6% of
|
|
41
|
+
the view not counting (was 15%); each `.gw-reveal` after the first among its siblings waits 70ms more, at most 380ms;
|
|
42
|
+
a `[data-gw-count]` number inside counts up from 0 over 1.1s (new); the script's failsafe at 1.6s (was 2.5s). The
|
|
43
|
+
values are `system.json` `motion.reveal`.
|
|
44
|
+
- `check`: `--gw-label-mark` is an input, like a mega panel's widths.
|
|
45
|
+
- `website.js` is 10.4 KB gzipped (the budget is 10.5 KB, was 10 KB: the reveal's stagger and count-up).
|
|
46
|
+
|
|
47
|
+
## 0.11.0 (2026-10-26)
|
|
48
|
+
|
|
49
|
+
The header, 1:1 with gemboss.ai. Since the footer (0.10.0), the header was the last part of gemboss.ai not drawn by
|
|
50
|
+
the kit, and the kit's header was a simpler one: a narrower panel with icons, a button for each section, no pictures,
|
|
51
|
+
nothing behind. Chris asked for it identical, with nothing missed, and for every value to live in the kit so that
|
|
52
|
+
GemPages, Gemians and GemX inherit it (26/10/2026). 0.11.0 takes every value and every motion from gemboss.ai's own
|
|
53
|
+
header and was measured against it in Chromium, pixel by pixel: the bar at 320 to 1920px, every menu open at 1081,
|
|
54
|
+
1366, 1440 and 1920px, rows hovered (their previews), the pill under a hovered name, the keyboard's focus, the phone
|
|
55
|
+
menu's top level, each level and each level's end at 390, 768 and 1080px, light and dark, on pages in each section.
|
|
56
|
+
All of it is identical but one thing, on purpose: on the phone, gemboss.ai's own menu gives "Start free" a light
|
|
57
|
+
bottom hairline and takes "Book a demo"'s away (a rule meant for its menu's rows reaches them); the kit draws the two
|
|
58
|
+
buttons whole.
|
|
59
|
+
|
|
60
|
+
A minor version: a 0.10.0 header changes to these values, and its mega menu's markup changes (below).
|
|
61
|
+
|
|
62
|
+
- The bar: the page's wrap + 12px (1132px on GemBoss), 24px inside (6px up to 640px), its own width whatever order the
|
|
63
|
+
stylesheets load in (`.gw-header > .gw-header__bar`; drop `.gw-wrap` from it). The logo 34px with 8px corners (was
|
|
64
|
+
26px), a 44px row up to 768px. The menu's words 0.005em tighter, 38px tall (8px x 12px, 1.6 lines); the current page
|
|
65
|
+
or section in the accent's strong ink, weight 600 (was ink with an underline; a section's name carries
|
|
66
|
+
`aria-current`). Actions 4px apart: Sign in from 1081px, a second text action `.gw-header__link` (Book a demo) from
|
|
67
|
+
1181px, the button from 561px, 8px further out. The menu button 42px (44px on touch) with one strong hairline on
|
|
68
|
+
the surface, the card radius, ink while open; its icons gemboss.ai's. The phone menu runs to 1080px, the desktop
|
|
69
|
+
starts at 1081px (was 1080px), in the CSS and in `website.js`.
|
|
70
|
+
- The mega menu, gemboss.ai's own (its v5): a section's name is a link to its page (`a.gw-nav__trigger` with a 12px
|
|
71
|
+
`.gw-nav__chev`) that opens its panel after the pointer rests 200ms (90ms to switch, 350ms to close; the keyboard's
|
|
72
|
+
focus at once; ArrowDown steps into the first row). One surface morphs to the open panel's size and place, the
|
|
73
|
+
panels crossfade on it, a caret points at the name, a pill glides under the hovered name, a highlight under the
|
|
74
|
+
hovered row, the page behind dims and blurs (`.gw-scrim`, `--gw-scrim`). A panel: `.gw-mega__body` (columns of
|
|
75
|
+
rows, then `.gw-mega__aside`, the pictures) and an optional `.gw-mega__foot` strip; its widths and columns are its
|
|
76
|
+
markup's (`--gw-mega-w`, `--gw-mega-pv`, `--gw-mega-cols`). Pictures sit on the Stage (`.gw-mega__art`, new tokens
|
|
77
|
+
`--gw-stage-*`): the panel's own `.gw-mega__card`, and a row's preview, the `<template>` its `data-gw-preview` names
|
|
78
|
+
(`"feature"`: the panel's card). A card's pictures load the first time it shows (`data-gw-bg`,
|
|
79
|
+
`template[data-gw-hydrate]`, `.is-hydrated`). A picture straight on the Stage (an `<img>`) fills it.
|
|
80
|
+
- Moving a 0.10.0 header: the panel's `.gw-wrap.gw-mega__grid` becomes `.gw-mega__body > .gw-mega__grid`, the
|
|
81
|
+
`.gw-mega__feature` card becomes a `.gw-mega__card` in a `.gw-mega__aside` (its words in `.gw-mega__card-text`, a
|
|
82
|
+
picture in `.gw-mega__art`), the rows' `.gw-mega__icon` is not drawn on desktop. A `<button>` name still works: a
|
|
83
|
+
click opens its panel and keeps it open, a second click closes it. `templates/header.html` has the new markup.
|
|
84
|
+
- The script: the mega menu is wired per header (the `mega` mark is on the `.gw-header` now, not on each name);
|
|
85
|
+
`gw:mega` fires on the name. One panel open on the page, across headers. `destroy` takes the surface, caret, pill,
|
|
86
|
+
scrim and previews away and hides the panels again.
|
|
87
|
+
- The phone menu (the drill-down): 24px in from the edges, its links set at 18px, weight 500, 0.005em tighter, its
|
|
88
|
+
heads and headings on 1.6 lines; a row under the pointer or the keyboard takes the soft ground, 2px to the right, its
|
|
89
|
+
icon tile in the accent; a row may carry a 48x32 picture; a level may end with its panel's card and "All of … →"
|
|
90
|
+
(the arrow after a space); the action bar's buttons 8px apart, 16px words; `.gw-mobile-menu__link--muted`, a
|
|
91
|
+
quieter link before Sign in (What's new). The current page is not marked on the phone.
|
|
92
|
+
- Tokens, gemboss.ai's: the dark theme's shadows (`shadow.dark`: a 1px ledge, a deeper raised shadow; the kit kept
|
|
93
|
+
the light ones in dark before), `--gw-shadow-lift` (an object on the Stage), `--gw-stage-*` (glow, glow-2, top,
|
|
94
|
+
bottom, dot, ink), `--gw-scrim` light and dark, `--gw-radius-2` (the caret's corner), the dark theme's primary
|
|
95
|
+
button `#e3e4e8` (gemboss.ai's ink, was `#f2f3f5`). The focus ring 3px out with 4px corners (was 2px out).
|
|
96
|
+
- `check`: a mega panel's `--gw-mega-w`, `--gw-mega-pv`, `--gw-mega-cols` are inputs set in the markup, not tokens;
|
|
97
|
+
every kit shadow (dark ones and the lift included) is a token shadow.
|
|
98
|
+
- Budget: `js/website.js` is 34 KB, 9.9 KB gzipped (0.10.0: 23.1 KB, 7.1 KB); the test's budget is now 36 KB and
|
|
99
|
+
10 KB.
|
|
100
|
+
- Tests: `test/run.mjs` holds the header's base rules byte for byte again from this version (their hash renewed once),
|
|
101
|
+
the mega menu in its fake DOM (the marks, the drawn parts, hover 200/90/350ms, touch, focus, ArrowDown, the pinned
|
|
102
|
+
button, one open across headers, destroy); `test/browser.mjs` drives the desktop mega menu at 1366px (its timing,
|
|
103
|
+
the surface and caret placement, a row's preview, ArrowDown, Escape, destroy). Demos and templates carry the new
|
|
104
|
+
markup.
|
|
105
|
+
|
|
7
106
|
## 0.10.0 (2026-10-26)
|
|
8
107
|
|
|
9
108
|
The footer, 1:1 with gemboss.ai. 0.7.0 drew the footer "as gemboss.ai has it", but not to the pixel: when gemboss.ai
|
package/README.md
CHANGED
|
@@ -40,9 +40,9 @@ nó đọc `AGENTS.md` của kit trước, dựng từ mẫu, và chạy `check`
|
|
|
40
40
|
**Site HTML tĩnh hoặc không có bước build:** dùng CDN của npm, ghim đúng phiên bản.
|
|
41
41
|
|
|
42
42
|
```html
|
|
43
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gemboss/website-ui@0.
|
|
43
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gemboss/website-ui@0.12.0/website.min.css">
|
|
44
44
|
<link rel="stylesheet" href="/site.css"> <!-- CSS riêng của site, luôn SAU kit -->
|
|
45
|
-
<script src="https://cdn.jsdelivr.net/npm/@gemboss/website-ui@0.
|
|
45
|
+
<script src="https://cdn.jsdelivr.net/npm/@gemboss/website-ui@0.12.0/js/website.js" defer></script>
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Chèn markup của kit sau khi trang đã tải (block của builder, bản xem trước CMS): gọi `gwWebsite.init(phầnMới)` ngay
|
package/bin/lib/check.mjs
CHANGED
|
@@ -335,7 +335,10 @@ export function subjectOf(sel) {
|
|
|
335
335
|
const ATTR_THEME = String.raw`\[\s*data-theme(?:\s*[~|^$*]?=\s*(?:"[^"]*"|'[^']*'|[\w-]+))?\s*\]`;
|
|
336
336
|
const ROOTISH = new RegExp(`^(?::root|html)?(?:${ATTR_THEME}|:not\\(\\s*${ATTR_THEME}\\s*\\))*$`, "i");
|
|
337
337
|
const isRootish = (sel) => splitTop(sel).every((s) => s && ROOTISH.test(s));
|
|
338
|
-
|
|
338
|
+
// set on one element in the markup, read by the kit's CSS: the stars' value (style="--gw-stars: 4.9"); a mega panel's width,
|
|
339
|
+
// its pictures' width and its columns (0.11.0: style="--gw-mega-w: 1120px; --gw-mega-pv: 380px; --gw-mega-cols: 2"); the colour of
|
|
340
|
+
// a label's square (0.12.0: --gw-label-mark, on the label or around it)
|
|
341
|
+
const INPUTS = new Set(["--gw-stars", "--gw-mega-w", "--gw-mega-pv", "--gw-mega-cols", "--gw-label-mark"]);
|
|
339
342
|
const THEMABLE = /^--gw-(?:accent(?:-[\w-]+)?|on-accent(?:-(?:light|dark))?|wash(?:-[\w-]+)?)$/; // docs/theming.md: the eight accent variables (-light/-dark) + wash
|
|
340
343
|
|
|
341
344
|
const COLOR_PROPS = /^(?:color|background(?:-color|-image)?|border(?:-(?:top|right|bottom|left|block|inline)(?:-(?:start|end))?)?(?:-color)?|outline(?:-color)?|fill|stroke|text-decoration(?:-color)?|caret-color|accent-color|column-rule(?:-color)?|text-emphasis(?:-color)?|-webkit-text-fill-color|-webkit-text-stroke(?:-color)?|scrollbar-color|stop-color|flood-color|lighting-color)$/;
|
|
@@ -361,7 +364,9 @@ const BUTTONISH = /btn|button/i;
|
|
|
361
364
|
const pxNumbers = (v) => [...v.matchAll(/(-?\d*\.?\d+)(px|rem)\b/gi)].map((m) => ({ raw: m[0], px: Math.abs(parseFloat(m[1])) * (m[2].toLowerCase() === "rem" ? 16 : 1), unit: m[2].toLowerCase() }));
|
|
362
365
|
const isFraction = (n) => Math.abs(n - Math.round(n)) > 1e-6;
|
|
363
366
|
const normShadow = (s) => s.toLowerCase().replace(/\b0\./g, ".").replace(/\s*([,()])\s*/g, "$1").replace(/\s+/g, " ").trim();
|
|
364
|
-
|
|
367
|
+
// every shadow the kit draws: rest, sm, raised, the Stage's lift and (0.11.0) the dark theme's own
|
|
368
|
+
const TOKEN_SHADOWS = new Set(Object.entries(SYSTEM.shadow).filter(([k]) => !k.startsWith("$"))
|
|
369
|
+
.flatMap(([, v]) => (typeof v === "string" ? [v] : Object.values(v))).map(normShadow));
|
|
365
370
|
|
|
366
371
|
function okShadowPart(p) {
|
|
367
372
|
const v = p.trim();
|
package/css/base.css
CHANGED
|
@@ -32,33 +32,34 @@ h1, h2, h3, h4, h5, h6, .gw-h1, .gw-h2, .gw-h3, .gw-h4 {
|
|
|
32
32
|
text-wrap: balance;
|
|
33
33
|
}
|
|
34
34
|
h1, .gw-h1, h2, .gw-h2 { font-weight: var(--gw-display-weight); letter-spacing: var(--gw-display-tracking); }
|
|
35
|
-
h1, .gw-h1 { font-size: var(--gw-display-h1); }
|
|
36
|
-
h2, .gw-h2 { font-size: var(--gw-display-h2); }
|
|
37
|
-
h3,
|
|
35
|
+
h1, .gw-h1 { font-size: var(--gw-display-h1); line-height: var(--gw-display-h1-leading); }
|
|
36
|
+
h2, .gw-h2 { font-size: var(--gw-display-h2); line-height: var(--gw-display-h2-leading); }
|
|
37
|
+
/* h3 (0.12.0): 20px/600, as every h3 on gemboss.ai */
|
|
38
|
+
h3, .gw-h3 { font-size: 20px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
|
|
38
39
|
h4, .gw-h4 { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
|
|
39
40
|
h5, h6 { font-size: 16px; font-weight: 600; letter-spacing: 0; }
|
|
40
41
|
|
|
41
|
-
.gw-lead { font-size: 18px; line-height: 1.55; color: var(--gw-muted); max-width:
|
|
42
|
+
.gw-lead { font-size: 18px; line-height: 1.55; color: var(--gw-muted); max-width: 58ch; }
|
|
42
43
|
.gw-note { font-size: 14px; color: var(--gw-muted); }
|
|
43
44
|
.gw-dim { color: var(--gw-muted); }
|
|
44
45
|
|
|
45
|
-
/* the label above a heading: sentence case, muted, led by the 8px
|
|
46
|
+
/* the label above a heading: sentence case, muted, led by the 8px square, ink by default (0.12.0, as gemboss.ai). The
|
|
47
|
+
input --gw-label-mark paints the square another colour (a product's own, say): set it on the label or on anything
|
|
48
|
+
around it, e.g. style="--gw-label-mark: var(--gw-accent)". */
|
|
46
49
|
.gw-label {
|
|
47
50
|
display: inline-flex;
|
|
48
51
|
align-items: center;
|
|
49
52
|
gap: 8px;
|
|
50
53
|
font-size: 13px;
|
|
51
54
|
font-weight: 500;
|
|
52
|
-
line-height: 1.4;
|
|
53
55
|
color: var(--gw-muted);
|
|
54
56
|
}
|
|
55
57
|
.gw-label::before {
|
|
56
58
|
content: "";
|
|
57
|
-
flex: none;
|
|
58
59
|
width: 8px;
|
|
59
60
|
height: 8px;
|
|
60
|
-
border-radius: var(--gw-radius-
|
|
61
|
-
background: var(--gw-
|
|
61
|
+
border-radius: var(--gw-radius-2);
|
|
62
|
+
background: var(--gw-label-mark, var(--gw-ink));
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/* links inside running text (and anywhere in .gw-prose) get a visible link style; everything else opts in with .gw-link */
|
|
@@ -74,22 +75,26 @@ h5, h6 { font-size: 16px; font-weight: 600; letter-spacing: 0; }
|
|
|
74
75
|
:where(p, dd, td, figcaption, .gw-list--check li, .gw-prose) a:not([class]):hover,
|
|
75
76
|
.gw-link:hover { text-decoration-color: currentColor; }
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
/* the focus ring, as gemboss.ai draws it (0.11.0): 2px of accent, 3px out, 4px corners */
|
|
79
|
+
:focus-visible { border-radius: var(--gw-radius-4); outline: 2px solid var(--gw-accent); outline-offset: 3px; }
|
|
78
80
|
[id] { scroll-margin-top: calc(var(--gw-header-height) + 16px); }
|
|
79
81
|
|
|
82
|
+
/* the skip link (0.12.0, gemboss.ai's): the accent tab in the top left corner, shown while it has the focus */
|
|
80
83
|
.gw-skip {
|
|
81
84
|
position: absolute;
|
|
82
85
|
left: -9999px;
|
|
83
|
-
top:
|
|
84
|
-
z-index:
|
|
85
|
-
padding: 12px
|
|
86
|
-
border-radius: var(--gw-radius-
|
|
87
|
-
background: var(--gw-
|
|
88
|
-
color: var(--gw-on-
|
|
86
|
+
top: 0;
|
|
87
|
+
z-index: 200;
|
|
88
|
+
padding: 12px 20px;
|
|
89
|
+
border-radius: 0 0 var(--gw-radius-card) 0;
|
|
90
|
+
background: var(--gw-accent);
|
|
91
|
+
color: var(--gw-on-accent);
|
|
92
|
+
box-shadow: var(--gw-shadow);
|
|
89
93
|
font-size: 14px;
|
|
90
94
|
font-weight: 600;
|
|
91
95
|
}
|
|
92
|
-
|
|
96
|
+
/* its corner again with the focus: a page's own :focus-visible corners, loaded after the kit, must not round the tab */
|
|
97
|
+
.gw-skip:focus { left: 0; border-radius: 0 0 var(--gw-radius-card) 0; }
|
|
93
98
|
|
|
94
99
|
/* words for a screen reader only (0.7.0): " (opens in a new tab)" in a link with target="_blank" */
|
|
95
100
|
.gw-visually-hidden {
|
|
@@ -103,10 +108,11 @@ h5, h6 { font-size: 16px; font-weight: 600; letter-spacing: 0; }
|
|
|
103
108
|
border: 0;
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
/* scroll reveal: the script adds .is-in
|
|
111
|
+
/* scroll reveal: the script adds .is-in (system.json motion.reveal: when, the stagger, the failsafe); the animation is
|
|
112
|
+
a second failsafe, for a page whose script never ran, that shows it anyway after 2.5s */
|
|
107
113
|
.gw-reveal {
|
|
108
114
|
opacity: 0;
|
|
109
|
-
transform: translateY(
|
|
115
|
+
transform: translateY(var(--gw-reveal-distance));
|
|
110
116
|
transition: opacity var(--gw-reveal-ms) var(--gw-ease), transform var(--gw-reveal-ms) var(--gw-ease);
|
|
111
117
|
animation: gw-reveal-failsafe 1ms linear 2.5s forwards;
|
|
112
118
|
}
|
package/css/components.css
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
/* actions are rectangles: 40px, the action radius of the site's profile (8, 12 in soft), 14px/600, sentence case.
|
|
4
4
|
The fill is the action colour: ink, or the brand's accent under data-gw-action="accent" (tokens.css). Never a
|
|
5
|
-
gradient
|
|
5
|
+
gradient or a wash hue. On hover (0.12.0, as gemboss.ai) the filled button rises 1px onto the rest shadow; the framed
|
|
6
|
+
and frameless ones only change their frame or tint. Phones: see "touch" below. */
|
|
6
7
|
.gw-btn {
|
|
7
8
|
position: relative;
|
|
8
9
|
display: inline-flex;
|
|
9
10
|
align-items: center;
|
|
10
|
-
justify-content: center;
|
|
11
11
|
gap: 8px;
|
|
12
12
|
max-width: 100%;
|
|
13
13
|
height: var(--gw-button-height);
|
|
@@ -16,26 +16,34 @@
|
|
|
16
16
|
border-radius: var(--gw-radius-action);
|
|
17
17
|
background: var(--gw-action);
|
|
18
18
|
color: var(--gw-on-action);
|
|
19
|
+
font-family: var(--gw-font-action);
|
|
19
20
|
font-size: 14px;
|
|
20
21
|
font-weight: 600;
|
|
21
|
-
line-height: 1.4;
|
|
22
22
|
letter-spacing: 0;
|
|
23
23
|
text-align: center;
|
|
24
24
|
white-space: nowrap;
|
|
25
25
|
cursor: pointer;
|
|
26
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
26
27
|
}
|
|
27
|
-
.gw-btn:hover {
|
|
28
|
+
.gw-btn:hover { transform: translateY(-1px); box-shadow: var(--gw-shadow); }
|
|
28
29
|
.gw-btn svg { flex: none; width: 16px; height: 16px; }
|
|
29
30
|
.gw-btn--secondary { background: transparent; border-color: var(--gw-line-strong); color: var(--gw-ink); }
|
|
30
31
|
.gw-btn--secondary:hover { background: transparent; border-color: var(--gw-ink); }
|
|
31
32
|
.gw-btn--ghost { background: transparent; color: var(--gw-ink); }
|
|
32
33
|
.gw-btn--ghost:hover { background: var(--gw-bg-soft); }
|
|
34
|
+
.gw-btn:is(.gw-btn--secondary, .gw-btn--ghost):hover { transform: none; box-shadow: none; }
|
|
35
|
+
/* an arrow after the label (→), nudged 3px on hover */
|
|
36
|
+
.gw-btn__arrow { letter-spacing: 0; transition: transform 0.18s ease; }
|
|
37
|
+
.gw-btn:hover .gw-btn__arrow { transform: translateX(3px); }
|
|
38
|
+
|
|
33
39
|
.gw-btn--on-night { background: var(--gw-on-night); color: var(--gw-night); }
|
|
34
40
|
.gw-btn--on-night:hover { background: var(--gw-on-night); opacity: 0.88; }
|
|
35
41
|
.gw-btn--sm { height: 36px; padding: 0 16px; }
|
|
36
42
|
.gw-btn--sm::after { content: ""; position: absolute; top: -6px; right: 0; bottom: -6px; left: 0; }
|
|
37
43
|
.gw-btn--lg { height: 48px; padding: 0 24px; font-size: 16px; }
|
|
38
|
-
.
|
|
44
|
+
/* a button wider than its label keeps the label at its start (as gemboss.ai), unless it is made wide on purpose: full
|
|
45
|
+
width (--block), a phone's row of actions, an inline form */
|
|
46
|
+
.gw-btn--block { display: flex; width: 100%; justify-content: center; }
|
|
39
47
|
.gw-btn:disabled, .gw-btn[aria-disabled="true"] { opacity: 0.48; cursor: not-allowed; pointer-events: none; }
|
|
40
48
|
/* pressed: the ink one step darker (the hover ink, as the dashboard's primary), nothing moves; the frameless variants
|
|
41
49
|
take one more step of tint */
|
|
@@ -334,16 +342,21 @@
|
|
|
334
342
|
.gw-faq__item[open] > summary::after { transform: rotate(45deg); }
|
|
335
343
|
.gw-faq__item > :not(summary) { margin: 0 0 20px; max-width: 68ch; color: var(--gw-muted); font-size: 16px; }
|
|
336
344
|
|
|
337
|
-
/* touch: every control is at least 44px tall,
|
|
338
|
-
|
|
345
|
+
/* touch: every control is at least 44px tall. A button up to 768px (0.12.0, as gemboss.ai: by the width, not the
|
|
346
|
+
pointer), its label wrapping (and tighter) from 480px down in the page's <main>, so a long one never pushes the page
|
|
347
|
+
sideways (a header or an overlay outside <main> keeps its one line) */
|
|
348
|
+
@media (max-width: 768px) {
|
|
339
349
|
.gw-btn, .gw-btn--sm, .gw-btn--lg {
|
|
340
350
|
height: auto;
|
|
341
351
|
min-height: var(--gw-tap-min);
|
|
342
352
|
padding-block: 8px;
|
|
343
|
-
white-space: normal;
|
|
344
|
-
text-wrap: balance;
|
|
345
353
|
}
|
|
346
354
|
.gw-btn--lg { min-height: 48px; }
|
|
355
|
+
}
|
|
356
|
+
@media (max-width: 480px) {
|
|
357
|
+
:where(main) .gw-btn { white-space: normal; line-height: 1.35; }
|
|
358
|
+
}
|
|
359
|
+
@media (max-width: 768px), (pointer: coarse) {
|
|
347
360
|
:is(a, button, label).gw-chip { min-height: var(--gw-tap-min); }
|
|
348
361
|
.gw-segmented > button { height: auto; min-height: var(--gw-tap-min); padding-block: 8px; white-space: normal; text-wrap: balance; }
|
|
349
362
|
}
|
package/css/effects.css
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
the build checks the words on. */
|
|
51
51
|
.gw-btn.gw-spot:not([aria-busy="true"])::before { --gw-spot-mix: var(--gw-spot-strength-action); }
|
|
52
52
|
/* the mega menu's feature card is the Stage, a night ground: a stronger light, or it would not show */
|
|
53
|
-
.gw-
|
|
53
|
+
.gw-mega__art.gw-spot:not([aria-busy="true"])::before { --gw-spot-mix: var(--gw-spot-strength-stage); }
|
|
54
54
|
|
|
55
55
|
/* words under the light: lit, muted words are ink-2 at once (rules above); back to muted only once the light has gone
|
|
56
56
|
out (a colour that waits the light's time, no movement). :where(), so a part's own transition wins. */
|
package/css/forms.css
CHANGED
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
room; below 480px, and in a box too narrow for both, the field and the button each take a full line. */
|
|
135
135
|
.gw-form-inline { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
136
136
|
.gw-form-inline > :not(.gw-btn) { flex: 999 1 160px; min-width: 0; }
|
|
137
|
-
.gw-form-inline > .gw-btn { flex: 1 0 auto; }
|
|
137
|
+
.gw-form-inline > .gw-btn { flex: 1 0 auto; justify-content: center; }
|
|
138
138
|
@media (max-width: 479px) {
|
|
139
139
|
.gw-form-inline > :not(.gw-btn) { flex-basis: 100%; }
|
|
140
140
|
}
|