@gemboss/ui 0.4.0 → 0.4.2

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/README.md CHANGED
@@ -202,6 +202,25 @@ The surface owns where the seam sits and what it does. Five rules, each paid for
202
202
  React surfaces: `useResizableChatPanel` in the admin is the reference. Others write the same markup and
203
203
  the five rules by hand; the catalog's "Thanh kéo giữa hai cột" shows the markup.
204
204
 
205
+ ## The assistant launcher (0.4.2)
206
+
207
+ The top-right corner of the topbar is the ACCOUNT (`AccountMenu`). The button that opens a surface's AI assistant floats
208
+ bottom-right instead (Chris, 02/10/2026): partner-radar had it top-right, and on a phone it became a ✦ circle exactly where
209
+ content-radar shows the account chip.
210
+
211
+ ```tsx
212
+ import { AssistantLauncher } from "@gemboss/ui";
213
+
214
+ <AssistantLauncher label="Partner Assistant" shortcut="⌘J"
215
+ hidden={dock.presentation !== "hidden"} onClick={() => dock.reopen()} />
216
+ ```
217
+
218
+ - No provider and no state: pass `hidden` while your assistant is open (it would sit under the dock).
219
+ - 44px floor everywhere; label + shortcut on wide screens, the `sparkle` icon alone at ≤760px (the label stays the
220
+ accessible name). Safe-area insets keep it off the iPhone home indicator. z-index 280: under the dock and the topbar,
221
+ over page content.
222
+ - The shortcut is a hint only: the surface owns the key binding.
223
+
205
224
  ## The topbar kit: lockup, account, icons
206
225
 
