/*
 * GemBoss admin design system — GENERATED — do not edit; regenerate from gemboss:
 *   node apps/admin/scripts/export-ui-css.mjs --out <path>   (npm run export:ui-css)
 * gemboss commit: df45faa4dbe3cd2a792194682a7e71ceaed05b08
 * sources sha256: 073ea4d3d9160057ff0198dc220673bc0523726ecb50a4488a7b62f304ff8ca5
 * contents: 1 allow-listed rule from apps/admin/src/app/globals.css + apps/admin/src/app/gemboss-tokens.css
 *   (verbatim) + apps/admin/src/components/ui/ui.css (verbatim) + 57 allow-listed rules from apps/admin/src/app/gemboss-shell.css
 * Polaris --p-* references are resolved to their fallbacks; declarations with no fallback are dropped
 *   (0 dropped).
 */
/* ═══ globals.css — allow-listed reset ═══ */
* {
  box-sizing: border-box;
}

/* ═══ gemboss-tokens.css ═══ */
/* The design tokens, and ONLY the tokens.
 *
 * Split out of gemboss-shell.css because that file is 203 KB of dashboard component CSS and it was
 * loaded by the ROOT layout — so /try and /login, which render no .gemboss-* component at all,
 * blocked their first paint on it. Tokens are 6 KB of the 203; /login uses var(--gemboss-primary)
 * and the rewritten /try uses the palette, so everyone needs these and almost nobody needs the rest.
 *
 * Order matters and is preserved: the second :root block below redefines --gemboss-primary and
 * friends from the first, exactly as it did inside the shell file. The Polaris --p-* overrides stay
 * in gemboss-shell.css, next to the Polaris stylesheet they override.
 */
