@gemboss/ui 0.40.0 → 0.42.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 CHANGED
@@ -2,6 +2,108 @@
2
2
 
3
3
  Versions up to 0.9.0 are described in the README, each in the section that introduced it.
4
4
 
5
+ ## 0.42.0 (21/10/2026)
6
+
7
+ **The editor's colour field offers the page's theme colours and this store's recent colours** (gemboss #4888, Chris "bấm
8
+ trước gõ sau").
9
+
10
+ Added
11
+ - `ColorControl` takes `choices` (`ColorChoice { value, label, swatch }`): chips under the field while it is in use; a chip
12
+ writes its `value` (a theme chip writes `var(--gem-color-<role>)`). `themeColorChoices(palette)` lists the theme's roles in
13
+ `TOKEN_NAMES` order. No new CSS: `.gemboss-ei-swatches` / `.gemboss-ei-sw`.
14
+
15
+ **Team chat days in a given time zone; leaderboard words in the page's language** (follow-ups of GemCommunity's UX audit,
16
+ 20–21/10/2026: /chat threw React #418 because the server (UTC) and a browser in Hanoi drew different day separators, and the
17
+ app had to feed the rules shifted dates; the podium's screen-reader words were English on vi and zh pages).
18
+
19
+ Added
20
+ - `timeZone` (IANA name) on `teamChatRows` options and as a last argument of `chatDayKey` and `chatDayWord`: days are that
21
+ zone's calendar days. An unknown name or an invalid date falls back to the local day, as without it.
22
+ - `chatDayISO(at, timeZone?)`: the day as "2026-10-21", for a `DaySeparator`'s `dateTime`.
23
+ - Plain script: `gembossUI.teamChat.rows` reads `opts.timeZone`; `dayKey`, `dayWord` take it last; `dayISO` is new. Held to
24
+ the TypeScript by `team-chat-plain-data.test.ts` under four zones (one unknown).
25
+ - `Podium`: `label` (the list's name, default "Top three") and `rankLabel` (default `(n) => "Rank " + n`); `Leaderboard`:
26
+ `rankLabel`. Defaults keep the markup as it was.
27
+
28
+ **"Frequently used" in the reaction picker always holds nine** (Chris 20/10/2026: GemCare's row held nine; the package's showed
29
+ only what this browser had used, one or two for a new person, which read as empty).
30
+
31
+ Changed
32
+ - `ReactionPicker` (React) and `gembossUI.teamChat.reactionPicker` (plain): "Frequently used" is what this browser used, most
33
+ recent first, then the `SUGGESTED_REACTIONS` it has not used (👍 ✅ 🙏 🎉 😂 ❤️ 👀 🙌 🔥), nine in all.
34
+ - `reactions-data.ts` exports `SUGGESTED_REACTIONS`, `FREQUENT_MAX` and `frequentReactions(recent)`. The plain script carries
35
+ the list in its data block and the same function in ES5, held to the TypeScript by `team-chat-plain-data.test.ts`.
36
+
37
+ ## 0.41.0 (20/10/2026)
38
+
39
+ **A document read over its list** (Chris 20/10/2026, after GemMedia's and partner-radar's Docs drew the same popup with
40
+ their own CSS: "làm đi").
41
+
42
+ Added
43
+ - `ReaderDialog`: the kit popup sized for reading, `min(1440px, 94vw)` × `min(92dvh, 1200px)`, the whole screen under
44
+ 768px with the head's actions on their own line. It is `Dialog` with `ui-reader` (same props, less `wide`). The body has
45
+ no padding and is a column the document fills: `ui-reader__frame` (an iframe) or `ui-reader__scroll` (a padded scroller
46
+ of the surface's own). README "ReaderDialog", catalog "Hộp đọc tài liệu".
47
+ - `packages/ui/src/reader-dialog.css` (`@gemboss/ui/reader-dialog.css`): its own entry, imported by the component; every
48
+ selector `dialog.ui-modal.ui-reader…`. Nothing moves into the core or the bundle.
49
+ - `reader-dialog.test.tsx` (markup, every class styled, selectors), `reader-dialog-browser.test.tsx` (Chromium: size,
50
+ fill, scroll, phone head, page lock, Escape; negative control without the entry finds the 460px popup).
51
+
52
+ **A colour field reads every colour, not only a 6-digit hex** (A4, 21/10/2026). Measured on 169 element pages: of 3,283 colour
53
+ values, 66% are `rgb()`, 17% `rgba()`, 9% a 6-digit hex, ~3% `oklch()`. Only the hex 9% had a swatch: nine colours in ten showed a
54
+ locked black square.
55
+
56
+ Changed
57
+ - `swatchState` shows any one colour (`parseColor`: hex of 3, 4, 6 or 8 digits, `rgb`/`rgba`, `hsl`/`hsla`, `oklch`). A token, a
58
+ gradient, a scheme id or a padded value is still not a colour the swatch can stand for: off, with the reason.
59
+ - `ColorControl`: a pick on the swatch keeps the value's transparency and way of writing (`pickSwatch`: a hex stays a hex, else
60
+ `rgb()`, `rgba()` with an alpha), so turning the swatch on can never drop an alpha. A colour's opacity sits beside it in a `%`
61
+ box (`input[data-alpha]`, `withOpacity`); a value that is not one colour has none. No CSS change (the box's width is inline).
62
+ - `swatchWhy`: "Type a color to use your own"; the kept-as-written reason names what the swatch reads.
63
+ - `editor-plain.js`: the same swatch and `%` box on a page without React, for a hex and `rgb()`/`rgba()` (92% of the colours
64
+ measured); `hsl()` and `oklch()` stay a locked swatch there (named in editor-panel.test.tsx). Exposes `gembossUI.colorOf`,
65
+ `pickSwatch`, `withOpacity`.
66
+
67
+ Added
68
+ - `parseColor`, `pickSwatch`, `opacityOf`, `withOpacity`, type `Rgba` (from `@gemboss/ui/editor`).
69
+
70
+ **A colour field offers colours to click before one to type** (A4b, 21/10/2026; Chris: "bấm trước gõ sau").
71
+
72
+ Added
73
+ - `ColorControl` `choices`: chips under the field while it is in use (focus inside it), each a `ColorChoice` `{ value, label,
74
+ swatch }`: the value written on a click, its name, the colour it paints. A token value painted by a chip shows that colour on the
75
+ swatch, and a pick on the swatch then starts from it. None drawn in SSR or when `choices` is empty.
76
+ - `themeColorChoices(palette)`: the theme's colour roles as choices (`var(--gem-color-<role>)`, in `TOKEN_NAMES` order), painted
77
+ with the colour the page draws for each; a role the palette does not paint is left out. Type `ColorChoice`.
78
+
79
+ **The team chat's rows for a plain page, from the package: `gembossUI.teamChat`** (Chris 20/10/2026: the markup in ONE place,
80
+ so GemCare stops writing it by hand and a change to it is made once).
81
+
82
+ Added
83
+ - `packages/ui/src/team-chat-plain.js` (`@gemboss/ui/team-chat-plain.js`, its own entry): builders that RETURN elements with
84
+ the components' markup for the same props: `message` (`Message`, every prop; plus `picking` / `reactionsPicking` /
85
+ `onPickingChange` for a page that redraws its list), `daySeparator`, `newMessagesLine`, `jumpToLatest` + `updateJump`,
86
+ `readReceipt`, `channelSection`, `channelItem`, `peopleSection`, `personRow`, `reactions`, `reactionPicker` (the package's
87
+ picker and its keys, "Frequently used" under the React picker's storage key), `avatar`, `icon`, and `rows` / `dayKey` /
88
+ `dayWord` (`teamChatRows`, `chatDayKey`, `chatDayWord`). Labels are `TEAM_CHAT_LABELS` (`LABELS`), any subset overridable.
89
+ Strings are text; callbacks are click listeners. A classic script, ES5, after `kit-plain.js` when the page has it.
90
+ 8,208 B gzip minified (ceiling 8,714 in `weight-budget.json`; a page that draws no team chat never loads it).
91
+ - `team-chat-plain-browser.test.ts` (Chromium, `test:ui-browser`): every builder, in every state, against
92
+ `renderToStaticMarkup` of its component as one tree (attributes, classes, text, SVG in full); the same clicks and keys on
93
+ the mounted components and on the plain rows leave the same DOM (the pickers, search, Escape and focus); callbacks,
94
+ escaping, toolbar and picker keys, `updateJump`, the load-order warning. `team-chat-plain-data.test.ts` (node): the
95
+ generated block (icons, emoji set; `UPDATE_PLAIN_TEAM_CHAT=1` writes it) and the ES5 copies (labels, initials, tone,
96
+ reaction helpers, row rules) held to the TypeScript.
97
+ - `team-chat.test.fixtures.tsx`: the contract test's data, now shared with the plain parity test (the README is unchanged).
98
+ - The catalog's "Chat đội" section has a live plain-HTML frame built with `gembossUI.teamChat`.
99
+
100
+ **A list whose items come from elsewhere** (item management IM2, 21/10/2026: a list that shows a content type).
101
+
102
+ Changed
103
+ - `RepeaterList` `onMove` and `onRemove` are optional. Without `onMove` the rows keep their order: no grip, no ↑ ↓, no
104
+ Alt+arrows, no drop. Without `onRemove`, no ✕. A row still opens (inline or in the popover) and still says it was picked
105
+ (`onActive`). The admin draws a list read from Content this way: its order and its rows are Content's. No CSS change.
106
+
5
107
  ## 0.40.0 (20/10/2026)
6
108
 
7
109
  **A list's item edits in a popover** (item management IM1a, Chris 20/10/2026; GemPages 7.5's "Item management" read in its code).