207
226
  What goes INTO the frame, so a surface does not draw its own (28/09/2026: GemFactory's rail icons came
@@ -227,7 +246,7 @@ import { AppShell, BrandLockup, AccountMenu, AccountMenuItem, Icon, RailItem } f
227
246
  - `AccountMenu`: the admin's 32px initials chip and popover (same CSS). A `<details>`, so it opens
228
247
  without JavaScript on a page that never hydrates; with React it also closes on an outside click and
229
248
  on Escape. `AccountMenuItem` is a link (`href`), a POST form (`formAction`), or a button.
230
- - `Icon`: the GemBoss set, 38 icons on a 20px grid with 1.5px strokes, drawn to sit next to Polaris.
249
+ - `Icon`: the GemBoss set, 39 icons on a 20px grid with 1.5px strokes, drawn to sit next to Polaris.
231
250
  `ICON_NAMES` lists them. Internal tools cannot use `@shopify/polaris-icons`: its licence only covers
232
251
  applications that integrate with Shopify. Draw a missing one HERE, not in the surface: every rail
233
252
  icon must keep `fill="none"` on its inner `<g>`, because `.gnav-ico svg { fill: currentColor }`
@@ -240,7 +259,7 @@ import { AppShell, BrandLockup, AccountMenu, AccountMenuItem, Icon, RailItem } f
240
259
 
241
260
  ## Report pages (0.4.0)
242
261
 
243
- Plain CSS in `kit-plain.css` for a numbers page written by hand (first user: gemnews `/admin`, 03/10/2026). The
262
+ Plain CSS in `kit-plain.css` for a numbers page written by hand (first user: gemnews `/admin`, 03/10/2026; that page moved to GemCommunity the same day, so gemnews no longer takes the package). The
244
263
  surface computes every number and ratio; the kit only draws. Markup for each is in the catalog's "Báo cáo" section.
245
264
 
246
265
  - `ui-metrics--grid` + `ui-metric--lg` + `ui-metric__foot`: KPI tiles in an even grid (never 3 + 1 orphan), label on
@@ -27,7 +27,7 @@ body{margin:0;background:var(--gemboss-app-bg,#f1f1f1);color:var(--gemboss-text)
27
27
  @media (max-width:760px){.cat{grid-template-columns:1fr;padding:16px}.cat-nav{position:static;flex-direction:row;flex-wrap:wrap}}
28
28
  </style></head><body>
29
29
  <div class="cat"><nav class="cat-nav" aria-label="Mục"><a href="#tokens">Token</a><a href="#buttons">Nút</a><a href="#fields">Ô nhập</a><a href="#choice">Tab, nhóm nút, thẻ</a><a href="#surfaces">Thẻ, số liệu, bảng, trạng thái trống</a><a href="#report">Báo cáo</a><a href="#resizer">Thanh kéo giữa hai cột</a><a href="#modal">Hộp thoại, toast, menu (JS thuần)</a><a href="#shell">Khung app</a><a href="#auth">Đăng nhập</a><a href="#chat">Thân chat</a><a href="#assistant">Trợ lý: cột phiên</a><a href="#icons">Icon</a></nav>
30
- <main><header class="cat-head"><h1>@gemboss/ui 0.4.0</h1><p>Ngôn ngữ thiết kế chung của các công cụ GemBoss. Markup dưới mỗi ví dụ là đúng thứ package render ra; bề mặt không dùng React (HTML tĩnh, Python) chép markup này và nạp <code>gemboss-ui.css</code>. Dựng từ gemboss <code>e86d83befc81</code>.</p></header>
30
+ <main><header class="cat-head"><h1>@gemboss/ui 0.4.2</h1><p>Ngôn ngữ thiết kế chung của các công cụ GemBoss. Markup dưới mỗi ví dụ là đúng thứ package render ra; bề mặt không dùng React (HTML tĩnh, Python) chép markup này và nạp <code>gemboss-ui.css</code>. Dựng từ gemboss <code>1ca4f9ec8573</code>.</p></header>
31
31
  <section id="tokens"><h2>Token</h2><p>Đổi giao diện một bề mặt bằng cách đặt lại token, không viết đè class. Tên và giá trị đọc thẳng từ gemboss-ui.css.</p><div class="cat-swatches"><div class="cat-swatch"><i style="background:var(--gemboss-primary)"></i><code>--gemboss-primary</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-primary-dark)"></i><code>--gemboss-primary-dark</code><span>#000000</span></div><div class="cat-swatch"><i style="background:var(--gemboss-primary-soft)"></i><code>--gemboss-primary-soft</code><span>#f2f3f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent)"></i><code>--gemboss-accent</code><span>#5661f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent-strong)"></i><code>--gemboss-accent-strong</code><span>#3a44de</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent-soft)"></i><code>--gemboss-accent-soft</code><span>#eef0fe</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text-strong)"></i><code>--gemboss-text-strong</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text)"></i><code>--gemboss-text</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text-muted)"></i><code>--gemboss-text-muted</code><span>#686b71</span></div><div class="cat-swatch"><i style="background:var(--gemboss-surface)"></i><code>--gemboss-surface</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-canvas)"></i><code>--gemboss-canvas</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-preview-canvas)"></i><code>--gemboss-preview-canvas</code><span>#eceef1</span></div><div class="cat-swatch"><i style="background:var(--gemboss-rail-bg)"></i><code>--gemboss-rail-bg</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-panel-bg)"></i><code>--gemboss-panel-bg</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-divider)"></i><code>--gemboss-divider</code><span>#e5e7ea</span></div><div class="cat-swatch"><i style="background:var(--gemboss-divider-soft)"></i><code>--gemboss-divider-soft</code><span>#edeff2</span></div><div class="cat-swatch"><i style="background:var(--gemboss-hover)"></i><code>--gemboss-hover</code><span>#eceef2</span></div><div class="cat-swatch"><i style="background:var(--gemboss-active-bg)"></i><code>--gemboss-active-bg</code><span>#f0f1f4</span></div><div class="cat-swatch"><i style="background:var(--gemboss-active-fg)"></i><code>--gemboss-active-fg</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger)"></i><code>--gemboss-danger</code><span>#d72c0d</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-strong)"></i><code>--gemboss-danger-strong</code><span>#b42318</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-soft)"></i><code>--gemboss-danger-soft</code><span>#fff0e9</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-border)"></i><code>--gemboss-danger-border</code><span>#f5c9bc</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success)"></i><code>--gemboss-success</code><span>#007f5f</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-strong)"></i><code>--gemboss-success-strong</code><span>#0a6a4c</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-soft)"></i><code>--gemboss-success-soft</code><span>#e3f1df</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-border)"></i><code>--gemboss-success-border</code><span>#b7dfcd</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning)"></i><code>--gemboss-warning</code><span>#9a6700</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning-soft)"></i><code>--gemboss-warning-soft</code><span>#fff8e0</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning-border)"></i><code>--gemboss-warning-border</code><span>#f5d569</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-bg)"></i><code>--gemboss-dark-bg</code><span>#0a0a0c</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-rail)"></i><code>--gemboss-dark-rail</code><span>#0e0e11</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-surface)"></i><code>--gemboss-dark-surface</code><span>#16161a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-surface-2)"></i><code>--gemboss-dark-surface-2</code><span>#1e1e24</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-divider)"></i><code>--gemboss-dark-divider</code><span>#2a2a31</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-text)"></i><code>--gemboss-dark-text</code><span>#ededf0</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-muted)"></i><code>--gemboss-dark-muted</code><span>#9a9aa4</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-bg)"></i><code>--gemboss-field-bg</code><span>#fdfdfd</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-bg-hover)"></i><code>--gemboss-field-bg-hover</code><span>#fafafa</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-ink)"></i><code>--gemboss-field-ink</code><span>#303030</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-placeholder)"></i><code>--gemboss-field-placeholder</code><span>#616161</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line)"></i><code>--gemboss-field-line</code><span>#8a8a8a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line-hover)"></i><code>--gemboss-field-line-hover</code><span>#616161</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line-active)"></i><code>--gemboss-field-line-active</code><span>#1a1a1a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-ink)"></i><code>--gemboss-chip-ink</code><span>#303633</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-line)"></i><code>--gemboss-chip-line</code><span>#cfd6ce</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-line-hover)"></i><code>--gemboss-chip-line-hover</code><span>#aab4ad</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-bg-hover)"></i><code>--gemboss-chip-bg-hover</code><span>#f6f7f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-on-primary)"></i><code>--gemboss-on-primary</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-app-bg)"></i><code>--gemboss-app-bg</code><span>#ffffff</span></div></div><table class="ui-table cat-scale"><thead><tr><th>Token</th><th>Giá trị</th><th>Mẫu</th></tr></thead><tbody><tr><td><code>--gemboss-fs-micro</code></td><td>11px</td><td style="font-size:var(--gemboss-fs-micro)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-caption</code></td><td>12px</td><td style="font-size:var(--gemboss-fs-caption)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-body</code></td><td>14px</td><td style="font-size:var(--gemboss-fs-body)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-body-lg</code></td><td>16px</td><td style="font-size:var(--gemboss-fs-body-lg)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h3</code></td><td>16px</td><td style="font-size:var(--gemboss-fs-h3)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h2</code></td><td>20px</td><td style="font-size:var(--gemboss-fs-h2)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h1</code></td><td>24px</td><td style="font-size:var(--gemboss-fs-h1)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-display</code></td><td>30px</td><td style="font-size:var(--gemboss-fs-display)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-radius-xs</code></td><td>4px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-xs)"></i></td></tr><tr><td><code>--gemboss-radius-sm</code></td><td>6px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-sm)"></i></td></tr><tr><td><code>--gemboss-radius-md</code></td><td>8px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-md)"></i></td></tr><tr><td><code>--gemboss-radius-lg</code></td><td>12px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-lg)"></i></td></tr><tr><td><code>--gemboss-radius-xl</code></td><td>16px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-xl)"></i></td></tr><tr><td><code>--gemboss-radius-2xl</code></td><td>20px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-2xl)"></i></td></tr><tr><td><code>--gemboss-radius-full</code></td><td>999px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-full)"></i></td></tr><tr><td><code>--gemboss-shadow-resting</code></td><td class="cat-small">0 1px 2px rgba(31, 30, 29, 0.04), 0 2px 6px rgba(31, 30, 29, 0.06)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-resting);border:0"></i></td></tr><tr><td><code>--gemboss-shadow-raised</code></td><td class="cat-small">0 4px 16px rgba(31, 30, 29, 0.10)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-raised);border:0"></i></td></tr><tr><td><code>--gemboss-shadow-overlay</code></td><td class="cat-small">0 16px 48px rgba(31, 30, 29, 0.18)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-overlay);border:0"></i></td></tr></tbody></table></section>
32
32
  <section id="buttons"><h2>Nút</h2><p>Một lớp <code>ui-btn</code>, ba biến thể, một cỡ nhỏ. Dùng được trên <code>&lt;button&gt;</code> lẫn <code>&lt;a&gt;</code> (căn giữa sẵn).</p><figure class="cat-demo"><figcaption>Mặc định · chính · ghost · nhỏ · tắt</figcaption><div class="cat-live"><div class="cat-row"><button type="button" class="ui-btn">Lưu nháp</button><button type="button" class="ui-btn ui-btn--primary">Xuất bản</button><button type="button" class="ui-btn ui-btn--ghost">Huỷ</button><button type="button" class="ui-btn ui-btn--sm">Nhỏ</button><button type="button" class="ui-btn ui-btn--primary" disabled>Đang lưu…</button><a class="ui-btn" href="#buttons">Link dạng nút</a></div></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div class=&quot;cat-row&quot;&gt;
33
33
  &lt;button type=&quot;button&quot; class=&quot;ui-btn&quot;&gt;Lưu nháp&lt;/button&gt;
@@ -737,7 +737,7 @@ body{margin:0;background:var(--gemboss-app-bg,#f1f1f1);color:var(--gemboss-text)
737
737
  &lt;button type=&quot;submit&quot; aria-label=&quot;Gửi&quot;&gt;↑&lt;/button&gt;
738
738
  &lt;/form&gt;
739
739
  &lt;/div&gt;</code></pre></details></figure></section>
740
- <section id="assistant"><h2>Trợ lý: cột phiên</h2><p><code>SessionRail</code> (React). Khung toàn màn hình / cửa sổ nổi / cột phải cao hết màn (<code>allowSide</code>) / thanh là <code>AssistantHost</code>, cần React vì có trạng thái.</p><figure class="cat-demo"><figcaption>SessionRail</figcaption><div class="cat-live"><div style="height:360px;display:flex"><aside class="gemboss-assistant-rail"><div class="gemboss-assistant-rail-top"><button type="button" class="gemboss-assistant-newchat" title="Phiên mới"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H5.5A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16h9a1.5 1.5 0 0 0 1.5-1.5V9"></path><path d="M14.5 3.5l2 2L10 12H8v-2z"></path></g></svg><span>Phiên mới</span></button><button type="button" class="gemboss-assistant-collapse" aria-label="Collapse sidebar" title="Collapse"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5l-5 5 5 5"></path></g></svg></button></div><div class="gemboss-assistant-search gemboss-field gemboss-field--group"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="5"></circle><path d="M13 13l3.5 3.5"></path></g></svg><input class="gemboss-field__bare" placeholder="Tìm phiên…" aria-label="Search history" value=""/><kbd class="gemboss-assistant-kbd">/</kbd></div><div class="gemboss-assistant-threads"><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Đã ghim</div><div class="gemboss-assistant-thread"><button type="button" class="gemboss-assistant-thread-main" title="So sánh advertorial với listicle"><span class="gemboss-assistant-thread-titlerow"><svg viewBox="0 0 20 20" class="gemboss-assistant-pin-dot" aria-hidden="true" focusable="false"><path d="M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z" fill="currentColor"></path><path d="M10 11v5.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"></path></svg><span class="gemboss-assistant-thread-title">So sánh advertorial với listicle</span></span><span class="gemboss-assistant-thread-meta">23/8/2026</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Hôm nay</div><div class="gemboss-assistant-thread active"><button type="button" class="gemboss-assistant-thread-main" title="Store nào đang dựng loạt landing?"><span class="gemboss-assistant-thread-titlerow"><span class="gemboss-assistant-thread-title">Store nào đang dựng loạt landing?</span></span><span class="gemboss-assistant-thread-meta">3 giờ trước</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Hôm qua</div><div class="gemboss-assistant-thread"><button type="button" class="gemboss-assistant-thread-main" title="Landing điểm cao nhất của corpus"><span class="gemboss-assistant-thread-titlerow"><span class="gemboss-assistant-thread-title">Landing điểm cao nhất của corpus</span></span><span class="gemboss-assistant-thread-meta">1 ngày trước</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div></div></aside></div></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div style=&quot;height:360px;display:flex&quot;&gt;
740
+ <section id="assistant"><h2>Trợ lý: cột phiên</h2><p><code>SessionRail</code> (React). Khung toàn màn hình / cửa sổ nổi / cột phải cao hết màn (<code>allowSide</code>) / thanh là <code>AssistantHost</code>, cần React vì có trạng thái.</p><figure class="cat-demo"><figcaption>SessionRail</figcaption><div class="cat-live"><div style="height:360px;display:flex"><aside class="gemboss-assistant-rail"><div class="gemboss-assistant-rail-top"><button type="button" class="gemboss-assistant-newchat" title="Phiên mới"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H5.5A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16h9a1.5 1.5 0 0 0 1.5-1.5V9"></path><path d="M14.5 3.5l2 2L10 12H8v-2z"></path></g></svg><span>Phiên mới</span></button><button type="button" class="gemboss-assistant-collapse" aria-label="Collapse sidebar" title="Collapse"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5l-5 5 5 5"></path></g></svg></button></div><div class="gemboss-assistant-search gemboss-field gemboss-field--group"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="5"></circle><path d="M13 13l3.5 3.5"></path></g></svg><input class="gemboss-field__bare" placeholder="Tìm phiên…" aria-label="Search history" value=""/><kbd class="gemboss-assistant-kbd">/</kbd></div><div class="gemboss-assistant-threads"><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Đã ghim</div><div class="gemboss-assistant-thread"><button type="button" class="gemboss-assistant-thread-main" title="So sánh advertorial với listicle"><span class="gemboss-assistant-thread-titlerow"><svg viewBox="0 0 20 20" class="gemboss-assistant-pin-dot" aria-hidden="true" focusable="false"><path d="M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z" fill="currentColor"></path><path d="M10 11v5.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"></path></svg><span class="gemboss-assistant-thread-title">So sánh advertorial với listicle</span></span><span class="gemboss-assistant-thread-meta">24/8/2026</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Hôm nay</div><div class="gemboss-assistant-thread active"><button type="button" class="gemboss-assistant-thread-main" title="Store nào đang dựng loạt landing?"><span class="gemboss-assistant-thread-titlerow"><span class="gemboss-assistant-thread-title">Store nào đang dựng loạt landing?</span></span><span class="gemboss-assistant-thread-meta">3 giờ trước</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div><div class="gemboss-assistant-group"><div class="gemboss-assistant-group-label">Hôm qua</div><div class="gemboss-assistant-thread"><button type="button" class="gemboss-assistant-thread-main" title="Landing điểm cao nhất của corpus"><span class="gemboss-assistant-thread-titlerow"><span class="gemboss-assistant-thread-title">Landing điểm cao nhất của corpus</span></span><span class="gemboss-assistant-thread-meta">1 ngày trước</span></button><div class="gemboss-assistant-thread-actions"><button type="button" class="gemboss-assistant-thread-act" aria-label="Options"><svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="10" r=".8"></circle><circle cx="10" cy="10" r=".8"></circle><circle cx="15" cy="10" r=".8"></circle></g></svg></button></div></div></div></div></aside></div></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;div style=&quot;height:360px;display:flex&quot;&gt;
741
741
  &lt;aside class=&quot;gemboss-assistant-rail&quot;&gt;
742
742
  &lt;div class=&quot;gemboss-assistant-rail-top&quot;&gt;
743
743
  &lt;button type=&quot;button&quot; class=&quot;gemboss-assistant-newchat&quot; title=&quot;Phiên mới&quot;&gt;
@@ -786,7 +786,7 @@ body{margin:0;background:var(--gemboss-app-bg,#f1f1f1);color:var(--gemboss-text)
786
786
  &lt;/svg&gt;
787
787
  &lt;span class=&quot;gemboss-assistant-thread-title&quot;&gt;So sánh advertorial với listicle&lt;/span&gt;
788
788
  &lt;/span&gt;
789
- &lt;span class=&quot;gemboss-assistant-thread-meta&quot;&gt;23/8/2026&lt;/span&gt;
789
+ &lt;span class=&quot;gemboss-assistant-thread-meta&quot;&gt;24/8/2026&lt;/span&gt;
790
790
  &lt;/button&gt;
791
791
  &lt;div class=&quot;gemboss-assistant-thread-actions&quot;&gt;
792
792
  &lt;button type=&quot;button&quot; class=&quot;gemboss-assistant-thread-act&quot; aria-label=&quot;Options&quot;&gt;
@@ -857,7 +857,7 @@ body{margin:0;background:var(--gemboss-app-bg,#f1f1f1);color:var(--gemboss-text)
857
857
  &lt;/div&gt;
858
858
  &lt;/aside&gt;
859
859
  &lt;/div&gt;</code></pre></details></figure></section>
860
- <section id="icons"><h2>Icon</h2><p>Bộ icon GemBoss: 40 icon, lưới 20px, nét 1.5. <code>fill="none"</code> nằm trên <code>&lt;g&gt;</code>, không trên <code>&lt;svg&gt;</code>.</p><div class="cat-icons"><div class="gnav-ico cat-icon" title="home"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 9 10 3.5 16.5 9"></path><path d="M5 7.8v8.7h10V7.8"></path><path d="M8.5 16.5v-4h3v4"></path></g></svg><code>home</code></div><div class="gnav-ico cat-icon" title="dashboard"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="6" height="6" rx="1.3"></rect><rect x="11" y="3" width="6" height="6" rx="1.3"></rect><rect x="3" y="11" width="6" height="6" rx="1.3"></rect><rect x="11" y="11" width="6" height="6" rx="1.3"></rect></g></svg><code>dashboard</code></div><div class="gnav-ico cat-icon" title="board"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="4" height="13" rx="1.2"></rect><rect x="8" y="3.5" width="4" height="9" rx="1.2"></rect><rect x="13" y="3.5" width="4" height="6" rx="1.2"></rect></g></svg><code>board</code></div><div class="gnav-ico cat-icon" title="layout"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="3" width="13" height="3.5" rx="1"></rect><rect x="3.5" y="8.25" width="13" height="3.5" rx="1"></rect><rect x="3.5" y="13.5" width="13" height="3.5" rx="1"></rect></g></svg><code>layout</code></div><div class="gnav-ico cat-icon" title="layers"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3 17 6.8 10 10.6 3 6.8z"></path><path d="M3 10.1l7 3.8 7-3.8"></path><path d="M3 13.4l7 3.8 7-3.8"></path></g></svg><code>layers</code></div><div class="gnav-ico cat-icon" title="document"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 2.8h6.8l3.2 3.2v11.2H5z"></path><path d="M11.8 2.8V6H15M7.5 10h5M7.5 13h5"></path></g></svg><code>document</code></div><div class="gnav-ico cat-icon" title="article"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="14" height="13" rx="1.5"></rect><path d="M6 7h8M6 10h8M6 13h5"></path></g></svg><code>article</code></div><div class="gnav-ico cat-icon" title="page"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="3.5" width="15" height="13" rx="2"></rect><path d="M2.5 7.5h15M6 11h8M6 13.5h5"></path></g></svg><code>page</code></div><div class="gnav-ico cat-icon" title="image"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="14" height="13" rx="1.8"></rect><circle cx="7.3" cy="7.8" r="1.3"></circle><path d="M3.5 15l4.2-4.2 3 3 2.2-2.2 3.6 3.6"></path></g></svg><code>image</code></div><div class="gnav-ico cat-icon" title="folder"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.8 5.3c0-.8.6-1.3 1.3-1.3h3.4l1.8 2h6.6c.8 0 1.3.6 1.3 1.3v7.7c0 .8-.6 1.3-1.3 1.3H4.1c-.8 0-1.3-.6-1.3-1.3z"></path></g></svg><code>folder</code></div><div class="gnav-ico cat-icon" title="list"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 5h9M8 10h9M8 15h9"></path><circle cx="4" cy="5" r=".9"></circle><circle cx="4" cy="10" r=".9"></circle><circle cx="4" cy="15" r=".9"></circle></g></svg><code>list</code></div><div class="gnav-ico cat-icon" title="activity"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 10h3l2-5 3 10 2-5h5"></path></g></svg><code>activity</code></div><div class="gnav-ico cat-icon" title="chart"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 16.5h14"></path><rect x="4.5" y="9" width="2.8" height="5.5" rx=".7"></rect><rect x="8.6" y="5" width="2.8" height="9.5" rx=".7"></rect><rect x="12.7" y="11" width="2.8" height="3.5" rx=".7"></rect></g></svg><code>chart</code></div><div class="gnav-ico cat-icon" title="radar"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><circle cx="10" cy="10" r="3.5"></circle><path d="M10 10l5-5"></path></g></svg><code>radar</code></div><div class="gnav-ico cat-icon" title="map"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="14" height="14" rx="2"></rect><path d="M3 7.7h14M3 12.3h14M7.7 3v14M12.3 3v14"></path></g></svg><code>map</code></div><div class="gnav-ico cat-icon" title="globe"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M3 10h14M10 3c2 2 2.8 4.3 2.8 7s-.8 5-2.8 7c-2-2-2.8-4.3-2.8-7s.8-5 2.8-7z"></path></g></svg><code>globe</code></div><div class="gnav-ico cat-icon" title="megaphone"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8v4h3l6 4V4L6 8H3z"></path><path d="M15 7.5a3.5 3.5 0 0 1 0 5"></path></g></svg><code>megaphone</code></div><div class="gnav-ico cat-icon" title="star"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 2.8l2.2 4.5 5 .7-3.6 3.5.9 5-4.5-2.4-4.5 2.4.9-5L2.8 8l5-.7z"></path></g></svg><code>star</code></div><div class="gnav-ico cat-icon" title="eye"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1.8 10S4.7 4.8 10 4.8 18.2 10 18.2 10 15.3 15.2 10 15.2 1.8 10 1.8 10z"></path><circle cx="10" cy="10" r="2.5"></circle></g></svg><code>eye</code></div><div class="gnav-ico cat-icon" title="inbox"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 11l2-7h10l2 7v5H3z"></path><path d="M3 11h4l1 2h4l1-2h4"></path></g></svg><code>inbox</code></div><div class="gnav-ico cat-icon" title="bell"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13.5V9a5 5 0 0 1 10 0v4.5l1.3 1.5H3.7z"></path><path d="M8.3 17.2a1.9 1.9 0 0 0 3.4 0"></path></g></svg><code>bell</code></div><div class="gnav-ico cat-icon" title="chat"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4.5h14v9H8.5L5 16.5v-3H3z"></path></g></svg><code>chat</code></div><div class="gnav-ico cat-icon" title="money"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M12 7.6c-.5-.7-1.2-1-2-1-1.1 0-2 .7-2 1.6 0 2.1 4 1.2 4 3.4 0 .9-.9 1.6-2 1.6-.8 0-1.6-.3-2.1-1M10 5v1.6M10 13.2V15"></path></g></svg><code>money</code></div><div class="gnav-ico cat-icon" title="store"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.2 7.5 4.5 3.5h11l1.3 4"></path><path d="M3.2 7.5c0 1.3 1 2.2 2.3 2.2s2.2-1 2.2-2.2c0 1.3 1 2.2 2.3 2.2s2.3-1 2.3-2.2c0 1.3.9 2.2 2.2 2.2s2.3-.9 2.3-2.2"></path><path d="M4.5 9.5v7h11v-7M8.5 16.5v-3.5h3v3.5"></path></g></svg><code>store</code></div><div class="gnav-ico cat-icon" title="user"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="7" r="3.2"></circle><path d="M3.8 16.5c.8-2.8 3.3-4.5 6.2-4.5s5.4 1.7 6.2 4.5"></path></g></svg><code>user</code></div><div class="gnav-ico cat-icon" title="users"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="7.5" cy="7.3" r="2.8"></circle><path d="M2.5 16.3c.6-2.5 2.5-4 5-4s4.4 1.5 5 4"></path><path d="M12.3 4.8a2.8 2.8 0 0 1 0 5.2M14.3 12.5c1.6.4 2.7 1.7 3.2 3.8"></path></g></svg><code>users</code></div><div class="gnav-ico cat-icon" title="calendar"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4.5" width="14" height="12.5" rx="1.8"></rect><path d="M3 8.5h14M7 3v3M13 3v3"></path></g></svg><code>calendar</code></div><div class="gnav-ico cat-icon" title="clock"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M10 6v4l2.8 1.8"></path></g></svg><code>clock</code></div><div class="gnav-ico cat-icon" title="search"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8.8" cy="8.8" r="5.3"></circle><path d="M12.8 12.8 17 17"></path></g></svg><code>search</code></div><div class="gnav-ico cat-icon" title="link"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8.6 11.4a3 3 0 0 0 4.2 0l2.6-2.6a3 3 0 0 0-4.2-4.2l-1 1"></path><path d="M11.4 8.6a3 3 0 0 0-4.2 0l-2.6 2.6a3 3 0 0 0 4.2 4.2l1-1"></path></g></svg><code>link</code></div><div class="gnav-ico cat-icon" title="sliders"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5h14M3 10h14M3 15h14"></path><circle cx="7" cy="5" r="1.6"></circle><circle cx="13" cy="10" r="1.6"></circle><circle cx="9" cy="15" r="1.6"></circle></g></svg><code>sliders</code></div><div class="gnav-ico cat-icon" title="settings"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15.52 9.08 17.15 9.15 17.15 10.85 15.52 10.92 14.56 13.26 15.66 14.45 14.45 15.66 13.26 14.56 10.92 15.52 10.85 17.15 9.15 17.15 9.08 15.52 6.74 14.56 5.55 15.66 4.34 14.45 5.44 13.26 4.48 10.92 2.85 10.85 2.85 9.15 4.48 9.08 5.44 6.74 4.34 5.55 5.55 4.34 6.74 5.44 9.08 4.48 9.15 2.85 10.85 2.85 10.92 4.48 13.26 5.44 14.45 4.34 15.66 5.55 14.56 6.74Z"></path><circle cx="10" cy="10" r="2.4"></circle></g></svg><code>settings</code></div><div class="gnav-ico cat-icon" title="alert"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3.2 17.3 16H2.7z"></path><path d="M10 8.2v3.6M10 13.9v.1"></path></g></svg><code>alert</code></div><div class="gnav-ico cat-icon" title="info"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M10 9v4.5M10 6.4v.1"></path></g></svg><code>info</code></div><div class="gnav-ico cat-icon" title="check"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5 8 14.5 16 5.5"></path></g></svg><code>check</code></div><div class="gnav-ico cat-icon" title="plus"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 4v12M4 10h12"></path></g></svg><code>plus</code></div><div class="gnav-ico cat-icon" title="close"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l10 10M15 5 5 15"></path></g></svg><code>close</code></div><div class="gnav-ico cat-icon" title="more"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="4.5" cy="10" r="1"></circle><circle cx="10" cy="10" r="1"></circle><circle cx="15.5" cy="10" r="1"></circle></g></svg><code>more</code></div><div class="gnav-ico cat-icon" title="utensils"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3v5a2 2 0 0 0 4 0V3M8 3v14"></path><path d="M15 3c-1.6 1.4-2.5 3.6-2.5 6.5H15V17"></path></g></svg><code>utensils</code></div><div class="gnav-ico cat-icon" title="signOut"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3.5H4v13h4M12.5 6.5 16 10l-3.5 3.5M16 10H8"></path></g></svg><code>signOut</code></div></div><figure class="cat-demo"><figcaption>Một icon (markup)</figcaption><div class="cat-live"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="4" height="13" rx="1.2"></rect><rect x="8" y="3.5" width="4" height="9" rx="1.2"></rect><rect x="13" y="3.5" width="4" height="6" rx="1.2"></rect></g></svg></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;svg viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;
860
+ <section id="icons"><h2>Icon</h2><p>Bộ icon GemBoss: 41 icon, lưới 20px, nét 1.5. <code>fill="none"</code> nằm trên <code>&lt;g&gt;</code>, không trên <code>&lt;svg&gt;</code>.</p><div class="cat-icons"><div class="gnav-ico cat-icon" title="home"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 9 10 3.5 16.5 9"></path><path d="M5 7.8v8.7h10V7.8"></path><path d="M8.5 16.5v-4h3v4"></path></g></svg><code>home</code></div><div class="gnav-ico cat-icon" title="dashboard"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="6" height="6" rx="1.3"></rect><rect x="11" y="3" width="6" height="6" rx="1.3"></rect><rect x="3" y="11" width="6" height="6" rx="1.3"></rect><rect x="11" y="11" width="6" height="6" rx="1.3"></rect></g></svg><code>dashboard</code></div><div class="gnav-ico cat-icon" title="board"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="4" height="13" rx="1.2"></rect><rect x="8" y="3.5" width="4" height="9" rx="1.2"></rect><rect x="13" y="3.5" width="4" height="6" rx="1.2"></rect></g></svg><code>board</code></div><div class="gnav-ico cat-icon" title="layout"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="3" width="13" height="3.5" rx="1"></rect><rect x="3.5" y="8.25" width="13" height="3.5" rx="1"></rect><rect x="3.5" y="13.5" width="13" height="3.5" rx="1"></rect></g></svg><code>layout</code></div><div class="gnav-ico cat-icon" title="layers"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3 17 6.8 10 10.6 3 6.8z"></path><path d="M3 10.1l7 3.8 7-3.8"></path><path d="M3 13.4l7 3.8 7-3.8"></path></g></svg><code>layers</code></div><div class="gnav-ico cat-icon" title="document"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 2.8h6.8l3.2 3.2v11.2H5z"></path><path d="M11.8 2.8V6H15M7.5 10h5M7.5 13h5"></path></g></svg><code>document</code></div><div class="gnav-ico cat-icon" title="article"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="14" height="13" rx="1.5"></rect><path d="M6 7h8M6 10h8M6 13h5"></path></g></svg><code>article</code></div><div class="gnav-ico cat-icon" title="page"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="3.5" width="15" height="13" rx="2"></rect><path d="M2.5 7.5h15M6 11h8M6 13.5h5"></path></g></svg><code>page</code></div><div class="gnav-ico cat-icon" title="image"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="14" height="13" rx="1.8"></rect><circle cx="7.3" cy="7.8" r="1.3"></circle><path d="M3.5 15l4.2-4.2 3 3 2.2-2.2 3.6 3.6"></path></g></svg><code>image</code></div><div class="gnav-ico cat-icon" title="folder"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.8 5.3c0-.8.6-1.3 1.3-1.3h3.4l1.8 2h6.6c.8 0 1.3.6 1.3 1.3v7.7c0 .8-.6 1.3-1.3 1.3H4.1c-.8 0-1.3-.6-1.3-1.3z"></path></g></svg><code>folder</code></div><div class="gnav-ico cat-icon" title="list"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 5h9M8 10h9M8 15h9"></path><circle cx="4" cy="5" r=".9"></circle><circle cx="4" cy="10" r=".9"></circle><circle cx="4" cy="15" r=".9"></circle></g></svg><code>list</code></div><div class="gnav-ico cat-icon" title="activity"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 10h3l2-5 3 10 2-5h5"></path></g></svg><code>activity</code></div><div class="gnav-ico cat-icon" title="chart"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 16.5h14"></path><rect x="4.5" y="9" width="2.8" height="5.5" rx=".7"></rect><rect x="8.6" y="5" width="2.8" height="9.5" rx=".7"></rect><rect x="12.7" y="11" width="2.8" height="3.5" rx=".7"></rect></g></svg><code>chart</code></div><div class="gnav-ico cat-icon" title="radar"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><circle cx="10" cy="10" r="3.5"></circle><path d="M10 10l5-5"></path></g></svg><code>radar</code></div><div class="gnav-ico cat-icon" title="map"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="14" height="14" rx="2"></rect><path d="M3 7.7h14M3 12.3h14M7.7 3v14M12.3 3v14"></path></g></svg><code>map</code></div><div class="gnav-ico cat-icon" title="globe"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M3 10h14M10 3c2 2 2.8 4.3 2.8 7s-.8 5-2.8 7c-2-2-2.8-4.3-2.8-7s.8-5 2.8-7z"></path></g></svg><code>globe</code></div><div class="gnav-ico cat-icon" title="megaphone"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8v4h3l6 4V4L6 8H3z"></path><path d="M15 7.5a3.5 3.5 0 0 1 0 5"></path></g></svg><code>megaphone</code></div><div class="gnav-ico cat-icon" title="star"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 2.8l2.2 4.5 5 .7-3.6 3.5.9 5-4.5-2.4-4.5 2.4.9-5L2.8 8l5-.7z"></path></g></svg><code>star</code></div><div class="gnav-ico cat-icon" title="eye"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1.8 10S4.7 4.8 10 4.8 18.2 10 18.2 10 15.3 15.2 10 15.2 1.8 10 1.8 10z"></path><circle cx="10" cy="10" r="2.5"></circle></g></svg><code>eye</code></div><div class="gnav-ico cat-icon" title="inbox"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 11l2-7h10l2 7v5H3z"></path><path d="M3 11h4l1 2h4l1-2h4"></path></g></svg><code>inbox</code></div><div class="gnav-ico cat-icon" title="bell"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13.5V9a5 5 0 0 1 10 0v4.5l1.3 1.5H3.7z"></path><path d="M8.3 17.2a1.9 1.9 0 0 0 3.4 0"></path></g></svg><code>bell</code></div><div class="gnav-ico cat-icon" title="chat"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4.5h14v9H8.5L5 16.5v-3H3z"></path></g></svg><code>chat</code></div><div class="gnav-ico cat-icon" title="money"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M12 7.6c-.5-.7-1.2-1-2-1-1.1 0-2 .7-2 1.6 0 2.1 4 1.2 4 3.4 0 .9-.9 1.6-2 1.6-.8 0-1.6-.3-2.1-1M10 5v1.6M10 13.2V15"></path></g></svg><code>money</code></div><div class="gnav-ico cat-icon" title="store"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.2 7.5 4.5 3.5h11l1.3 4"></path><path d="M3.2 7.5c0 1.3 1 2.2 2.3 2.2s2.2-1 2.2-2.2c0 1.3 1 2.2 2.3 2.2s2.3-1 2.3-2.2c0 1.3.9 2.2 2.2 2.2s2.3-.9 2.3-2.2"></path><path d="M4.5 9.5v7h11v-7M8.5 16.5v-3.5h3v3.5"></path></g></svg><code>store</code></div><div class="gnav-ico cat-icon" title="user"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="7" r="3.2"></circle><path d="M3.8 16.5c.8-2.8 3.3-4.5 6.2-4.5s5.4 1.7 6.2 4.5"></path></g></svg><code>user</code></div><div class="gnav-ico cat-icon" title="users"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="7.5" cy="7.3" r="2.8"></circle><path d="M2.5 16.3c.6-2.5 2.5-4 5-4s4.4 1.5 5 4"></path><path d="M12.3 4.8a2.8 2.8 0 0 1 0 5.2M14.3 12.5c1.6.4 2.7 1.7 3.2 3.8"></path></g></svg><code>users</code></div><div class="gnav-ico cat-icon" title="calendar"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4.5" width="14" height="12.5" rx="1.8"></rect><path d="M3 8.5h14M7 3v3M13 3v3"></path></g></svg><code>calendar</code></div><div class="gnav-ico cat-icon" title="clock"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M10 6v4l2.8 1.8"></path></g></svg><code>clock</code></div><div class="gnav-ico cat-icon" title="search"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8.8" cy="8.8" r="5.3"></circle><path d="M12.8 12.8 17 17"></path></g></svg><code>search</code></div><div class="gnav-ico cat-icon" title="link"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8.6 11.4a3 3 0 0 0 4.2 0l2.6-2.6a3 3 0 0 0-4.2-4.2l-1 1"></path><path d="M11.4 8.6a3 3 0 0 0-4.2 0l-2.6 2.6a3 3 0 0 0 4.2 4.2l1-1"></path></g></svg><code>link</code></div><div class="gnav-ico cat-icon" title="sliders"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5h14M3 10h14M3 15h14"></path><circle cx="7" cy="5" r="1.6"></circle><circle cx="13" cy="10" r="1.6"></circle><circle cx="9" cy="15" r="1.6"></circle></g></svg><code>sliders</code></div><div class="gnav-ico cat-icon" title="settings"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15.52 9.08 17.15 9.15 17.15 10.85 15.52 10.92 14.56 13.26 15.66 14.45 14.45 15.66 13.26 14.56 10.92 15.52 10.85 17.15 9.15 17.15 9.08 15.52 6.74 14.56 5.55 15.66 4.34 14.45 5.44 13.26 4.48 10.92 2.85 10.85 2.85 9.15 4.48 9.08 5.44 6.74 4.34 5.55 5.55 4.34 6.74 5.44 9.08 4.48 9.15 2.85 10.85 2.85 10.92 4.48 13.26 5.44 14.45 4.34 15.66 5.55 14.56 6.74Z"></path><circle cx="10" cy="10" r="2.4"></circle></g></svg><code>settings</code></div><div class="gnav-ico cat-icon" title="alert"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3.2 17.3 16H2.7z"></path><path d="M10 8.2v3.6M10 13.9v.1"></path></g></svg><code>alert</code></div><div class="gnav-ico cat-icon" title="info"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="7"></circle><path d="M10 9v4.5M10 6.4v.1"></path></g></svg><code>info</code></div><div class="gnav-ico cat-icon" title="check"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5 8 14.5 16 5.5"></path></g></svg><code>check</code></div><div class="gnav-ico cat-icon" title="plus"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 4v12M4 10h12"></path></g></svg><code>plus</code></div><div class="gnav-ico cat-icon" title="close"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l10 10M15 5 5 15"></path></g></svg><code>close</code></div><div class="gnav-ico cat-icon" title="more"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="4.5" cy="10" r="1"></circle><circle cx="10" cy="10" r="1"></circle><circle cx="15.5" cy="10" r="1"></circle></g></svg><code>more</code></div><div class="gnav-ico cat-icon" title="utensils"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3v5a2 2 0 0 0 4 0V3M8 3v14"></path><path d="M15 3c-1.6 1.4-2.5 3.6-2.5 6.5H15V17"></path></g></svg><code>utensils</code></div><div class="gnav-ico cat-icon" title="signOut"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3.5H4v13h4M12.5 6.5 16 10l-3.5 3.5M16 10H8"></path></g></svg><code>signOut</code></div><div class="gnav-ico cat-icon" title="sparkle"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3.5c.4 2.9 1.6 4.1 4.5 4.5-2.9.4-4.1 1.6-4.5 4.5-.4-2.9-1.6-4.1-4.5-4.5 2.9-.4 4.1-1.6 4.5-4.5z"></path><path d="M14.5 12.5c.2 1.3.7 1.8 2 2-1.3.2-1.8.7-2 2-.2-1.3-.7-1.8-2-2 1.3-.2 1.8-.7 2-2z"></path></g></svg><code>sparkle</code></div></div><figure class="cat-demo"><figcaption>Một icon (markup)</figcaption><div class="cat-live"><svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="4" height="13" rx="1.2"></rect><rect x="8" y="3.5" width="4" height="9" rx="1.2"></rect><rect x="13" y="3.5" width="4" height="6" rx="1.2"></rect></g></svg></div><details class="cat-code"><summary>Markup</summary><pre><code>&lt;svg viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;
861
861
  &lt;g fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;
862
862
  &lt;rect x=&quot;3&quot; y=&quot;3.5&quot; width=&quot;4&quot; height=&quot;13&quot; rx=&quot;1.2&quot;&gt;
863
863
  &lt;/rect&gt;
package/gemboss-ui.css CHANGED
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  * GemBoss admin design system — GENERATED — do not edit; regenerate from gemboss:
3
3
  * node apps/admin/scripts/export-ui-css.mjs --out <path> (npm run export:ui-css)
4
- * gemboss commit: e86d83befc81e8a35c127cbe327f3ad895713c22
5
- * sources sha256: 2807a6d2a8b27730eaa31cbe6195b633cbba9467b0ab62b9244a7f814bb8d205
4
+ * gemboss commit: 1ca4f9ec8573ad9a6d72aad5f8a8e223cbf0e459
5
+ * sources sha256: a715d9e6a38a71817c8fc1389151ce000b89959b7ff1577af3851a953df73eba
6
6
  * contents: 1 allow-listed rule from apps/admin/src/app/globals.css + packages/ui/src/gemboss-tokens.css
7
7
  * (verbatim) + packages/ui/src/ui.css (verbatim) + packages/ui/src/gemboss-field.css (verbatim)
8
8
  * + 180 rules from packages/ui/src/shell.css (the shared shell)
@@ -1342,12 +1342,13 @@ textarea.gemboss-field { height: auto; padding: 6px 12px; resize: vertical; }
1342
1342
  display: flex;
1343
1343
  width: min(82vw, 300px);
1344
1344
  transform: translateX(-100%);
1345
- transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1);
1345
+ transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.26s cubic-bezier(0.4, 0, 0.2, 1);
1346
1346
  z-index: 1000;
1347
- box-shadow: 2px 0 26px rgba(31, 30, 29, 0.20);
1347
+ box-shadow: none;
1348
1348
  }
1349
1349
  .gemboss-platform-shell.is-mobile-nav-open .icon-nav {
1350
1350
  transform: translateX(0);
1351
+ box-shadow: 2px 0 26px rgba(31, 30, 29, 0.20);
1351
1352
  }
1352
1353
  .gemboss-mobile-nav-backdrop {
1353
1354
  display: block;
@@ -3161,6 +3162,42 @@ body.gemboss-assistant-unread .gnav-item.gnav-assistant::after {
3161
3162
  .gb-dock-side .gb-dock-sidegrip, .gb-dock-pinside { display: none; }
3162
3163
  }
3163
3164
 
3165
+ /* ── AssistantLauncher (02/10/2026): the floating button that opens the assistant, bottom-right ──────────────────────
3166
+ Top-right is the account corner (AccountMenu). Below the dock (290/320) and the topbar (300), above page content; the
3167
+ phone drawer (1000) covers it. 44px floor at every width; text + shortcut on wide screens, the icon alone on phones
3168
+ (the label stays the accessible name). Clears the iPhone home indicator with safe-area insets. */
3169
+ .gb-assistant-launcher {
3170
+ position: fixed;
3171
+ right: calc(20px + env(safe-area-inset-right, 0px));
3172
+ bottom: calc(20px + env(safe-area-inset-bottom, 0px));
3173
+ z-index: 280;
3174
+ display: inline-flex;
3175
+ align-items: center;
3176
+ gap: 8px;
3177
+ min-height: 44px;
3178
+ padding: 0 16px;
3179
+ border: 0;
3180
+ border-radius: 999px;
3181
+ background: var(--gemboss-primary, #1b1c1e);
3182
+ color: var(--gemboss-on-primary, #fff);
3183
+ font: 600 14px/1 var(--gemboss-font-sans, system-ui, sans-serif);
3184
+ box-shadow: var(--gemboss-shadow-raised, 0 6px 18px rgba(0, 0, 0, 0.18));
3185
+ cursor: pointer;
3186
+ }
3187
+ .gb-assistant-launcher:hover { background: var(--gemboss-primary-dark, #000); }
3188
+ .gb-assistant-launcher:focus-visible { outline: 2px solid var(--gemboss-accent, #5661f5); outline-offset: 2px; }
3189
+ .gb-assistant-launcher svg { flex: 0 0 auto; }
3190
+ .gb-assistant-launcher-kbd {
3191
+ font: inherit; font-size: 11px; opacity: 0.7;
3192
+ border: 1px solid currentColor; border-radius: 5px; padding: 1px 5px;
3193
+ }
3194
+ @media (max-width: 760px) {
3195
+ .gb-assistant-launcher { min-width: 52px; min-height: 52px; padding: 0; justify-content: center; }
3196
+ .gb-assistant-launcher-label, .gb-assistant-launcher-kbd {
3197
+ position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
3198
+ }
3199
+ }
3200
+
3164
3201
  /* ═══ @gemboss/ui src/kit-plain.css ═══ */
3165
3202
  /* kit-plain.css — kit primitives that only the NON-React surfaces use (GemFactory, gemcare, gempress write the
3166
3203
  markup by hand). They ship inside gemboss-ui.css (scripts/build-css.mjs `own`), but the admin does NOT import
@@ -3490,9 +3527,14 @@ button.ui-card__media, a.ui-card__media { cursor: pointer; }
3490
3527
  border: 1px solid transparent;
3491
3528
  padding: 6px 8px; font-size: var(--gemboss-fs-body); font-family: inherit;
3492
3529
  /* Starts at one line; GemChat's auto-grow JS expands it up to ~3 lines (max-height),
3493
- then scrolls inside (ChatGPT/Gemini-style). overflow-y is hidden until the JS flips
3494
- it to auto past the cap, so a 1–2 line message never shows a (rounding) scrollbar. */
3495
- min-height: 0; max-height: 84px; line-height: 1.5; overflow-y: hidden;
3530
+ then scrolls inside (ChatGPT/Gemini-style), and writes overflow-y itself (hidden until
3531
+ the cap, auto past it). The DEFAULT here is auto, for every surface that has no such
3532
+ JS: it was hidden, and there a message taller than the box could not be scrolled at
3533
+ all — wheel and touch do nothing under overflow:hidden. Measured 02/10/2026 in Chromium:
3534
+ wheel scrolled 0/9 overflowing boxes with hidden, 9/9 with auto; a box whose text
3535
+ fits showed no overflow at 13.5 / 14 / 15px (no rounding scrollbar). Found on
3536
+ partner-radar's assistant: 264px of text in a 75px box, unreadable. */
3537
+ min-height: 0; max-height: 84px; line-height: 1.5; overflow-y: auto;
3496
3538
  scrollbar-width: thin; scrollbar-color: rgba(31,30,29,0.22) transparent; /* thin, not the OS bar */
3497
3539
  }
3498
3540
  .gemboss-ec-input textarea::-webkit-scrollbar { width: 7px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gemboss/ui",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "GemBoss design system for every surface in the fleet: the admin shell (topbar + rail + drawer) as React components, and the admin stylesheet exported as one CSS file.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
package/src/assistant.css CHANGED
@@ -494,3 +494,39 @@
494
494
  .gb-dock-side { left: 240px; width: auto; }
495
495
  .gb-dock-side .gb-dock-sidegrip, .gb-dock-pinside { display: none; }
496
496
  }
497
+
498
+ /* ── AssistantLauncher (02/10/2026): the floating button that opens the assistant, bottom-right ──────────────────────
499
+ Top-right is the account corner (AccountMenu). Below the dock (290/320) and the topbar (300), above page content; the
500
+ phone drawer (1000) covers it. 44px floor at every width; text + shortcut on wide screens, the icon alone on phones
501
+ (the label stays the accessible name). Clears the iPhone home indicator with safe-area insets. */
502
+ .gb-assistant-launcher {
503
+ position: fixed;
504
+ right: calc(20px + env(safe-area-inset-right, 0px));
505
+ bottom: calc(20px + env(safe-area-inset-bottom, 0px));
506
+ z-index: 280;
507
+ display: inline-flex;
508
+ align-items: center;
509
+ gap: 8px;
510
+ min-height: 44px;
511
+ padding: 0 16px;
512
+ border: 0;
513
+ border-radius: 999px;
514
+ background: var(--gemboss-primary, #1b1c1e);
515
+ color: var(--gemboss-on-primary, #fff);
516
+ font: 600 14px/1 var(--gemboss-font-sans, system-ui, sans-serif);
517
+ box-shadow: var(--gemboss-shadow-raised, 0 6px 18px rgba(0, 0, 0, 0.18));
518
+ cursor: pointer;
519
+ }
520
+ .gb-assistant-launcher:hover { background: var(--gemboss-primary-dark, #000); }
521
+ .gb-assistant-launcher:focus-visible { outline: 2px solid var(--gemboss-accent, #5661f5); outline-offset: 2px; }
522
+ .gb-assistant-launcher svg { flex: 0 0 auto; }
523
+ .gb-assistant-launcher-kbd {
524
+ font: inherit; font-size: 11px; opacity: 0.7;
525
+ border: 1px solid currentColor; border-radius: 5px; padding: 1px 5px;
526
+ }
527
+ @media (max-width: 760px) {
528
+ .gb-assistant-launcher { min-width: 52px; min-height: 52px; padding: 0; justify-content: center; }
529
+ .gb-assistant-launcher-label, .gb-assistant-launcher-kbd {
530
+ position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
531
+ }
532
+ }
package/src/chat.css CHANGED
@@ -108,9 +108,14 @@
108
108
  border: 1px solid transparent;
109
109
  padding: 6px 8px; font-size: var(--gemboss-fs-body); font-family: inherit;
110
110
  /* Starts at one line; GemChat's auto-grow JS expands it up to ~3 lines (max-height),
111
- then scrolls inside (ChatGPT/Gemini-style). overflow-y is hidden until the JS flips
112
- it to auto past the cap, so a 1–2 line message never shows a (rounding) scrollbar. */
113
- min-height: 0; max-height: 84px; line-height: 1.5; overflow-y: hidden;
111
+ then scrolls inside (ChatGPT/Gemini-style), and writes overflow-y itself (hidden until
112
+ the cap, auto past it). The DEFAULT here is auto, for every surface that has no such
113
+ JS: it was hidden, and there a message taller than the box could not be scrolled at
114
+ all — wheel and touch do nothing under overflow:hidden. Measured 02/10/2026 in Chromium:
115
+ wheel scrolled 0/9 overflowing boxes with hidden, 9/9 with auto; a box whose text
116
+ fits showed no overflow at 13.5 / 14 / 15px (no rounding scrollbar). Found on
117
+ partner-radar's assistant: 264px of text in a 75px box, unreadable. */
118
+ min-height: 0; max-height: 84px; line-height: 1.5; overflow-y: auto;
114
119
  scrollbar-width: thin; scrollbar-color: rgba(31,30,29,0.22) transparent; /* thin, not the OS bar */
115
120
  }
116
121
  .gemboss-ec-input textarea::-webkit-scrollbar { width: 7px; }
package/src/icons.tsx CHANGED
@@ -57,6 +57,8 @@ const P = {
57
57
  more: <><circle cx="4.5" cy="10" r="1" /><circle cx="10" cy="10" r="1" /><circle cx="15.5" cy="10" r="1" /></>,
58
58
  utensils: <><path d="M6 3v5a2 2 0 0 0 4 0V3M8 3v14" /><path d="M15 3c-1.6 1.4-2.5 3.6-2.5 6.5H15V17" /></>,
59
59
  signOut: <path d="M8 3.5H4v13h4M12.5 6.5 16 10l-3.5 3.5M16 10H8" />,
60
+ // The assistant's mark (✦ in the surfaces' old hand-drawn buttons): a four-point star + a small one.
61
+ sparkle: <><path d="M9 3.5c.4 2.9 1.6 4.1 4.5 4.5-2.9.4-4.1 1.6-4.5 4.5-.4-2.9-1.6-4.1-4.5-4.5 2.9-.4 4.1-1.6 4.5-4.5z" /><path d="M14.5 12.5c.2 1.3.7 1.8 2 2-1.3.2-1.8.7-2 2-.2-1.3-.7-1.8-2-2 1.3-.2 1.8-.7 2-2z" /></>,
60
62
  } satisfies Record<string, React.ReactNode>;
61
63
  // `satisfies`, not a `Record<string, …>` annotation: the annotation widened `keyof` to `string`, so a
62
64
  // typo (`name="setings"`) type-checked and drew an empty box (review #3474).
package/src/index.ts CHANGED
@@ -8,3 +8,4 @@ export { BrandLockup } from "./brand";
8
8
  export { AccountMenu, AccountMenuItem, initialsOf } from "./account";
9
9
  export { Menu, MenuItem, MenuSeparator } from "./menu";
10
10
  export { Icon, ICON_NAMES, type IconName } from "./icons";
11
+ export { AssistantLauncher } from "./launcher";
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ /**
3
+ * The button that opens a surface's AI assistant: bottom-right, floating (02/10/2026, Chris: "chắc vẫn phải để button ở góc
4
+ * dưới bên phải còn góc trên bên phải là account … đồng bộ"). partner-radar had it in the topbar's top-right corner, which on
5
+ * a phone became a black ✦ circle exactly where content-radar shows the account chip — two surfaces on one frame, the same
6
+ * corner doing two different jobs. The top-right corner is the ACCOUNT (AccountMenu); the assistant lives here.
7
+ *
8
+ * Deliberately dumb: no provider, no state. A surface on `@gemboss/ui/assistant` passes `hidden` while its dock is open
9
+ * (`presentation !== "hidden"`); a surface with its own panel does the same with its own flag.
10
+ */
11
+ import React from "react";
12
+ import { Icon } from "./icons";
13
+
14
+ export function AssistantLauncher({ label, shortcut, hidden, onClick, className, ...rest }: {
15
+ /** Visible name, e.g. "Hỏi AI" / "Partner Assistant". Kept as the accessible name when the text hides on phones. */
16
+ label: string;
17
+ /** Keyboard hint shown on wide screens, e.g. "⌘J". Decorative: the surface owns the shortcut itself. */
18
+ shortcut?: string;
19
+ /** The assistant is already open — the launcher steps out of the way (it would sit under the dock). */
20
+ hidden?: boolean;
21
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
22
+ className?: string;
23
+ } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick" | "hidden">) {
24
+ if (hidden) return null;
25
+ return (
26
+ <button type="button" className={className ? `gb-assistant-launcher ${className}` : "gb-assistant-launcher"}
27
+ aria-label={shortcut ? `${label} (${shortcut})` : label} onClick={onClick} {...rest}>
28
+ <Icon name="sparkle" />
29
+ <span className="gb-assistant-launcher-label">{label}</span>
30
+ {shortcut ? <kbd className="gb-assistant-launcher-kbd">{shortcut}</kbd> : null}
31
+ </button>
32
+ );
33
+ }
package/src/shell.css CHANGED
@@ -512,15 +512,18 @@
512
512
  .gemboss-mobile-menu-btn:active { background: var(--gemboss-hover); }
513
513
  /* rail → off-canvas drawer (slides over the content; later source beats the
514
514
  earlier ≤760 `display:none`) */
515
+ /* The shadow belongs to the OPEN drawer only. On the closed one (translateX(-100%), right edge at x=0) a
516
+ 26px blur bleeds back across the left edge of every phone screen as a grey strip — measured on
517
+ content-radar at 390, 02/10/2026; every surface on this shell had it. */
515
518
  .icon-nav {
516
519
  display: flex;
517
520
  width: min(82vw, 300px);
518
521
  transform: translateX(-100%);
519
- transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1);
522
+ transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.26s cubic-bezier(0.4, 0, 0.2, 1);
520
523
  z-index: 1000;
521
- box-shadow: 2px 0 26px rgba(31, 30, 29, 0.20);
524
+ box-shadow: none;
522
525
  }
523
- .gemboss-platform-shell.is-mobile-nav-open .icon-nav { transform: translateX(0); }
526
+ .gemboss-platform-shell.is-mobile-nav-open .icon-nav { transform: translateX(0); box-shadow: 2px 0 26px rgba(31, 30, 29, 0.20); }
524
527
  .gemboss-mobile-nav-backdrop {
525
528
  display: block; position: fixed; inset: 56px 0 0 0;
526
529
  width: 100%; border: 0; padding: 0;