:root {
  --gemboss-primary: #1b1c1e;        /* near-black — primary action (buttons / CTA) */
  --gemboss-primary-dark: #000000;   /* black hover */
  --gemboss-primary-soft: #f2f3f5;   /* neutral tint */
  --gemboss-accent: #5661f5;         /* iris — brand accent, điểm nhấn only (links / focus / active) */
  --gemboss-accent-strong: #3a44de;  /* iris strong (hover / text) */
  --gemboss-accent-soft: #eef0fe;    /* iris tint */
  --gemboss-text-strong: #1b1c1e;    /* neutral near-black */
  --gemboss-text: #1b1c1e;
  --gemboss-text-muted: #686b71;     /* neutral gray */
  --gemboss-surface: #ffffff;
  --gemboss-canvas: #ffffff;         /* white page background (was #f6f7f9 gray) — body + Polaris --p-color-bg */
  --gemboss-preview-canvas: #eceef1; /* neutral sunken backdrop behind a live preview/widget stage */
  --gemboss-rail-bg: #ffffff;        /* white sidebar (was #f4f5f7) — separated by border-right divider */
  --gemboss-panel-bg: #ffffff;       /* white secondary panels (was #f2f4f6) */
  --gemboss-divider: #e5e7ea;        /* neutral hairline border */

  /* Chiều cao THẬT của lời mời desktop, do DesktopInvite.tsx ghi đè lúc chạy bằng ResizeObserver
     (chip ~44px, thẻ mở ~328px) và GỠ HẲN khi lời mời không hiện. Khai ở đây bằng 0px vì hai lẽ:
     cổng `export-ui-css` đòi mọi token phải được khai (nó bắt được đúng thiếu sót này), và một
     `var()` không có chủ sở hữu là thứ không ai tra ngược được. Trang dùng nó để chừa chỗ ở cuối
     tài liệu — xem `.gemboss-platform-main { padding-bottom: … }` trong gemboss-shell.css. */
  --gemboss-invite-h: 0px;
  --gemboss-divider-soft: #edeff2;
  --gemboss-hover: #eceef2;
  --gemboss-active-bg: #f0f1f4;      /* neutral selected (Polaris-style) */
  --gemboss-active-fg: #1b1c1e;      /* near-black selected text */
  --gemboss-danger: #d72c0d;
  --gemboss-danger-strong: #b42318;
  --gemboss-danger-soft: #fff0e9;
  --gemboss-danger-border: #f5c9bc;
  --gemboss-success: #007f5f;
  --gemboss-success-strong: #0a6a4c;
  --gemboss-success-soft: #e3f1df;
  --gemboss-success-border: #b7dfcd;
  --gemboss-warning: #9a6700;
  --gemboss-warning-soft: #fff8e0;
  --gemboss-warning-border: #f5d569;
  /* Corner-radius scale — Polaris border-radius steps (2/4/6/8/12/16/20 + pill). The old
     long tail of one-off radii (5/7/9/10/11/14/18px) was consolidated onto these steps
     (round-half-up on ties: 5→6, 7→8, 9→8, 10→12, 11→12, 14→16, 18→20) — the
     check-typography guard now keeps radii on-scale. Prefer a token below; raw px must
     still land on a step. */
  --gemboss-radius-xs: 4px;
  --gemboss-radius-sm: 6px;
  --gemboss-radius-md: 8px;
  --gemboss-radius-lg: 12px;
  --gemboss-radius-xl: 16px;
  --gemboss-radius-2xl: 20px;
  --gemboss-radius-full: 999px;
  /* ── Elevation scale (design-language §G) ────────────────────────────────────
     THREE layers, one shadow each — was ~25 bespoke box-shadows (0 6/8/12/16/28px
     at a dozen opacities + mixed shadow colours) = no elevation system. Warm-neutral
     shadow (rgba 31,30,29) to match the ivory canvas. Use a token, never a hand-rolled
     drop shadow. (Directional edge shadows, coloured glows, focus rings, and insets are
     NOT elevation — they stay literal.) */
  --gemboss-shadow-resting: 0 1px 2px rgba(31, 30, 29, 0.04), 0 2px 6px rgba(31, 30, 29, 0.06); /* cards at rest on canvas */
  --gemboss-shadow-raised: 0 4px 16px rgba(31, 30, 29, 0.10);   /* dropdowns · popovers · hovercards */
  --gemboss-shadow-overlay: 0 16px 48px rgba(31, 30, 29, 0.18); /* modals · sheets · large floating panels */
  /* Interaction transition speeds — fast = hover/focus on buttons & toggles, base = the
     general default. One-off animation timings (toast/enter, 240–420ms) stay literal. */
  --gemboss-transition-fast: 0.12s;
  --gemboss-transition-base: 0.15s;
  /* ── Type scale ─────────────────────────────────────────────────────────────
     ONE font-size scale for all custom (non-Polaris-<Text>) chrome. Before this,
     gemboss-shell.css carried ~20 ad-hoc sizes (9px → 40px, incl. fractional 10.5 /
     11.5 / 12.5 / 13.5) — every component hand-nudged its own, drifting smaller
     and reading as "the font keeps shrinking". New rule: pick a step here, never a
     raw px. Floor is 12px (--fs-caption); 11px (--fs-micro) is reserved for bold
     micro-badges/count-pills ONLY — nothing below that. Body default is 14px, one
     step up from Polaris bodySm(13) which the app had been leaning on for prose. */
  --gemboss-fs-micro: 11px;   /* bold count-pills / status chips only */
  --gemboss-fs-caption: 12px; /* metadata, timestamps, secondary labels */
  --gemboss-fs-body: 14px;    /* default body / reading text */
  --gemboss-fs-body-lg: 16px; /* primary descriptions, empty-state prose */
  --gemboss-fs-h3: 16px;      /* card titles */
  --gemboss-fs-h2: 20px;      /* zone / section headers */
  --gemboss-fs-h1: 24px;      /* page titles */
  --gemboss-fs-display: 30px; /* hero / banner display */
  /* Headings use the same clean sans as Polaris body (Shopify-admin feel) rather
   * than a serif display face — a dashboard reads calmer/more neutral that way.
   * Name kept as `--gemboss-serif` to avoid churning ~10 call sites. */
  /* -- Khung nen TOI, dung chung cho hai be mat toi --------------------------
     `/admin` khai `--adm-*`, `/intel` khai `--in-*`, va bay gia tri trung tinh cua chung trung
     nhau TUNG BYTE duoi hai bo ten khac nhau -- do 10/09/2026:

       #0a0a0c  adm-bg        in-bg        #2a2a31  adm-divider    in-border
       #0e0e11  adm-rail      in-bg2       #ededf0  adm-text       in-text
       #16161a  adm-surface   in-panel     #9a9aa4  adm-muted      in-muted
       #1e1e24  adm-surface-2 in-panel2

     Do la mot ban sao, khong phai mot bien the: hai console cung mot nen, va lam nen sang them
     mot bac thi phai nho sua o hai cho mang ten khac nhau. Bay gia tri nay song o day; `--adm-*`
     va `--in-*` tro thanh BI DANH tro vao, nen 595 cho dang goi chung khong phai doi mot chu.

     KHONG gop phan con lai: `--in-panel3/-border2/-faint` la bac rieng intel that su can, va bon
     mau ngu nghia cua no (xanh - ho phach - san ho - tim) la ngon ngu rieng cua be mat do. Gop
     nen, giu diem nhan. */
  --gemboss-dark-bg: #0a0a0c;
  --gemboss-dark-rail: #0e0e11;
  --gemboss-dark-surface: #16161a;
  --gemboss-dark-surface-2: #1e1e24;
  --gemboss-dark-divider: #2a2a31;
  --gemboss-dark-text: #ededf0;
  --gemboss-dark-muted: #9a9aa4;
  --gemboss-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

:root {
  --gemboss-primary: #1b1c1e;
  --gemboss-primary-dark: #000000;
  --gemboss-primary-soft: #f2f3f5;
  --gemboss-accent: #5661f5;
  --gemboss-accent-strong: #3a44de;
  --gemboss-accent-soft: #eef0fe;
  --gemboss-active-bg: #f0f1f4;      /* neutral selected (Polaris-style) */
  --gemboss-active-fg: #1b1c1e;      /* near-black selected text */
  --gemboss-app-bg: #ffffff; /* clean white main content (was #f6f7f9 gray) — cards keep separation via border/resting-shadow */
}

/* ═══ ui.css ═══ */
/* ════════════════════════════════════════════════════════════════════════════
   Tool/App UI kit — the shared primitive layer for the internal operator surfaces
   (admin console, seller app chrome, theme-editor). ONE semantic token spine
   (`--ui-*`) that every primitive reads, plus the primitive CSS itself.

   Why this exists: buttons/cards/badges were forked into 4–8 hand-rolled class
   families per surface, each re-deriving color/spacing/centering — so the same
   primitive drifted (e.g. a link-button whose text wasn't vertically centered).
   See docs/frontend-shared-system-plan.md.

   The `--ui-*` layer is SEMANTIC and resolved per surface: components only read
   `--ui-*`; each surface maps those to its own tokens (admin → `--adm-*` below),
   so one <Button> looks native everywhere without hard-coding a palette.
   ════════════════════════════════════════════════════════════════════════════ */

:root {
  --ui-surface: #ffffff;
  /* --ui-* is a SEMANTIC layer resolved PER SURFACE — it references each surface's own base tokens
     rather than guessing from the OS. The default (`:root`) maps onto the seller app's warm-ivory
     `--gemboss-*` set; `.gemboss-admin-shell` below remaps onto the dark `--adm-*` set. Literal fallbacks
     keep the kit usable if a surface's base stylesheet isn't loaded. This is the "unify under --ui-*"
     backbone — one token spine, no duplicated palette. */
  --ui-surface: var(--gemboss-surface, #ffffff);
  --ui-surface-2: var(--gemboss-hover, #eceef2);
  --ui-text: var(--gemboss-text, #1b1c1e);
  --ui-text-muted: var(--gemboss-text-muted, #686b71);
  --ui-border: var(--gemboss-divider, #e5e7ea);
  --ui-accent: var(--gemboss-primary, #1b1c1e);
  --ui-accent-hover: var(--gemboss-primary-dark, #000000);
  --ui-accent-fg: #ffffff;
  --ui-accent-soft: var(--gemboss-active-bg, #f0f1f4);   /* tinted bg for a selected/active state */
  --ui-accent-strong: var(--gemboss-active-fg, #1b1c1e); /* readable accent text ON --ui-accent-soft */
  --ui-text-strong: var(--gemboss-text-strong, #1b1c1e);
  --ui-focus: var(--gemboss-primary, #1b1c1e);
  --ui-radius-sm: 6px;
  --ui-radius-md: 8px;
  --ui-radius-lg: 12px;
  --ui-space-1: 4px;
  --ui-space-2: 8px;
  --ui-space-3: 12px;
  --ui-space-4: 16px;
  --ui-control-h: 34px;
  --ui-fs-body: 13px;
  --ui-fs-caption: 12px;
  /* Content column width for the seller app shell — ONE source of truth for every wide surface
     right of the 240px sidebar (bare Page, .gemboss-w-dashboard, .gemboss-w-gallery, and the
     navigation skeleton), so they cannot drift apart again. The /admin console is a SEPARATE
     surface and still sets its own 1200px in admin/admin-shell.css; it does not read this token.
     900px. Polaris' own cap is 998px — 41.375rem primary column + 20rem secondary + 1rem gutter,
     read out of the installed @shopify/polaris stylesheet — and this sits deliberately BELOW it.

     The reason is a measurement, not a preference about Shopify. The previous value was 1080/1040,
     and moving to Polaris' 998 was the obvious "correct" answer, so that shipped first (#2250). Then
     it turned out to be invisible: 1040 → 998 is 42px total, which is 21px of extra gutter per side.
     Screenshotted side by side at 1440 on the same page seconds apart, the two rows were
     indistinguishable, and Chris — who asked for this — could not see any change at all.

     A cap only does its job if the breathing room it buys is legible. Measured gutters on
     .Polaris-Page at 1440 beside the 240px sidebar:

       1040px → 75 / 86      (before)
        998px → 96 / 107     Polaris' number; +21px a side, not perceivable
        960px → 115 / 126
        900px → 145 / 156    +70px a side, roughly double the old gutter

     900 is the first value where the column visibly stops leaning on the rail. The one cost, and it
     was measured rather than guessed: card descriptions gain a line (Cart drawer 2 → 3). The 3-up
     grid holds, and no width from 320 to 1920 overflows.

     Still fixed px, no percentage, for the reason Polaris uses px: a % cap grows the reading measure
     with the monitor (80% of 2560 is 2048px of line length). Responsiveness belongs to the padding
     and to the secondary column dropping, not to the cap.

     .gemboss-w-form stays 662px — that IS `.Polaris-Page--narrowWidth`, the primary column alone,
     and a form is the one surface where Polaris' measure is about the input, not the page. */
  --ui-content-max: 900px;
}

/* Admin console bridge: the black chrome defines `--adm-*`; remap `--ui-*` onto them so every
   <Button>/<Select>/<Tag>/<Modal> inside .gemboss-admin-shell adopts the dark palette automatically. */
.gemboss-admin-shell {
  --ui-surface: var(--adm-surface);
  --ui-surface-2: var(--adm-surface-2);
  --ui-text: var(--adm-text);
  --ui-text-muted: var(--adm-muted);
  --ui-border: var(--adm-divider);
  --ui-accent: var(--adm-accent);
  --ui-accent-hover: var(--gemboss-primary-dark, #000000);
  --ui-accent-fg: #ffffff;
  --ui-accent-soft: var(--adm-accent-soft);
  --ui-accent-strong: var(--adm-accent-fg);
  --ui-text-strong: var(--adm-text-strong);
  --ui-focus: var(--adm-accent);
}

/* ── Button ──────────────────────────────────────────────────────────────────
   inline-flex + center so a <button> and an <a> render identically (anchors ignore
   `height` as inline elements — the root cause of the misaligned link-buttons). */
.ui-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--ui-space-2);
  height: var(--ui-control-h); padding: 0 var(--ui-space-4); box-sizing: border-box;
  line-height: 1; white-space: nowrap; vertical-align: middle;
  border-radius: var(--ui-radius-md); font-family: inherit; font-size: var(--ui-fs-body); font-weight: 550;
  cursor: pointer; text-decoration: none; user-select: none;
  border: 1px solid var(--ui-border); background: transparent; color: var(--ui-text);
  transition: background .12s ease, border-color .12s ease;
}
.ui-btn:hover { background: var(--ui-surface-2); text-decoration: none; }
.ui-btn:focus-visible { outline: 2px solid var(--ui-focus); outline-offset: 2px; }
.ui-btn[disabled], .ui-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.ui-btn--primary { background: var(--ui-accent); border-color: var(--ui-accent); color: var(--ui-accent-fg); }
.ui-btn--primary:hover { background: var(--ui-accent-hover); border-color: var(--ui-accent-hover); }
.ui-btn--ghost { border-color: transparent; background: transparent; color: var(--ui-text-muted); }
.ui-btn--ghost:hover { background: var(--ui-surface-2); color: var(--ui-text); }
.ui-btn--sm { height: 28px; padding: 0 var(--ui-space-3); font-size: var(--ui-fs-caption); }

/* ── Card ──────────────────────────────────────────────────────────────────── */
.ui-card {
  background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg);
  padding: var(--ui-space-4); color: var(--ui-text);
}
.ui-card__title { font-size: 14px; font-weight: 600; margin: 0 0 var(--ui-space-2); }

/* ── Select ──────────────────────────────────────────────────────────────────
   Native <select> reskinned; custom caret as an inline SVG data-URI (caret color
   uses the muted token via %-encoding fallback). */
.ui-select {
  height: 36px; padding: 0 32px 0 12px; max-width: 100%;
  background: var(--ui-surface-2) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 20 20'><path fill='%239a9aa4' d='M5 7l5 5 5-5z'/></svg>") no-repeat right 10px center;
  border: 1px solid var(--ui-border); border-radius: var(--ui-radius-md);
  color: var(--ui-text); font-family: inherit; font-size: var(--ui-fs-body); font-weight: 500;
  appearance: none; -webkit-appearance: none; cursor: pointer;
}
.ui-select:hover { border-color: var(--ui-text-muted); }
.ui-select:focus { outline: none; border-color: var(--ui-accent); }
.ui-select--slim { height: 30px; font-size: var(--ui-fs-caption); }

/* ── Tag / Chip ──────────────────────────────────────────────────────────────
   Small inline labels. `solid` = filled muted pill (was gemboss-vault-tag); `chip` =
   bordered mono token (was gemboss-vault-chip). `accent` tone for the highlighted state. */
.ui-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  padding: 1px 6px; border-radius: 6px; background: var(--ui-surface-2); color: var(--ui-text-muted);
}
.ui-tag--accent { background: var(--adm-accent-soft, rgba(20,22,26,.05)); color: var(--adm-accent-fg, var(--ui-accent)); }
.ui-tag--chip {
  text-transform: none; letter-spacing: 0; font-size: 11px; font-weight: 500;
  padding: 2px 8px; background: transparent; border: 1px solid var(--ui-border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.ui-tag--chip.ui-tag--accent { color: var(--adm-accent-fg, var(--ui-accent)); border-color: var(--ui-accent); background: transparent; }

/* ── Badge ────────────────────────────────────────────────────────────────────
   Uppercase mono pill for a status/label (was gemboss-admin-storage-badge). */
.ui-badge {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
  padding: 1px 8px; border-radius: 6px; background: var(--ui-surface-2); color: var(--ui-text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── Modal ────────────────────────────────────────────────────────────────────
   Rendered INLINE (not portaled): a portal escapes the .gemboss-admin-shell token
   scope and would render light. Kept in-tree so --ui-* resolves to the surface. */
.ui-overlay {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(2px);
  display: grid; place-items: center; padding: 20px;
}
.ui-modal {
  width: min(460px, 100%);
  background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: 16px;
  box-shadow: var(--gemboss-shadow-overlay, 0 20px 60px rgba(0, 0, 0, 0.4)); overflow: hidden;
}
/* Head = title + the one close button every modal used to draw for itself. */
.ui-modal__head {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 16px 20px; border-bottom: 1px solid var(--ui-border);
  font-size: 15px; font-weight: 620; color: var(--ui-text);
}
.ui-modal__title { min-width: 0; flex: 1 1 auto; }
.ui-modal__close {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin: -8px -8px -8px 0;   /* a 44px target that does not grow the head */
  border: 0; border-radius: var(--ui-radius-md, 8px); background: transparent;
  color: var(--ui-text-muted); cursor: pointer;
}
.ui-modal__close svg { width: 20px; height: 20px; }
.ui-modal__close:hover { background: var(--ui-surface-2); color: var(--ui-text); }
.ui-modal__close:focus-visible { outline: 2px solid var(--ui-accent); outline-offset: -2px; }

/* `size="lg"` — the screen-shaped dialog. Only the HOOK lives here: this sheet is imported by the
   root layout, so every rule in it is paid on every screen, and the geometry of a dialog with one
   consumer belongs in that consumer's chunk (see SettingsDialog.module.css). */
.ui-modal--lg { position: relative; }

.ui-textarea {
  width: 100%; min-height: 96px; resize: vertical; box-sizing: border-box;
  background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-md);
  padding: 12px; color: var(--ui-text); font-size: 14px; font-family: inherit; outline: none;
}
.ui-textarea:focus { border-color: var(--ui-accent); }

/* ── Segmented control ────────────────────────────────────────────────────────
   Grouped toggle: icon squares (.ui-seg button) or text tabs (.is-text). The
   selected segment uses the accent-soft state. */
.ui-seg { display: inline-flex; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-md); overflow: hidden; }
.ui-seg button {
  display: inline-grid; place-items: center; width: 36px; height: 36px;
  border: 0; background: transparent; color: var(--ui-text-muted); cursor: pointer; font-family: inherit;
}
.ui-seg button.is-text { width: auto; padding: 0 12px; font-size: var(--ui-fs-body); font-weight: 500; }
.ui-seg button + button { border-left: 1px solid var(--ui-border); }
.ui-seg button:hover { background: var(--ui-surface-2); color: var(--ui-text); }
.ui-seg button.active { background: var(--ui-accent-soft); color: var(--ui-accent-strong); }
.ui-seg svg { width: 16px; height: 16px; fill: currentColor; }

/* ── Stat chip ────────────────────────────────────────────────────────────────
   Count-led pill; clickable ones double as filters (active = accent-soft). */
.ui-stats { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); margin-bottom: 24px; }
.ui-stat {
  display: inline-flex; align-items: center; gap: var(--ui-space-2);
  padding: 6px 12px; border-radius: 999px; font-family: inherit;
  background: var(--ui-surface); border: 1px solid var(--ui-border);
  font-size: var(--ui-fs-caption); color: var(--ui-text-muted);
}
.ui-stat b { color: var(--ui-text-strong); font-weight: 650; }
.ui-stat.is-clickable { cursor: pointer; transition: border-color 0.14s ease, background-color 0.14s ease; }
.ui-stat.is-clickable:hover { border-color: var(--ui-text-muted); background: var(--ui-surface-2); }
.ui-stat.is-clickable.active { border-color: var(--ui-accent); background: var(--ui-accent-soft); color: var(--ui-accent-strong); }
.ui-stat.is-clickable.active b { color: var(--ui-accent-strong); }

/* ── Toast / notification bar ─────────────────────────────────────────────────
   App-wide "done / failed" pill for async actions (delete/duplicate/publish…).
   Polaris-style: dark pill, bottom-center, error variant in critical red. Lives
   in <ToastProvider> (components/ui/Toast.tsx), portaled to <body>. */
.gemboss-toast-viewport {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 2147483000; /* above every overlay/modal/popup */
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  width: max-content; max-width: min(560px, calc(100vw - 32px)); pointer-events: none;
}
.gemboss-toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: 12px;
  min-width: 220px; max-width: 100%; padding: 12px 12px 12px 16px;
  background: var(--ui-text-strong, #1a1917); color: #fff; border-radius: 12px;
  font-size: var(--ui-fs-body, 13px); line-height: 1.4; font-weight: 500;
  box-shadow: var(--gemboss-shadow-overlay, 0 8px 28px rgba(0, 0, 0, 0.24));
  animation: gemboss-toast-in 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
.gemboss-toast.is-error { background: var(--gemboss-danger, #d72c0d); }
.gemboss-toast-text { flex: 1 1 auto; min-width: 0; }
.gemboss-toast-action {
  flex: 0 0 auto; border: 0; background: transparent; color: #fff; cursor: pointer;
  padding: 4px 8px; border-radius: 8px; font: inherit; font-weight: 650;
  text-decoration: underline; text-underline-offset: 2px;
  transition: background 0.14s ease;
}
.gemboss-toast-action:hover { background: rgba(255, 255, 255, 0.16); }
.gemboss-toast-dismiss {
  flex: 0 0 auto; display: inline-grid; place-items: center;
  width: 24px; height: 24px; border: 0; border-radius: 8px; cursor: pointer;
  background: rgba(255, 255, 255, 0.12); color: #fff;
  transition: background 0.14s ease;
}
.gemboss-toast-dismiss:hover { background: rgba(255, 255, 255, 0.26); }
.gemboss-toast-action:focus-visible,
.gemboss-toast-dismiss:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@keyframes gemboss-toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .gemboss-toast { animation: none; } }

/* ── The kit's controls under a thumb ─────────────────────────────────────────────────────────
 * Measured by hit test on /admin/{theme-kernel,media,style-packs} at 390 and 1366 with a coarse
 * pointer: segmented buttons 36x36, selects 30-36 tall, clickable stat tiles 29, the asset row's
 * note button 30x30. §9.1 puts every one of them in the CONTROL tier (44px).
 *
 * HERE rather than in each surface's stylesheet, because this is the shared primitive layer — the
 * same reason the kit exists at all. The admin console and the seller app both read it.
 *
 * `pointer: coarse` only: a mouse keeps the density these surfaces were designed at. Growing a box
 * for every pointer is what #2147 did to a working width.
 */
@media (pointer: coarse) {
  /* NOT `.ui-textarea`: it already declares `min-height: 96px` earlier in this file, so adding it to
     a 44px group LOWERS it — same specificity, later line. The note dialog's box would have gone from
     96 to ~58 on every touch device, inside a block whose whole point is bigger targets.
     NOT `.ui-btn--sm` either: `min-height` always beats `height`, so a 44px floor voids the compact
     variant — including four of them on the seller's own /app/settings/store. A density variant is a
     decision, not an oversight; it gets its own measurement pass or none. */
  .ui-btn:not(.ui-btn--sm),
  .ui-stat.is-clickable,
  .ui-seg button { min-height: 44px; }
  /* A clickable stat whose label is one short token ("7d" on /admin/gem-intelligence) measured 40x44
     in the 13/09/2026 sweep: the height floor held, the width did not. */
  .ui-stat.is-clickable { min-width: 44px; justify-content: center; }
  /* `--slim` is a second single class and lands later in this file, so it would win on order over a
     bare `.ui-select`. Doubled here to decide it on specificity instead. */
  .ui-select.ui-select,
  .ui-select--slim.ui-select--slim { min-height: 44px; }
  /* The icon-only segment is 36 WIDE as well — a target is an area. */
  .ui-seg button { min-width: 44px; }
}

/* ── Skeleton ─────────────────────────────────────────────────────────────────
   Vạch xám giữ chỗ cho nội dung chưa về. Ánh sáng chạy qua là gợi ý "đang chờ", không phải trang
   trí — nên nó tắt hẳn với `prefers-reduced-motion`, giữ nguyên vạch tĩnh. */
.ui-skeleton { display: flex; flex-direction: column; gap: var(--ui-space-2); }
.ui-skeleton__line {
  display: block; height: 12px; border-radius: 6px;
  background: linear-gradient(90deg, var(--ui-surface-2) 25%, var(--ui-border) 37%, var(--ui-surface-2) 63%);
  background-size: 400% 100%;
  animation: ui-skeleton-sheen 1.4s ease-in-out infinite;
}
@keyframes ui-skeleton-sheen { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
  .ui-skeleton__line { animation: none; background: var(--ui-surface-2); }
}
/* Nhãn cho trình đọc màn hình — thứ `<p>Loading…</p>` cũ vốn có và một khối hình thuần sẽ mất. */
.ui-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;

}

/* ── Tabs · Table · Empty state ───────────────────────────────────────────────
   Plain-CSS primitives for surfaces that are NOT React (gemcare's vanilla dashboard reads this
   file through `npm run export:ui-css`). The React app has Polaris <Tabs>/<DataTable>/<EmptyState>
   for these; nothing in apps/admin uses the classes below, and they restyle no existing component.
   Only `--ui-*` / `--gemboss-*` tokens, so the dark `.gemboss-admin-shell` bridge applies too.

   Tabs: `<div class="ui-tabs" role="tablist"><button role="tab" aria-selected="true">…` — the
   selected state IS `aria-selected`, so what a screen reader announces and what is painted cannot
   disagree. 44px under EVERY pointer (§9.1 control tier), not only coarse: tabs sit 4px apart, and
   that gap is only acceptable between targets that are already 44px. */
.ui-tabs {
  display: flex; gap: var(--ui-space-1); border-bottom: 1px solid var(--ui-border);
  overflow-x: auto; scrollbar-width: none;
}
.ui-tabs > button {
  position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--ui-space-2);
  min-height: 44px; padding: 0 var(--ui-space-3); border: 0; background: transparent; cursor: pointer;
  border-radius: var(--ui-radius-sm) var(--ui-radius-sm) 0 0;
  font-family: inherit; font-size: var(--gemboss-fs-body); font-weight: 500; white-space: nowrap;
  color: var(--ui-text-muted);
  transition: color var(--gemboss-transition-fast) ease, background-color var(--gemboss-transition-fast) ease;
}
.ui-tabs > button:hover { color: var(--ui-text); background: var(--ui-surface-2); }
.ui-tabs > button:focus-visible { outline: 2px solid var(--ui-focus); outline-offset: -2px; }
.ui-tabs > button[aria-selected="true"] { color: var(--ui-text-strong); font-weight: 600; }
.ui-tabs > button[aria-selected="true"]::after {
  content: ""; position: absolute; left: var(--ui-space-3); right: var(--ui-space-3); bottom: 0;
  height: 2px; border-radius: var(--gemboss-radius-full); background: var(--ui-accent);
}
.ui-tabs > button:disabled { opacity: .5; cursor: not-allowed; }

/* Table: wrap it — `<div class="ui-table-wrap"><table class="ui-table">` — so a wide table scrolls
   inside its card instead of pushing the page sideways at 320px. Numeric cells take `.is-num`:
   right-aligned tabular figures, so a column of numbers lines up digit for digit. */
.ui-table-wrap {
  overflow-x: auto; max-width: 100%;
  background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg);
}
.ui-table { width: 100%; border-collapse: collapse; font-size: var(--gemboss-fs-body); color: var(--ui-text); }
.ui-table th,
.ui-table td {
  padding: var(--ui-space-2) var(--ui-space-3); text-align: left; vertical-align: middle;
  border-bottom: 1px solid var(--ui-border);
}
.ui-table th {
  font-size: var(--gemboss-fs-caption); font-weight: 600; color: var(--ui-text-muted); white-space: nowrap;
}
.ui-table tbody tr:last-child > td { border-bottom: 0; }
.ui-table tbody tr:hover { background: var(--ui-surface-2); }
.ui-table .is-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Empty state: `<div class="ui-empty"><p class="ui-empty__title">…</p><p class="ui-empty__body">…</p>
   <button class="ui-btn">…</button></div>`. Says what is missing and what to do next. */
.ui-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--ui-space-2);
  padding: var(--ui-space-4); padding-block: 40px; text-align: center;
  color: var(--ui-text-muted); font-size: var(--gemboss-fs-body);
}
.ui-empty__title { margin: 0; font-size: var(--gemboss-fs-h3); font-weight: 600; color: var(--ui-text-strong); }
.ui-empty__body { margin: 0; max-width: 48ch; line-height: 1.5; }
.ui-empty > .ui-btn { margin-top: var(--ui-space-2); }

/* ═══ gemboss-shell.css — allow-listed layout extract (rail + topbar + main) ═══ */
.icon-nav {
  position: fixed;
  top: 56px;
  left: 0;
  z-index: 200;
  width: 72px;
  height: calc(100dvh - 56px);
  background: var(--gemboss-rail-bg);
  border-right: 1px solid var(--gemboss-divider);
  display: flex;
  flex-direction: column;
  padding-top: 8px;
  overflow: hidden;
}
.gemboss-platform-main {
  box-sizing: border-box;
  min-height: 100dvh;
  margin-left: 72px;
  padding-top: 56px;
  background: var(--gemboss-app-bg);
}
.icon-nav {
  top: 56px;
  height: calc(100dvh - 56px);
  background: var(--gemboss-surface);
  border-right-color: var(--gemboss-divider);
}
@media (max-width: 1040px) {
  .gemboss-platform-topbar {
    grid-template-columns: minmax(120px, 1fr) minmax(220px, 520px) minmax(120px, 1fr);
  }
}
@media (max-width: 760px) {
  .gemboss-platform-main {
    margin-left: 0;
  }
}
.gemboss-platform-main {
  margin-top: 56px;
  margin-left: 72px;
  min-height: calc(100vh - 56px);
  padding: 24px;
  background: #fafafb;
}
@media (max-width: 768px) {
  .gemboss-platform-main {
    margin-left: 0;
    padding: 16px;
  }
}
.gemboss-platform-shell {
  display: block;
  min-height: 100vh;
  background: var(--gemboss-app-bg);
}
.gemboss-platform-topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 300;
  height: 56px;
  border-bottom: 1px solid var(--gemboss-divider);
  background: rgba(255, 255, 255, 0.98);
  display: grid;
  grid-template-columns: minmax(200px, 1fr) minmax(280px, 560px) minmax(200px, 1fr);
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  box-shadow: var(--gemboss-shadow-resting);
}
.icon-nav {
  position: fixed;
  top: 56px;
  left: 0;
  z-index: 200;
  width: 72px;
  height: calc(100dvh - 56px);
  border-right: 1px solid var(--gemboss-divider);
  background: var(--gemboss-surface);
  padding-top: 12px;
}
.gemboss-platform-main {
  min-height: calc(100vh - 56px);
  margin-top: 56px;
  margin-left: 72px;
  background: var(--gemboss-app-bg);
  padding: 24px;
}
@media (max-width: 1120px) {
  .gemboss-platform-topbar {
    grid-template-columns: 220px minmax(220px, 1fr) auto;
    gap: 12px;
  }
}
@media (max-width: 760px) {
  .gemboss-platform-topbar {
    height: auto;
    min-height: 56px;
    grid-template-columns: minmax(0, 1fr) auto;
    padding: 12px 12px;
  }
  .icon-nav {
    display: none;
  }
  .gemboss-platform-main {
    margin-left: 0;
    padding: 16px;
    padding-top: 104px;
  }
}
.gnav-scroll {
  scrollbar-width: thin;
  scrollbar-color: rgba(31,30,29,0.22) transparent;
}
.gemboss-platform-shell {
  --assistant-w: 384px;
}
@media (max-width: 760px) {
  .gemboss-platform-topbar {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 56px;
    min-height: 56px;
    padding: 0 12px;
  }
  .gemboss-platform-main {
    padding-top: 56px;
    padding-bottom: calc(56px + env(safe-area-inset-bottom));
  }
}
@media (pointer: coarse) {
  .gnav-item {
    min-height: 44px;
  }
}
.icon-nav {
  width: 240px;
  padding: 12px 12px 0;
  overflow: hidden;
  background: var(--gemboss-surface);
  display: flex;
  flex-direction: column;
}
.gnav-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
}
.gnav-bottom {
  padding-bottom: 12px;
}
.gnav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 8px 12px;
  margin: 1px 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
  border-radius: var(--gemboss-radius-md);
  text-decoration: none;
  font-family: inherit;
  color: var(--gemboss-text);
  font-size: var(--gemboss-fs-body);
  font-weight: 500;
  line-height: 1.2;
  transition: background-color var(--gemboss-transition-fast) ease, color var(--gemboss-transition-fast) ease;
}
.gnav-item:hover {
  background: rgba(20, 19, 18, 0.045);
}
.gnav-item.active {
  color: var(--gemboss-active-fg);
  font-weight: 600;
}
.gnav-group:not(.has-active-child) > .gnav-item.active {
  background: var(--gemboss-active-bg);
}
.gnav-group:not(.has-active-child) > .gnav-item.active:hover {
  background: var(--gemboss-active-bg);
}
.gnav-group.has-active-child > .gnav-item.active:hover {
  background: rgba(20, 19, 18, 0.045);
}
.gnav-ico {
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
}
.gnav-ico svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.gnav-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gnav-sub {
  list-style: none;
  margin: 1px 0 6px;
  padding: 0;
}
.gnav-subitem {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 12px 6px 44px;
  margin: 1px 0;
  border-radius: var(--gemboss-radius-sm);
  color: var(--gemboss-text-muted);
  font-size: 13px;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--gemboss-transition-fast) ease, color var(--gemboss-transition-fast) ease;
}
@media (pointer: coarse) {
  .gnav-subitem {
    min-height: 44px;
  }
}
.gnav-subitem:hover {
  background: rgba(20, 19, 18, 0.045);
  color: var(--gemboss-text);
}
.gnav-subitem.active {
  color: var(--gemboss-active-fg);
  font-weight: 600;
  background: var(--gemboss-active-bg);
}
.gnav-subitem.active:hover {
  background: var(--gemboss-active-bg);
  color: var(--gemboss-active-fg);
}
.gnav-subitem.active::before {
  content: "";
  position: absolute;
  left: 20px;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 15px;
  border-radius: 2px;
  background: var(--gemboss-primary);
}
.gnav-subitem.is-soon {
  opacity: 0.5;
  cursor: default;
}
.gnav-subitem em {
  font-style: normal;
  font-size: var(--gemboss-fs-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid var(--gemboss-divider);
  border-radius: var(--gemboss-radius-sm);
  padding: 1px 6px;
}
.gnav-sep {
  height: 1px;
  background: var(--gemboss-divider);
  margin: 8px 6px;
}
.gemboss-platform-main {
  margin-left: 240px;
}
.gemboss-mobile-menu-btn {
  display: none;
}
.gemboss-mobile-nav-backdrop {
  display: none;
}
@media (max-width: 760px) {
  .gemboss-platform-main {
    margin-left: 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .gemboss-mobile-menu-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    margin-left: -2px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    cursor: pointer;
    color: var(--gemboss-text);
  }
  .gemboss-mobile-menu-btn:active {
    background: var(--gemboss-hover);
  }
  .icon-nav {
    display: flex;
    width: min(82vw, 300px);
    transform: translateX(-100%);
    transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 1000;
    box-shadow: 2px 0 26px rgba(31, 30, 29, 0.20);
  }
  .gemboss-platform-shell.is-mobile-nav-open .icon-nav {
    transform: translateX(0);
  }
  .gemboss-mobile-nav-backdrop {
    display: block;
    position: fixed;
    inset: 56px 0 0 0;
    width: 100%;
    border: 0;
    padding: 0;
    background: rgba(20, 19, 18, 0.38);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease;
    z-index: 999;
  }
  .gemboss-platform-shell.is-mobile-nav-open .gemboss-mobile-nav-backdrop {
    opacity: 1;
    pointer-events: auto;
  }
}
@media (max-width: 305.98px) {
  .gemboss-platform-topbar {
    padding: 0 8px;
  }
}
@media (min-width: 306px) and (max-width: 460px) {
  .gemboss-platform-topbar {
    padding: 0 8px;
  }
  .gemboss-mobile-menu-btn {
    width: 44px;
    height: 44px;
  }
}
.gemboss-platform-shell {
  display: flow-root;
}
.gemboss-platform-main {
  padding-bottom: calc(24px + var(--gemboss-invite-h, 0px));
}