@@ -17,6 +119,14 @@ Added
17
119
  - `packages/ui/src/editor-repeater.css`: the popover's placement and header, the picked row's outline, the picture (+220 B gzip,
18
120
  1,096 of its 1,384 B ceiling). The surface is the fleet's `gemboss-popover-surface`.
19
121
 
122
+ **An inspector's tabs stand on the fields' edge** (Chris 20/10/2026: "cùng là tabs mà chỗ to chỗ nhỏ").
123
+
124
+ Fixed
125
+ - `packages/ui/src/editor.css`: `.gemboss-ei-tabs` inside a settings body or the column's dock drop their 12px side margin
126
+ (`:is(.gemboss-settings-body,.gemboss-ec-dock-body)`), so the Settings · Advanced track lines up with the fields under it (the
127
+ canvas's element and section panels measured 34–360 and 316px over fields at 22–372). A docked inspector keeps its own, more
128
+ specific rule; a floating inspector keeps 12px. +15 B gzip (8,680 of 8,690).
129
+
20
130
  **A phone pays for the topbar once, and the full-screen assistant gets the whole width** (measured on the admin at 390×844,
21
131
  19/10/2026).
22
132
 
package/README.md CHANGED
@@ -71,6 +71,7 @@ its CSS out of the build with it (`sideEffects`). gzip of the minified file, as
71
71
  | assistant-chat | `@gemboss/ui/assistant-chat.css` | `packages/ui/src/assistant-chat.css` | the chat pieces the package draws (0.29.0): column, starters that wrap, meta, errors, notes, paperclip | 0.9 KB | `AssistantChat` and its pieces import it |
72
72
  | minichart | `@gemboss/ui/minichart.css` | `packages/ui/src/minichart.css` | `Sparkline`, `ShareBar` (0.30.0) | 0.5 KB | those components import it |
73
73
  | setup-guide | `@gemboss/ui/setup-guide.css` | `packages/ui/src/setup-guide.css` | `SetupGuide` (0.30.0) | 0.9 KB | `SetupGuide` imports it |
74
+ | reader-dialog | `@gemboss/ui/reader-dialog.css` | `packages/ui/src/reader-dialog.css` | `ReaderDialog`: the popup sized for reading a document (0.41.0) | 0.4 KB | `ReaderDialog` imports it |
74
75
  | service-switcher | `@gemboss/ui/service-switcher.css` | `packages/ui/src/service-switcher.css` | `ServiceSwitcher` and `Switcher`: the button after the brand and its panel (0.36.0; any list, illustrated tiles 0.40.0) | 2.2 KB | `ServiceSwitcher` imports it, and `BrandLockup` through it (README "ServiceSwitcher") |
75
76
  | team-chat | `@gemboss/ui/team-chat.css` | `packages/ui/src/team-chat.css` | the team chat layer (20/10/2026): rail, messages, composer, thread and people panels, the screen's layout | 3.6 KB | `TeamChat` and its pieces import it (with `Avatar`'s portal.css and `Reactions`' reactions.css); a plain-HTML page links it (README "The team chat layer") |
76
77
  | bundle | `@gemboss/ui/gemboss-ui.css` | `gemboss-ui.css` | core + components + shell + auth + assistant + chat + portal + theme-dark | 21.9 KB | compatibility only (see CHANGELOG 0.23.0) |
@@ -1177,6 +1178,40 @@ The body scrolls under a head that stays, and scrolling past its end does not sc
1177
1178
  contain`). `packages/ui/src/sheet-browser.test.tsx` measures it in Chromium; its negative control runs the same probe
1178
1179
  without `sheet.css` and finds the centred popup. Catalog section "Ngăn trượt cạnh phải".
1179
1180
 
1181
+ ## ReaderDialog (0.41.0): a document read over its list
1182
+
1183
+ Two surfaces drew the same popup with their own CSS the same week, because `Dialog`'s widths (460, `wide` 620) are a
1184
+ form's: GemMedia's admin Docs (gemmedia #76) and partner-radar's Docs (gemlabs #1122) open a long document over the list
1185
+ of documents, nearly the whole window, the whole screen on a phone. Chris 20/10/2026: put it in the kit. `ReaderDialog`
1186
+ is that popup:
1187
+
1188
+ ```tsx
1189
+ import { ReaderDialog } from "@gemboss/ui";
1190
+
1191
+ <ReaderDialog open onClose={close} title={doc.title} subtitle={`v${doc.version} · updated ${doc.updated}`}
1192
+ actions={<><CopyLink slug={doc.slug} /><a className="ui-btn ui-btn--sm" href={doc.src} target="_blank">Open in a new tab</a></>}>
1193
+ <iframe className="ui-reader__frame" src={doc.src} title={doc.title} />
1194
+ </ReaderDialog>
1195
+ ```
1196
+
1197
+ The body is the document's. Give it one child that fills it: `iframe.ui-reader__frame` for a self-contained HTML
1198
+ document, or a scroller of your own with `ui-reader__scroll` (padded 24/32/48, 16/16/40 on a phone; it scrolls, keeps
1199
+ its overscroll, and takes `tabIndex={-1}` and focus so the arrow keys and Space read the document). Keys pressed inside
1200
+ an iframe do not reach the `<dialog>`: a surface that wants Escape there forwards it (`frame.contentWindow` keydown →
1201
+ `dialog.close()`, same-origin). A route that draws it (Next's intercepting route) leaves `open` true and goes back in
1202
+ `onClose`, as with `Sheet`.
1203
+
1204
+ | | |
1205
+ | --- | --- |
1206
+ | Markup | `<dialog class="ui-modal ui-reader">` with the popup's own `ui-modal__head` (title, `__subtitle`, `__actions`, ✕), `__body`, `__foot` |
1207
+ | Behaviour | It is `Dialog` with `ui-reader` on it (one render tree, one hook, `useModalDialog`): Escape, ✕ and a press that started on the backdrop close it, `onClose` hears each once, the page behind is inert and holds still (`html:has(dialog.ui-modal:modal)`), focus goes back to the opener. On open focus goes to the first control, as `Dialog`'s; move it to your document |
1208
+ | Size | `min(1440px, 94vw)` × `min(92dvh, 1200px)`, centred, from 768px up; the whole screen below that, where the actions take their own line under the title and ✕ stays beside it |
1209
+ | CSS | `reader-dialog.css`, its own entry, loaded by the component. Every selector is `dialog.ui-modal.ui-reader…` ((0,2,1)). It lays itself out (no padding, border-box, a column the document fills), so it works on a surface that loads `ui.css` alone. A plain-HTML surface links `@gemboss/ui/reader-dialog.css` beside `gemboss-ui.css` and opens the markup with `showModal()` |
1210
+
1211
+ `packages/ui/src/reader-dialog-browser.test.tsx` measures it in Chromium (size at four windows and three phones, the
1212
+ iframe flush under the head, the scroller scrolling under a head that stays, the phone's head, the page lock, Escape);
1213
+ its negative control runs without `reader-dialog.css` and finds the 460px popup. Catalog section "Hộp đọc tài liệu".
1214
+
1180
1215
  ## SettingsDialog (0.35.0): settings as one popup
1181
1216
 
1182
1217
  The admin's Settings (apps/admin `SettingsDialog`): one popup over the app, the sections in a rail on the left with a
@@ -1554,7 +1589,8 @@ import { Avatar, Dialog, Leaderboard, Podium, SearchDialog, ThemeToggle, themeSc
1554
1589
  Opt-in: a surface without it (the admin) stays light.
1555
1590
  - `Avatar` (24 · 32 · 40 · 56): picture or initials on one of eight tones picked from the name.
1556
1591
  - `Leaderboard`: 🥇 🥈 🥉 then the rank, avatar, name, count; the leader's count in gold; nothing at
1557
- all when empty. `Podium`: the first three, second · first · third.
1592
+ all when empty. `Podium`: the first three, second · first · third. Screen readers hear "Rank 1: " before each
1593
+ name and "Top three" for the podium; pass `rankLabel={(n) => …}` (both) and `label` (Podium) in the page's language.
1558
1594
  - `initialsOf` moved to `initials.ts` (plain, not "use client") so server components can call it; it is
1559
1595
  still exported from the package and from account.tsx.
1560
1596
  - **Without the whole kit (0.7.2):** a surface with its own skin (GemCommunity) takes only these pieces'
@@ -1679,7 +1715,10 @@ own state (the reaction picker a message opened, the composer's text when the ap
1679
1715
  write themselves is in `TEAM_CHAT_LABELS`; pass `labels` (any subset) to translate. `teamChatRows(messages, { meId,
1680
1716
  isUnread })` (plain TS, `team-chat-data.ts`) says where the day separators and the "New messages" line go and which
1681
1717
  messages are `grouped`: same author, same day, under 5 minutes apart, not a reply, and not the first new one (GemCare's
1682
- rules). `chatDayWord` gives "Today" / "Yesterday"; older days the app formats in its own locale.
1718
+ rules). `chatDayWord` gives "Today" / "Yesterday"; older days the app formats in its own locale. Days are the viewer's
1719
+ local days unless `timeZone` (an IANA name) is given to `teamChatRows`, `chatDayKey`, `chatDayWord` and `chatDayISO` (the day
1720
+ as "2026-10-21", for a `DaySeparator`'s `dateTime`): give it on a screen the server renders first, or the server's zone and
1721
+ the browser's draw different day separators (React #418). Format the times with the same zone.
1683
1722
 
1684
1723
  **The layout.** `.gb-tc` is a CSS grid and a size container: it decides by its OWN width (in an app shell the chat is the
1685
1724
  window minus the shell's rail), with container queries. `TEAM_CHAT_DRAWER_MAX` (1100) and `TEAM_CHAT_PHONE_MAX` (760) are the
@@ -2101,6 +2140,62 @@ closes a drawer, focus moves into it and back, the rail and the conversation are
2101
2140
  open state (`gb-tc-msg--active`, `aria-expanded` on its button); arrow keys along `div.gb-tc-acts[role=toolbar]`; when to
2102
2141
  show `.gb-tc-jump` and its count.
2103
2142
 
2143
+ ### Plain HTML: `gembossUI.teamChat` (20/10/2026)
2144
+
2145
+ So a plain page does not write the markup above by hand. `team-chat-plain.js` builds the rows from data and RETURNS
2146
+ elements whose markup is the component's for the same props: tags, classes, every attribute, the text, the icons' SVG.
2147
+ `team-chat-plain-browser.test.ts` draws every piece in every state both ways in Chromium (the contract's data,
2148
+ `team-chat.test.fixtures.tsx`, and the states beyond it) and holds them to one tree, so the markup is written once, in
2149
+ `team-chat.tsx`, and a plain page follows a change to it with a version bump. A classic script, no imports, inlinable:
2150
+ after `kit-plain.js` when the page has it (it adds `gembossUI.teamChat`; loaded first it says so in the console).
2151
+
2152
+ | Builder | Draws what this draws |
2153
+ |---|---|
2154
+ | `message(props)` | `Message`, every prop by the same name; plus `picking` / `reactionsPicking` (a picker drawn open) and `onPickingChange(which, open)` (`"bar"` or `"reactions"`) for a page that redraws its whole list |
2155
+ | `daySeparator(label, dateTime)`, `newMessagesLine(labels)` | `DaySeparator`, `NewMessagesLine` |
2156
+ | `jumpToLatest({ count, visible, onJump, labels })`, `updateJump(button, { count, visible, labels })` | `JumpToLatest`; `updateJump` redraws the same button (a scroll handler keeps its focus) |
2157
+ | `readReceipt({ read, of, label })` | `ReadReceipt` (`null` when `of` ≤ 0) |
2158
+ | `channelSection({ label, id, items })`, `channelItem(props)` | `ChannelSection`, `ChannelItem` (`href`: a link, else a button); `items` are rows or their props |
2159
+ | `peopleSection({ label, count, id, items })`, `personRow(props)` | `PeopleSection`, `PersonRow` (a link, a button with `onSelect`, else a `div`) |
2160
+ | `reactions(props)`, `reactionPicker(props)` | `Reactions` (plus `open` / `onOpenChange`), `ReactionPicker` |
2161
+ | `avatar({ name, src, size, className })`, `icon(name, size)` | `Avatar` (portal.tsx's initials and tone), `Icon` (the icons the builders draw, and `more`) |
2162
+ | `rows(messages, opts)`, `dayKey(at, timeZone)`, `dayISO(at, timeZone)`, `dayWord(at, now, timeZone)` | `teamChatRows`, `chatDayKey`, `chatDayISO`, `chatDayWord` |
2163
+ | `LABELS` | `TEAM_CHAT_LABELS`; `labels` (any subset) translates, functions included |
2164
+
2165
+ ```html
2166
+ <link rel="stylesheet" href="/ui/portal.css"><link rel="stylesheet" href="/ui/reactions.css"><link rel="stylesheet" href="/ui/team-chat.css">
2167
+ <script src="/ui/kit-plain.js"></script><script src="/ui/team-chat-plain.js"></script>
2168
+ ```
2169
+
2170
+ ```js
2171
+ const tc = gembossUI.teamChat;
2172
+ list.replaceChildren(...tc.rows(messages, { meId: me.id, isUnread: (m) => m.id > readUpTo }).map((r) =>
2173
+ r.kind === "day" ? tc.daySeparator(dayLabel(r.date), isoDay(r.date))
2174
+ : r.kind === "new" ? tc.newMessagesLine()
2175
+ : tc.message({ author: r.message.authorName, time: hhmm(r.message.at), dateTime: r.message.at, body: r.message.text,
2176
+ grouped: r.grouped, messageId: r.message.id, reactions: r.message.reactions, edited: Boolean(r.message.editedAt),
2177
+ receipt: tc.readReceipt({ read: 2, of: 3, label: "Read by Linh, Quan. Not yet: Bo" }),
2178
+ onReact: (emoji) => react(r.message.id, emoji), onReply: () => startReply(r.message), onOpenThread: (e) => openThread(r.message.id, e.currentTarget),
2179
+ moreActions: myMoreButton(r.message), picking: view.picking === r.message.id,
2180
+ onPickingChange: (which, open) => { if (which === "bar") view.picking = open ? r.message.id : null; } })));
2181
+ ```
2182
+
2183
+ Strings are TEXT (a body `"<img onerror=…>"` shows those characters); a slot that takes a node (`avatar`, `badges`,
2184
+ `attachments`, `extra`, `receipt`, `moreActions`, `editor`, a rich `time` or `body`) takes a DOM node as given. Callbacks are
2185
+ click listeners and get what React's `onClick` gets (the event; `onReact` the emoji). The behaviour is the components': the
2186
+ action bar is a toolbar (arrows, Home / End), "More reactions" opens the package's picker under the body and the reaction
2187
+ row's "Add reaction" one under the row (search, this browser's "Frequently used" under the React picker's own storage key,
2188
+ arrows, Enter picks the first match, Escape closes and gives focus back), a chip's click remembers its emoji. A row drawn
2189
+ with `picking` takes no focus: after a redraw the page puts focus back, as it does for anything it redraws.
2190
+
2191
+ Not built here: the screen's shell (`TeamChat`, `ChannelRail`, `ChatHeader`, `MessageList`, `Composer`, `ThreadPanel`,
2192
+ `PeoplePanel`) is markup a page writes once (the blocks above), with the behaviour listed just above.
2193
+
2194
+ The script carries two kinds of copy, both held by `team-chat-plain-data.test.ts`: the icons' drawing (icons.tsx) and the
2195
+ emoji set (reactions-data.ts) as a generated block (`UPDATE_PLAIN_TEAM_CHAT=1` on that test writes it), and the labels, the
2196
+ avatar's initials and tone, the reaction helpers and `teamChatRows` in ES5, called with the TypeScript's inputs and held to
2197
+ its answers.
2198
+
2104
2199
  ## Action card (0.28.0): an assistant proposes, a person applies
2105
2200
 
2106
2201
  Chris 08/10/2026: the Feedback Assistant lists likely duplicates and merges them, and carries out status, owner, label
@@ -2405,6 +2500,7 @@ something the base cannot express, add a token or a prop here, and every surface
2405
2500
  | `packages/ui/src/editor-plain.js` | 0.14.0: `gembossUI.initEditorFrame()`, the frame's behaviour for plain HTML; 0.17.0: `gembossUI.initEditorPanel()`, the settings panel's. Load after `kit-plain.js`. |
2406
2501
  | `packages/ui/src/editor-layers-plain.js` | 0.22.0: `gembossUI.initEditorLayers()`, the layers', the outline's and the drawers' behaviour for plain HTML. Load after `kit-plain.js`. |
2407
2502
  | `packages/ui/src/service-switcher-plain.js` | 0.36.0: `gembossUI.initServiceSwitcher()`, the ServiceSwitcher drawn and driven for plain HTML (`@gemboss/ui/service-switcher-plain.js`). After `kit-plain.js` when the page has it; works alone. See "ServiceSwitcher". |
2503
+ | `packages/ui/src/team-chat-plain.js` | 20/10/2026: `gembossUI.teamChat`, builders that return the team chat's rows (messages, day separators, "New messages", jump, receipt, rail rows, people rows, reactions and the picker) with the components' markup, for plain HTML (`@gemboss/ui/team-chat-plain.js`). After `kit-plain.js` when the page has it; works alone. See "The team chat layer". |
2408
2504
  | `catalog/editor.html` | 0.14.0: the frame rendered from the components and running (`packages/ui/scripts/build-catalog-editor.mjs`), linked from `catalog/index.html`. |
2409
2505
  | `packages/ui/src/editor.css` | 0.9.0: the editors (frame, top bar, preview, Configure dock, inspector and controls, Layers, settings drawer, page picker, menus). A separate entry, NOT inside `gemboss-ui.css`; the admin imports it from the editor components, never from a layout. See "Editor CSS" above. |
2410
2506
  | `packages/ui/src/chat.css`, `chat-composer.css`, `assistant.css`, `auth.css`, `app-shell.css` | the chat body, the composer, the assistant frame, the sign-in screen, the topbar slots + base text + the page width tiers (`ui-page`, 0.8.1). All inside `gemboss-ui.css`; the admin @imports `chat.css` and `chat-composer.css` itself. |
@@ -8,7 +8,7 @@
8
8
  .cat-code summary{padding:10px 16px;font-size:13px;cursor:pointer;color:var(--gemboss-text-muted);border-top:1px solid var(--gemboss-divider);min-height:24px}
9
9
  .cat-code pre,.cat-api{margin:0;padding:12px 16px;overflow:auto;background:#0f1012;color:#e8e8e6;font-size:12px;line-height:1.5;border-radius:0}
10
10
  .cat-api{border-radius:12px;margin:0 0 16px}</style></head><body><div class="cat">
11
- <h1>@gemboss/ui 0.40.0 · Editor</h1>
11
+ <h1>@gemboss/ui 0.42.0 · Editor</h1>
12
12
  <p>Khung của mọi editor: <code>EditorFrame</code> (cột trái · khe kéo · preview · cột phải dock trên mép phải preview) và <code>EditorTopbar</code> (← · tiêu đề · cụm giữa · cụm phải · dòng trạng thái). Là đúng khung của theme / page / section editor trong admin. Gói chỉ vẽ KHUNG; chat, Configure, canvas, page picker, menu, Publish là của editor, đi vào bằng slot. Trang HTML thuần nạp <code>editor.css</code> + <code>editor-plain.js</code> rồi gọi <code>gembossUI.initEditorFrame()</code>: kéo khe (chuột, chạm, phím mũi tên / Home / End), đổi thiết bị, mở ⋯ và Publish ▾, ẩn cột trái, Chat | Preview trên điện thoại. <a href="index.html">← Catalog</a></p>
13
13
  <h2>React</h2><pre class="cat-api"><code>import &quot;@gemboss/ui/editor.css&quot;;
14
14
  import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs, EditorSaveState, DeviceToggle } from &quot;@gemboss/ui/editor&quot;;
@@ -319,7 +319,7 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
319
319
  &lt;Field label=&quot;Padding&quot;&gt;&lt;EdgeBox label=&quot;Padding&quot; values={pad} onChange={(side, raw) =&gt; …} onCommit={save} /&gt;&lt;/Field&gt;
320
320
  &lt;Field label=&quot;Image&quot; htmlFor=&quot;img&quot;&gt;&lt;ImageControl id=&quot;img&quot; value={url} onChange={setUrl} /&gt;&lt;/Field&gt;
321
321
  &lt;/InspectorGroup&gt;</code></pre>
322
- <figure class="cat-demo"><figcaption>1280 (chuột): cột Configure 360px, đủ control, nhóm Motion đang gập</figcaption><div class="cat-wide"><iframe title="1280 (chuột): cột Configure 360px, đủ control, nhóm Motion đang gập" style="width:1280px;height:1120px" srcdoc="&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../gemboss-ui.css&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../src/editor.css&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;&lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ec-dock-body&quot; style=&quot;padding:0&quot;&gt;&lt;aside class=&quot;gemboss-ei gemboss-ei--docked&quot; role=&quot;region&quot; aria-label=&quot;Settings — Hero&quot;&gt;&lt;header class=&quot;gemboss-ei-head&quot;&gt;&lt;span class=&quot;gemboss-ei-title&quot;&gt;Hero&lt;small&gt;hero-banner.default.v1&lt;/small&gt;&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Duplicate section&quot; aria-label=&quot;Duplicate section&quot;&gt;⧉&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Restore this section to its previous version&quot; aria-label=&quot;Restore this section&quot;&gt;↺&lt;/button&gt;&lt;/header&gt;&lt;div class=&quot;gemboss-ei-tabs&quot; role=&quot;tablist&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;content&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Content&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;design&quot; class=&quot;gemboss-ei-tab on&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;Design&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;advanced&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Advanced&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-body&quot;&gt;&lt;div class=&quot;gemboss-ei-pane&quot;&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Layout&lt;small class=&quot;gemboss-ei-gh-note&quot;&gt;· all screens&lt;/small&gt;&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Content width&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Content width&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;full&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Full&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;contained&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;Contained&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;narrow&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Narrow&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Columns&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Columns&quot; aria-describedby=&quot;:R18u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Columns&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;2&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;2&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;3&quot; disabled=&quot;&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;3&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;4&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;4&lt;/button&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R18u:&quot;&gt;Disabled while a change is applied.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Spacing&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Padding&lt;/label&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding top&quot; value=&quot;24&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding bottom&quot; value=&quot;24&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Margin&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Margin&quot; aria-describedby=&quot;:R19e:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin top&quot; value=&quot;&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin bottom&quot; value=&quot;&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19e:&quot;&gt;Empty edges follow desktop.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Color&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-bg&quot;&gt;Background&lt;/label&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label for=&quot;cat-ov&quot;&gt;Overlay&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch picks 6-digit hex colors only.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;&lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;&lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch picks 6-digit hex colors only.&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-op&quot;&gt;Opacity&lt;span class=&quot;gemboss-ei-rangeval&quot; data-suffix=&quot;%&quot;&gt;80%&lt;/span&gt;&lt;/label&gt;&lt;input id=&quot;cat-op&quot; type=&quot;range&quot; class=&quot;gemboss-ei-range&quot; min=&quot;0&quot; max=&quot;100&quot; step=&quot;1&quot; value=&quot;80&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Media&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-img&quot;&gt;Image&lt;/label&gt;&lt;div class=&quot;gemboss-ei-img&quot;&gt;&lt;div class=&quot;gemboss-ei-img-thumb&quot; aria-hidden=&quot;true&quot;&gt;—&lt;/div&gt;&lt;div class=&quot;gemboss-ei-img-ctl&quot;&gt;&lt;input id=&quot;cat-img&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Paste image URL…&quot; value=&quot;&quot;/&gt;&lt;div class=&quot;gemboss-ei-img-actions&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; aria-expanded=&quot;false&quot;&gt;Library&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; data-gb-image-clear&gt;Clear&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;closed&quot; aria-expanded=&quot;false&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▸&lt;/span&gt;Motion&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Reveal&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Reveal&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;none&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;None&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;fade&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Fade&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;/div&gt;&lt;script src=&quot;../src/kit-plain.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;../src/editor-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorFrame()&lt;/script&gt;&lt;script&gt;gembossUI.initEditorPanel()&lt;/script&gt;&lt;script src=&quot;../src/editor-layers-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorLayers()&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;"></iframe></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;
322
+ <figure class="cat-demo"><figcaption>1280 (chuột): cột Configure 360px, đủ control, nhóm Motion đang gập</figcaption><div class="cat-wide"><iframe title="1280 (chuột): cột Configure 360px, đủ control, nhóm Motion đang gập" style="width:1280px;height:1120px" srcdoc="&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../gemboss-ui.css&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../src/editor.css&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;&lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ec-dock-body&quot; style=&quot;padding:0&quot;&gt;&lt;aside class=&quot;gemboss-ei gemboss-ei--docked&quot; role=&quot;region&quot; aria-label=&quot;Settings — Hero&quot;&gt;&lt;header class=&quot;gemboss-ei-head&quot;&gt;&lt;span class=&quot;gemboss-ei-title&quot;&gt;Hero&lt;small&gt;hero-banner.default.v1&lt;/small&gt;&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Duplicate section&quot; aria-label=&quot;Duplicate section&quot;&gt;⧉&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Restore this section to its previous version&quot; aria-label=&quot;Restore this section&quot;&gt;↺&lt;/button&gt;&lt;/header&gt;&lt;div class=&quot;gemboss-ei-tabs&quot; role=&quot;tablist&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;content&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Content&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;design&quot; class=&quot;gemboss-ei-tab on&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;Design&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;advanced&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Advanced&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-body&quot;&gt;&lt;div class=&quot;gemboss-ei-pane&quot;&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Layout&lt;small class=&quot;gemboss-ei-gh-note&quot;&gt;· all screens&lt;/small&gt;&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Content width&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Content width&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;full&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Full&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;contained&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;Contained&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;narrow&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Narrow&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Columns&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Columns&quot; aria-describedby=&quot;:R18u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Columns&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;2&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;2&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;3&quot; disabled=&quot;&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;3&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;4&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;4&lt;/button&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R18u:&quot;&gt;Disabled while a change is applied.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Spacing&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Padding&lt;/label&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding top&quot; value=&quot;24&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding bottom&quot; value=&quot;24&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Margin&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Margin&quot; aria-describedby=&quot;:R19e:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin top&quot; value=&quot;&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin bottom&quot; value=&quot;&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19e:&quot;&gt;Empty edges follow desktop.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Color&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-bg&quot;&gt;Background&lt;/label&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input class=&quot;gemboss-field gemboss-ei-inp&quot; data-alpha=&quot;&quot; aria-label=&quot;Background opacity&quot; inputMode=&quot;numeric&quot; style=&quot;flex:0 0 64px&quot; value=&quot;100%&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label for=&quot;cat-ov&quot;&gt;Overlay&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;&lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;&lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-op&quot;&gt;Opacity&lt;span class=&quot;gemboss-ei-rangeval&quot; data-suffix=&quot;%&quot;&gt;80%&lt;/span&gt;&lt;/label&gt;&lt;input id=&quot;cat-op&quot; type=&quot;range&quot; class=&quot;gemboss-ei-range&quot; min=&quot;0&quot; max=&quot;100&quot; step=&quot;1&quot; value=&quot;80&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Media&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-img&quot;&gt;Image&lt;/label&gt;&lt;div class=&quot;gemboss-ei-img&quot;&gt;&lt;div class=&quot;gemboss-ei-img-thumb&quot; aria-hidden=&quot;true&quot;&gt;—&lt;/div&gt;&lt;div class=&quot;gemboss-ei-img-ctl&quot;&gt;&lt;input id=&quot;cat-img&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Paste image URL…&quot; value=&quot;&quot;/&gt;&lt;div class=&quot;gemboss-ei-img-actions&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; aria-expanded=&quot;false&quot;&gt;Library&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; data-gb-image-clear&gt;Clear&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;closed&quot; aria-expanded=&quot;false&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▸&lt;/span&gt;Motion&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Reveal&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Reveal&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;none&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;None&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;fade&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Fade&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;/div&gt;&lt;script src=&quot;../src/kit-plain.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;../src/editor-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorFrame()&lt;/script&gt;&lt;script&gt;gembossUI.initEditorPanel()&lt;/script&gt;&lt;script src=&quot;../src/editor-layers-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorLayers()&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;"></iframe></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;
323
323
  &lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;
324
324
  &lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;
325
325
  &lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;
@@ -422,6 +422,7 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
422
422
  &lt;div class=&quot;gemboss-ei-color&quot;&gt;
423
423
  &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;
424
424
  &lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;
425
+ &lt;input class=&quot;gemboss-field gemboss-ei-inp&quot; data-alpha=&quot;&quot; aria-label=&quot;Background opacity&quot; inputMode=&quot;numeric&quot; style=&quot;flex:0 0 64px&quot; value=&quot;100%&quot;/&gt;
425
426
  &lt;/div&gt;
426
427
  &lt;/div&gt;
427
428
  &lt;div class=&quot;gemboss-ei-fld&quot;&gt;
@@ -430,9 +431,9 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
430
431
  &lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;
431
432
  &lt;/div&gt;
432
433
  &lt;div class=&quot;gemboss-ei-color&quot;&gt;
433
- &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch picks 6-digit hex colors only.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;
434
+ &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;
434
435
  &lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;
435
- &lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch picks 6-digit hex colors only.&lt;/p&gt;
436
+ &lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&lt;/p&gt;
436
437
  &lt;/div&gt;
437
438
  &lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;
438
439
  &lt;/div&gt;
@@ -475,7 +476,7 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
475
476
  &lt;/aside&gt;
476
477
  &lt;/div&gt;
477
478
  &lt;/div&gt;</code></pre></details></figure>
478
- <figure class="cat-demo"><figcaption>390 (điện thoại): ô nhập 16px, control 44px</figcaption><div class="cat-wide"><iframe title="390 (điện thoại): ô nhập 16px, control 44px" style="width:390px;height:1240px" srcdoc="&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../gemboss-ui.css&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../src/editor.css&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;&lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ec-dock-body&quot; style=&quot;padding:0&quot;&gt;&lt;aside class=&quot;gemboss-ei gemboss-ei--docked&quot; role=&quot;region&quot; aria-label=&quot;Settings — Hero&quot;&gt;&lt;header class=&quot;gemboss-ei-head&quot;&gt;&lt;span class=&quot;gemboss-ei-title&quot;&gt;Hero&lt;small&gt;hero-banner.default.v1&lt;/small&gt;&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Duplicate section&quot; aria-label=&quot;Duplicate section&quot;&gt;⧉&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Restore this section to its previous version&quot; aria-label=&quot;Restore this section&quot;&gt;↺&lt;/button&gt;&lt;/header&gt;&lt;div class=&quot;gemboss-ei-tabs&quot; role=&quot;tablist&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;content&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Content&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;design&quot; class=&quot;gemboss-ei-tab on&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;Design&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;advanced&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Advanced&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-body&quot;&gt;&lt;div class=&quot;gemboss-ei-pane&quot;&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Layout&lt;small class=&quot;gemboss-ei-gh-note&quot;&gt;· all screens&lt;/small&gt;&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Content width&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Content width&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;full&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Full&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;contained&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;Contained&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;narrow&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Narrow&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Columns&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Columns&quot; aria-describedby=&quot;:R18u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Columns&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;2&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;2&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;3&quot; disabled=&quot;&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;3&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;4&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;4&lt;/button&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R18u:&quot;&gt;Disabled while a change is applied.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Spacing&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Padding&lt;/label&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding top&quot; value=&quot;24&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding bottom&quot; value=&quot;24&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Margin&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Margin&quot; aria-describedby=&quot;:R19e:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin top&quot; value=&quot;&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin bottom&quot; value=&quot;&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19e:&quot;&gt;Empty edges follow desktop.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Color&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-bg&quot;&gt;Background&lt;/label&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label for=&quot;cat-ov&quot;&gt;Overlay&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch picks 6-digit hex colors only.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;&lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;&lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch picks 6-digit hex colors only.&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-op&quot;&gt;Opacity&lt;span class=&quot;gemboss-ei-rangeval&quot; data-suffix=&quot;%&quot;&gt;80%&lt;/span&gt;&lt;/label&gt;&lt;input id=&quot;cat-op&quot; type=&quot;range&quot; class=&quot;gemboss-ei-range&quot; min=&quot;0&quot; max=&quot;100&quot; step=&quot;1&quot; value=&quot;80&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Media&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-img&quot;&gt;Image&lt;/label&gt;&lt;div class=&quot;gemboss-ei-img&quot;&gt;&lt;div class=&quot;gemboss-ei-img-thumb&quot; aria-hidden=&quot;true&quot;&gt;—&lt;/div&gt;&lt;div class=&quot;gemboss-ei-img-ctl&quot;&gt;&lt;input id=&quot;cat-img&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Paste image URL…&quot; value=&quot;&quot;/&gt;&lt;div class=&quot;gemboss-ei-img-actions&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; aria-expanded=&quot;false&quot;&gt;Library&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; data-gb-image-clear&gt;Clear&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;closed&quot; aria-expanded=&quot;false&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▸&lt;/span&gt;Motion&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Reveal&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Reveal&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;none&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;None&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;fade&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Fade&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;/div&gt;&lt;script src=&quot;../src/kit-plain.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;../src/editor-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorFrame()&lt;/script&gt;&lt;script&gt;gembossUI.initEditorPanel()&lt;/script&gt;&lt;script src=&quot;../src/editor-layers-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorLayers()&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;"></iframe></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;
479
+ <figure class="cat-demo"><figcaption>390 (điện thoại): ô nhập 16px, control 44px</figcaption><div class="cat-wide"><iframe title="390 (điện thoại): ô nhập 16px, control 44px" style="width:390px;height:1240px" srcdoc="&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../gemboss-ui.css&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../src/editor.css&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;&lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ec-dock-body&quot; style=&quot;padding:0&quot;&gt;&lt;aside class=&quot;gemboss-ei gemboss-ei--docked&quot; role=&quot;region&quot; aria-label=&quot;Settings — Hero&quot;&gt;&lt;header class=&quot;gemboss-ei-head&quot;&gt;&lt;span class=&quot;gemboss-ei-title&quot;&gt;Hero&lt;small&gt;hero-banner.default.v1&lt;/small&gt;&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Duplicate section&quot; aria-label=&quot;Duplicate section&quot;&gt;⧉&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-act&quot; title=&quot;Restore this section to its previous version&quot; aria-label=&quot;Restore this section&quot;&gt;↺&lt;/button&gt;&lt;/header&gt;&lt;div class=&quot;gemboss-ei-tabs&quot; role=&quot;tablist&quot;&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;content&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Content&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;design&quot; class=&quot;gemboss-ei-tab on&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;Design&lt;/button&gt;&lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;advanced&quot; class=&quot;gemboss-ei-tab&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Advanced&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-body&quot;&gt;&lt;div class=&quot;gemboss-ei-pane&quot;&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Layout&lt;small class=&quot;gemboss-ei-gh-note&quot;&gt;· all screens&lt;/small&gt;&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Content width&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Content width&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;full&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Full&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;contained&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;Contained&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;narrow&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Narrow&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Columns&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Columns&quot; aria-describedby=&quot;:R18u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Columns&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;2&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;2&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;3&quot; disabled=&quot;&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;3&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;4&quot; disabled=&quot;&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;4&lt;/button&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R18u:&quot;&gt;Disabled while a change is applied.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Spacing&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Padding&lt;/label&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding top&quot; value=&quot;24&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding bottom&quot; value=&quot;24&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Padding left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label&gt;Margin&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Margin&quot; aria-describedby=&quot;:R19e:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edgebox&quot;&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin top&quot; value=&quot;&quot;/&gt;&lt;span&gt;T&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin right&quot; value=&quot;&quot;/&gt;&lt;span&gt;R&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;16&quot; aria-label=&quot;Margin bottom&quot; value=&quot;&quot;/&gt;&lt;span&gt;B&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-edge&quot;&gt;&lt;input class=&quot;gemboss-field gemboss-field--narrow gemboss-ei-inp&quot; inputMode=&quot;numeric&quot; placeholder=&quot;0&quot; aria-label=&quot;Margin left&quot; value=&quot;&quot;/&gt;&lt;span&gt;L&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19e:&quot;&gt;Empty edges follow desktop.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Color&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-bg&quot;&gt;Background&lt;/label&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;&lt;input class=&quot;gemboss-field gemboss-ei-inp&quot; data-alpha=&quot;&quot; aria-label=&quot;Background opacity&quot; inputMode=&quot;numeric&quot; style=&quot;flex:0 0 64px&quot; value=&quot;100%&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;div class=&quot;gemboss-ei-lbl&quot;&gt;&lt;label for=&quot;cat-ov&quot;&gt;Overlay&lt;/label&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-color&quot;&gt;&lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;&lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;&lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-op&quot;&gt;Opacity&lt;span class=&quot;gemboss-ei-rangeval&quot; data-suffix=&quot;%&quot;&gt;80%&lt;/span&gt;&lt;/label&gt;&lt;input id=&quot;cat-op&quot; type=&quot;range&quot; class=&quot;gemboss-ei-range&quot; min=&quot;0&quot; max=&quot;100&quot; step=&quot;1&quot; value=&quot;80&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;open&quot; aria-expanded=&quot;true&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▾&lt;/span&gt;Media&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label for=&quot;cat-img&quot;&gt;Image&lt;/label&gt;&lt;div class=&quot;gemboss-ei-img&quot;&gt;&lt;div class=&quot;gemboss-ei-img-thumb&quot; aria-hidden=&quot;true&quot;&gt;—&lt;/div&gt;&lt;div class=&quot;gemboss-ei-img-ctl&quot;&gt;&lt;input id=&quot;cat-img&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Paste image URL…&quot; value=&quot;&quot;/&gt;&lt;div class=&quot;gemboss-ei-img-actions&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; aria-expanded=&quot;false&quot;&gt;Library&lt;/button&gt;&lt;button type=&quot;button&quot; class=&quot;ui-btn&quot; data-gb-image-clear&gt;Clear&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gemboss-ei-grp&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;gemboss-ei-gh&quot; data-open=&quot;closed&quot; aria-expanded=&quot;false&quot;&gt;&lt;span class=&quot;gemboss-ei-chev&quot; aria-hidden=&quot;true&quot;&gt;▸&lt;/span&gt;Motion&lt;/button&gt;&lt;div class=&quot;gemboss-ei-fld&quot;&gt;&lt;label&gt;Reveal&lt;/label&gt;&lt;div class=&quot;ui-seg ui-seg--fill gemboss-ei-seg&quot; role=&quot;group&quot; aria-label=&quot;Reveal&quot;&gt;&lt;button type=&quot;button&quot; data-value=&quot;none&quot; aria-pressed=&quot;true&quot; class=&quot;is-text active&quot;&gt;None&lt;/button&gt;&lt;button type=&quot;button&quot; data-value=&quot;fade&quot; aria-pressed=&quot;false&quot; class=&quot;is-text&quot;&gt;Fade&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;/div&gt;&lt;script src=&quot;../src/kit-plain.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;../src/editor-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorFrame()&lt;/script&gt;&lt;script&gt;gembossUI.initEditorPanel()&lt;/script&gt;&lt;script src=&quot;../src/editor-layers-plain.js&quot;&gt;&lt;/script&gt;&lt;script&gt;gembossUI.initEditorLayers()&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;"></iframe></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div class=&quot;gemboss-ec&quot; style=&quot;width:360px;height:1040px&quot;&gt;
479
480
  &lt;div class=&quot;gemboss-ec-tabs&quot; role=&quot;tablist&quot; aria-label=&quot;Editor panels&quot;&gt;
480
481
  &lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;configure&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;true&quot;&gt;Settings&lt;/button&gt;
481
482
  &lt;button type=&quot;button&quot; role=&quot;tab&quot; data-value=&quot;chat&quot; class=&quot;gemboss-ec-tab&quot; aria-selected=&quot;false&quot;&gt;Chat&lt;/button&gt;
@@ -578,6 +579,7 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
578
579
  &lt;div class=&quot;gemboss-ei-color&quot;&gt;
579
580
  &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Background swatch&quot; value=&quot;#f4efe6&quot;/&gt;
580
581
  &lt;input id=&quot;cat-bg&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;#f4efe6&quot;/&gt;
582
+ &lt;input class=&quot;gemboss-field gemboss-ei-inp&quot; data-alpha=&quot;&quot; aria-label=&quot;Background opacity&quot; inputMode=&quot;numeric&quot; style=&quot;flex:0 0 64px&quot; value=&quot;100%&quot;/&gt;
581
583
  &lt;/div&gt;
582
584
  &lt;/div&gt;
583
585
  &lt;div class=&quot;gemboss-ei-fld&quot;&gt;
@@ -586,9 +588,9 @@ import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs
586
588
  &lt;button type=&quot;button&quot; class=&quot;gemboss-ei-help&quot; aria-label=&quot;About Overlay&quot; aria-describedby=&quot;:R19u:&quot; aria-expanded=&quot;false&quot;&gt;?&lt;/button&gt;
587
589
  &lt;/div&gt;
588
590
  &lt;div class=&quot;gemboss-ei-color&quot;&gt;
589
- &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch picks 6-digit hex colors only.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;
591
+ &lt;input type=&quot;color&quot; class=&quot;gemboss-ei-swatch&quot; aria-label=&quot;Overlay swatch&quot; disabled=&quot;&quot; title=&quot;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&quot; aria-describedby=&quot;:Rb9u:&quot; value=&quot;#000000&quot;/&gt;
590
592
  &lt;input id=&quot;cat-ov&quot; class=&quot;gemboss-field gemboss-ei-inp&quot; placeholder=&quot;Not set&quot; value=&quot;linear-gradient(90deg,#000,#0000)&quot;/&gt;
591
- &lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch picks 6-digit hex colors only.&lt;/p&gt;
593
+ &lt;p id=&quot;:Rb9u:&quot; class=&quot;gemboss-ei-color-why&quot;&gt;Kept as written: the swatch shows one color (hex, rgb, hsl or oklch), not a gradient or a name.&lt;/p&gt;
592
594
  &lt;/div&gt;
593
595
  &lt;p class=&quot;gemboss-ei-hint gemboss-ei-help-text&quot; id=&quot;:R19u:&quot;&gt;A gradient: the swatch cannot show it, so it is off.&lt;/p&gt;
594
596
  &lt;/div&gt;