/* ═══════════════════════════════════════════════════════════
   ChatMai UI kit — shared components on the app.css tokens.

   Every page used to draw its own buttons, chips, dialogs and empty states, each a little
   different and most without focus, pressed or disabled states. These are the one version of
   each. Flat (no gradient, no glass, no glow), hairline borders, 44px touch targets on coarse
   pointers, visible focus, and correct in both themes because they read tokens only.
   ═══════════════════════════════════════════════════════════ */

/* ── Utilities ─────────────────────────────────────────────── */
.sr-only {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    white-space: nowrap; border: 0;
}

.cm-skip-link {
    position: fixed; top: 0.5rem; left: 0.5rem; z-index: 3000;
    padding: 0.5rem 0.875rem;
    border-radius: var(--radius-sm);
    background: var(--accent-solid); color: var(--on-accent);
    font-weight: 600; font-size: var(--text-sm);
    transform: translateY(-150%);
    transition: transform var(--transition-fast);
}
.cm-skip-link:focus { transform: none; color: var(--on-accent); }

/* Focus that the app moves, not the reader: FocusOnNavigate puts it on the page heading and the
   skip link on <main> (both tabindex="-1") so screen readers start in the right place. That is not a
   control, so it gets no ring. Real controls keep :focus-visible from app.css. */
h1:focus, main:focus, [tabindex="-1"]:focus { outline: none; }

/* A button that looks like a link — "View all", "Manage", inline actions. */
.btn-link {
    display: inline-flex; align-items: center; gap: 0.25rem;
    padding: 0.375rem 0.5rem; margin: -0.375rem -0.5rem;
    border-radius: var(--radius-sm);
    background: none; border: 0;
    color: var(--link);
    font-size: var(--text-sm); font-weight: 600;
    text-decoration: none; cursor: pointer;
}
.btn-link:hover { background: var(--accent-light); color: var(--link); }

/* ── Buttons ───────────────────────────────────────────────── */
.cm-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
    min-height: var(--control-h);
    padding: 0 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font: 600 var(--text-base)/1.2 var(--font-sans);
    text-decoration: none; white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}
.cm-btn:active:not(:disabled) { transform: scale(0.98); }
.cm-btn:disabled, .cm-btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.cm-btn--primary { background: var(--accent-solid); color: var(--on-accent); }
.cm-btn--primary:hover:not(:disabled) { background: var(--accent-solid-hover); color: var(--on-accent); }
.cm-btn--secondary { background: var(--bg-surface); color: var(--text-primary); border-color: var(--border-default); }
.cm-btn--secondary:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--border-strong); color: var(--text-primary); }
.cm-btn--ghost { background: transparent; color: var(--text-secondary); }
.cm-btn--ghost:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); }
.cm-btn--danger { background: var(--accent-red); color: #fff; }
.cm-btn--danger:hover:not(:disabled) { background: #dc2626; color: #fff; }
.cm-btn--sm { min-height: var(--control-h-sm); padding: 0 0.75rem; font-size: var(--text-sm); }
.cm-btn--block { width: 100%; }
.cm-btn[aria-busy="true"] { cursor: progress; }

.cm-icon-btn {
    display: inline-grid; place-items: center;
    width: 36px; height: 36px; flex: none;
    border: 0; border-radius: var(--radius-sm);
    background: transparent; color: var(--text-secondary);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}
.cm-icon-btn:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); }
.cm-icon-btn--danger:hover:not(:disabled) { background: var(--accent-red-bg); color: var(--accent-red-text); }
.cm-icon-btn:disabled { opacity: 0.5; cursor: not-allowed; }

.cm-spinner {
    width: 1em; height: 1em; flex: none;
    border: 2px solid currentColor; border-right-color: transparent;
    border-radius: 50%;
    animation: cm-spin 0.7s linear infinite;
}
@keyframes cm-spin { to { transform: rotate(360deg); } }

/* ── Chips / filters / segmented control ─────────────────────
   Selection is aria-pressed (toggle) or aria-checked (radio group), and the selected look is
   keyed off that attribute — so the state a screen reader announces and the state you see
   cannot disagree. */
.cm-chip {
    display: inline-flex; align-items: center; gap: 0.375rem;
    min-height: var(--control-h-sm);
    padding: 0 0.75rem;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--bg-surface); color: var(--text-secondary);
    font: 600 var(--text-sm)/1 var(--font-sans);
    cursor: pointer;
}
.cm-chip:hover { border-color: var(--border-strong); color: var(--text-primary); }
.cm-chip[aria-pressed="true"], .cm-chip[aria-checked="true"], .cm-chip.is-selected {
    background: var(--accent-light); border-color: var(--accent-primary); color: var(--link);
}

/* ── Fields ────────────────────────────────────────────────── */
.cm-field { display: flex; flex-direction: column; gap: 0.375rem; min-width: 0; }
.cm-label { font-size: var(--text-sm); font-weight: 600; color: var(--text-primary); }
.cm-label .cm-required { color: var(--accent-red-text); margin-left: 0.125rem; }
.cm-hint { font-size: var(--text-xs); color: var(--text-muted); line-height: 1.5; }
.cm-field-error { font-size: var(--text-xs); color: var(--accent-red-text); font-weight: 600; }
.cm-input { width: 100%; min-height: var(--control-h); }
.cm-input[aria-invalid="true"] { border-color: var(--accent-red); }

/* ── Selectable option cards (radio semantics) ─────────────── */
.cm-option {
    display: flex; align-items: flex-start; gap: 0.75rem;
    width: 100%; padding: 1rem;
    text-align: left; font: inherit; color: var(--text-primary);
    background: var(--bg-surface);
    border: 1.5px solid var(--border-default);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--transition-fast), background-color var(--transition-fast);
}
.cm-option:hover { border-color: var(--border-strong); }
.cm-option[aria-checked="true"], .cm-option[aria-pressed="true"] {
    border-color: var(--accent-primary); background: var(--accent-light);
}

/* ── Alerts / inline feedback ──────────────────────────────── */
.cm-alert {
    display: flex; align-items: flex-start; gap: 0.625rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-default);
    background: var(--bg-secondary); color: var(--text-primary);
    font-size: var(--text-sm); line-height: 1.55;
}
.cm-alert--success { background: var(--accent-green-bg); border-color: transparent; color: var(--accent-green-text); }
.cm-alert--error   { background: var(--accent-red-bg);   border-color: transparent; color: var(--accent-red-text); }
.cm-alert--warning { background: var(--accent-amber-bg); border-color: transparent; color: var(--accent-amber-text); }
.cm-alert--info    { background: var(--accent-blue-bg);  border-color: transparent; color: var(--accent-blue-text); }
.cm-alert > iconify-icon, .cm-alert > .material-symbols-rounded { flex: none; margin-top: 0.125rem; }

/* ── Empty / loading states ────────────────────────────────── */
.cm-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 0.5rem; padding: 2.5rem 1.25rem; text-align: center;
    color: var(--text-secondary);
}
.cm-empty-icon {
    display: grid; place-items: center;
    width: 48px; height: 48px; border-radius: var(--radius-md);
    background: var(--bg-tertiary); color: var(--text-muted);
}
.cm-empty-title { margin: 0; font-size: var(--text-md); font-weight: 700; color: var(--text-primary); }
.cm-empty-text  { margin: 0; max-width: 28rem; font-size: var(--text-sm); color: var(--text-secondary); }

.cm-skeleton {
    display: block;
    border-radius: var(--radius-sm);
    background: var(--bg-tertiary);
    animation: cm-pulse 1.4s ease-in-out infinite;
}
@keyframes cm-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }

/* ── Dialog ────────────────────────────────────────────────── */
.cm-dialog-backdrop {
    position: fixed; inset: 0; z-index: 1500;
    display: grid; place-items: center;
    padding: 1rem;
    background: var(--overlay);
    animation: cm-fade 120ms ease-out;
}
.cm-dialog {
    width: min(100%, 28rem); max-height: calc(100dvh - 2rem);
    display: flex; flex-direction: column;
    overflow: auto;
    background: var(--bg-elevated); color: var(--text-primary);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    outline: none;
}
.cm-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; padding: 1.25rem 1.25rem 0.5rem; }
.cm-dialog-title { margin: 0; font-size: var(--text-lg); font-weight: 700; }
.cm-dialog-body { padding: 0.25rem 1.25rem 1rem; color: var(--text-secondary); font-size: var(--text-base); line-height: 1.6; }
.cm-dialog-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; padding: 0.75rem 1.25rem 1.25rem; }
@keyframes cm-fade { from { opacity: 0; } to { opacity: 1; } }

/* ── Popover menus built on <details data-cm-menu> ─────────── */
details[data-cm-menu] { position: relative; }
details[data-cm-menu] > summary { list-style: none; cursor: pointer; }
details[data-cm-menu] > summary::-webkit-details-marker { display: none; }
details[data-cm-menu] > summary::marker { content: ''; }

/* ── Image viewer ──────────────────────────────────────────── */
.cm-lightbox {
    position: fixed; inset: 0; z-index: 2500;
    display: grid; place-items: center;
    padding: 3.5rem 1rem 1rem;
    background: rgba(0, 0, 0, 0.9);
}
.cm-lightbox img { max-width: 100%; max-height: calc(100dvh - 5rem); object-fit: contain; border-radius: 8px; }
.cm-lightbox-bar { position: absolute; top: 0.75rem; right: 0.75rem; display: flex; gap: 0.5rem; }
.cm-lightbox-btn {
    display: inline-grid; place-items: center;
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(255, 255, 255, 0.16); color: #fff; border: 0; cursor: pointer; text-decoration: none;
}
.cm-lightbox-btn:hover { background: rgba(255, 255, 255, 0.28); color: #fff; }
.cm-lightbox-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* A thumbnail that opens the viewer: a real button with no chrome of its own. */
.cm-media-btn { display: block; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: inherit; max-width: 100%; }

/* ── Touch targets ────────────────────────────────────────────
   On a finger, small icon buttons grow to the 44px floor instead of being hit by guesswork. */
@media (pointer: coarse) {
    .cm-icon-btn { width: var(--touch-min); height: var(--touch-min); }
    .cm-btn, .cm-chip { min-height: var(--touch-min); }
    /* The older page buttons and fields (Settings, Team, Pricing, Activity log) get the same floor.
       !important because their scoped rules set a smaller fixed height. (Sweep 2026-09-28.) */
    .btn, a.btn, select.form-control, .form-control:not(textarea) { min-height: var(--touch-min) !important; }
    .btn-icon { min-width: var(--touch-min) !important; min-height: var(--touch-min) !important; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ── Dark theme patches for page styles that predate the tokens ── */
:root[data-theme="dark"] .modal-content,
:root[data-theme="dark"] .modal-card,
:root[data-theme="dark"] .confirm-dialog,
:root[data-theme="dark"] .confirm-box { background: var(--bg-elevated); color: var(--text-primary); }
:root[data-theme="dark"] img.brand-logo,
:root[data-theme="dark"] .legal-brand img { background: #fff; }

/* Language menu on the first-run screen, which has no sidebar. */
.welcome-lang { position: fixed; top: 0.75rem; right: 0.75rem; z-index: 60; }
@media (max-width: 640px) { .welcome-lang { position: static; display: flex; justify-content: flex-end; padding: 0.75rem 1rem 0; } }

/* ═══════════════════════════════════════════════════════════
   Phone and installed-app shell (increment 2, 2026-09-28)
   ═══════════════════════════════════════════════════════════ */

/* Notch and status bar. The page starts below the top inset and clears the side insets in
   landscape; fixed layers add the inset themselves. */
:root { --cm-safe-top: env(safe-area-inset-top, 0px); }
.page {
    padding-top: var(--cm-safe-top);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    box-sizing: border-box;
}
/* The status bar strip is painted in the page colour, above page content, so nothing can show
   through the clock however the page got there (an iOS scroll or keyboard pan). It is 0px tall
   wherever there is no top inset: desktop, Android, and iPhone Safari with its own toolbar.
   Drawers and dialogs (1000+) sit above it and add the inset themselves. */
body::before {
    content: ""; position: fixed; top: 0; left: 0; right: 0; z-index: 950;
    height: var(--cm-safe-top); background: var(--bg-app); pointer-events: none;
}
/* Typing in the app shell (chatmai-ui.js): the page is the visible part above the keyboard, so a
   focused field scrolls inside <article> instead of iOS panning the page under the status bar.
   The tab bar is behind the keyboard anyway. */
@media (max-width: 640.98px) {
    html.cm-kb-open .page { height: var(--cm-vvh, 100dvh); }
    html.cm-kb-open main { padding-bottom: 0; }
    html.cm-kb-open .bottom-nav { display: none; }
}
/* A dialog opened while typing (the Connect forms; the unsaved-changes question before the keyboard
   has gone) fits in the part above the keyboard, so its close button and buttons are not behind
   it. Not only narrow screens: on a phone on its side the keyboard leaves about 170px. */
html.cm-kb-open .cm-dialog-backdrop { bottom: auto; height: var(--cm-vvh, 100dvh); padding-bottom: 0.5rem; }
html.cm-kb-open .confirm-overlay { bottom: auto; height: var(--cm-vvh, 100dvh); padding-top: calc(1rem + var(--cm-safe-top)); padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); }
html.cm-kb-open .cm-dialog,
html.cm-kb-open .cm-dialog-backdrop > .modal-dialog { max-height: calc(var(--cm-vvh, 100dvh) - 1.5rem - var(--cm-safe-top)); }
html.cm-kb-open .confirm-overlay > .confirm-dialog { max-height: calc(var(--cm-vvh, 100dvh) - 2rem - var(--cm-safe-top)); overflow: auto; }
.cm-lightbox-bar { top: calc(0.75rem + var(--cm-safe-top)); }
.cm-lightbox { padding-top: calc(3.5rem + var(--cm-safe-top)); }
.cm-dialog-backdrop { padding-top: calc(1rem + var(--cm-safe-top)); padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); }

/* iOS zooms the page into any field under 16px and never zooms back out. */
@media (pointer: coarse) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
    select,
    textarea { font-size: max(16px, 1em) !important; }
}

/* The notification bell is fixed in the top-right corner. Page headers keep that corner free,
   so it never sits on Save, Refresh or Add. */
:root { --cm-bell-reserve: 60px; }
.page-header-sticky,
.page-header,
.sh-docs-hero,
.sod-hero,
.sales-settings-hero { padding-right: max(1rem, var(--cm-bell-reserve)) !important; }
@media (min-width: 641px) { :root { --cm-bell-reserve: 72px; } }
/* Scrolling down on a phone moves the bell out of the way (chatmai-ui.js, html.cm-bell-away). */
@media (max-width: 640.98px), (max-height: 500px) {
    .snc { transition: opacity 180ms ease, transform 180ms ease; }
    html.cm-bell-away .snc { opacity: 0; transform: translateY(-12px); pointer-events: none; }
}
@media (prefers-reduced-motion: reduce) { .snc { transition: none; } }

/* Welcome and legal pages are documents: they scroll (the app shell locks <body>). */
body:has(.welcome-shell),
body:has(.legal-shell) { overflow-y: auto; height: auto; }
.welcome-shell { padding-top: var(--cm-safe-top); padding-bottom: calc(6rem + env(safe-area-inset-bottom, 0px)); }
.legal-shell { padding-top: var(--cm-safe-top); padding-bottom: env(safe-area-inset-bottom, 0px); }

/* ── Toast: short confirmations such as "Copied" ── */
.cm-toast-host {
    position: fixed; left: 50%; transform: translateX(-50%); z-index: 2600;
    bottom: calc(1rem + var(--bottom-nav-height) + env(safe-area-inset-bottom, 0px));
    display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
    pointer-events: none;
}
@media (min-width: 641px) { .cm-toast-host { bottom: 1.5rem; } }
.cm-toast {
    max-width: min(28rem, calc(100vw - 2rem));
    padding: 0.625rem 1rem;
    border-radius: var(--radius-full);
    background: var(--text-primary); color: var(--bg-primary);
    font: 600 var(--text-sm)/1.4 var(--font-sans);
    box-shadow: var(--shadow-lg);
    animation: cm-fade 120ms ease-out;
}
.cm-toast--error { background: #dc2626; color: #fff; } /* 4.8:1; --accent-red is 3.4:1 */

/* ── App update and install prompts ── */
.cm-pwa-bar {
    position: fixed; z-index: 2400;
    left: max(0.75rem, env(safe-area-inset-left, 0px)); right: max(0.75rem, env(safe-area-inset-right, 0px));
    bottom: calc(0.75rem + var(--bottom-nav-height) + env(safe-area-inset-bottom, 0px));
    margin: 0 auto; max-width: 30rem;
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.75rem 0.75rem 0.75rem 1rem;
    background: var(--bg-elevated); color: var(--text-primary);
    border: 1px solid var(--border-default); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    font-size: var(--text-sm); line-height: 1.45;
}
@media (min-width: 641px) { .cm-pwa-bar { bottom: 1.25rem; left: auto; right: 1.25rem; } }
.cm-pwa-bar[hidden] { display: none; }
html.cm-notice-open #cm-main > article { padding-bottom: var(--cm-notice-space, 0px); }
.cm-pwa-bar p { margin: 0; flex: 1; }
.cm-pwa-bar strong { display: block; }
.cm-pwa-bar .cm-btn { min-height: var(--touch-min); }
.cm-pwa-bar .cm-pwa-close {
    display: grid; place-items: center; width: var(--touch-min); height: var(--touch-min); flex: none;
    border: 0; border-radius: var(--radius-full); background: none; color: var(--text-muted); cursor: pointer;
}
.cm-pwa-bar .cm-pwa-close:hover { background: var(--bg-secondary); color: var(--text-primary); }

/* Older Bootstrap-shaped dialogs (AI Settings docs and logs) inside the shared backdrop: never
   wider or taller than the screen, Close always reachable, code scrolls sideways inside itself. */
.cm-dialog-backdrop > .modal-dialog { width: min(100%, 48rem); max-height: calc(100dvh - 2rem - var(--cm-safe-top)); display: flex; margin: 0; }
.cm-dialog-backdrop .modal-content {
    display: flex; flex-direction: column; width: 100%; max-height: inherit; overflow: hidden;
    background: var(--bg-elevated); color: var(--text-primary);
    border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-xl);
}
.cm-dialog-backdrop .modal-header { position: sticky; top: 0; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 1rem 1.25rem; border-bottom: 1px solid var(--border-default); background: inherit; }
.cm-dialog-backdrop .modal-body { flex: 1; min-height: 0; overflow: auto; padding: 1rem 1.25rem; overscroll-behavior: contain; }
.cm-dialog-backdrop .modal-footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; padding: 0.75rem 1.25rem; border-top: 1px solid var(--border-default); }
.cm-dialog-backdrop pre { max-width: 100%; overflow-x: auto; white-space: pre; }
.cm-dialog-backdrop .btn-close { min-width: 44px; min-height: 44px; }

/* ── One filter chip (2026-09-30) ──
   Choosing which items a list shows looked like three different controls: indigo pills on Inbox,
   8px tinted boxes on Knowledge, and black pills on AI Questions that turned white in the dark
   theme, the loudest thing on that screen. Knowledge and AI Questions now use this one; Inbox's
   scoped rules draw the same active pill on its white list. Unselected chips sit on the grey page,
   so they keep a white fill and a hairline instead of Inbox's grey fill, which would vanish there. */
/* One row, always (2026-09-30): wrapping left "ทั้งหมด" alone on a second row of AI Questions at
   360px, which read as unfinished. The row scrolls sideways inside itself, never the page. An edge
   with more chips past it fades out (data-more, set by chatmai-ui.js, as on AI Settings), so a
   cut-off chip reads as "scroll for more". 4px of padding, taken back by the margin, keeps the
   focus ring inside the scroller's clip; scroll-padding keeps a focused or selected chip clear of
   the fade. */
.cm-chips {
    display: flex; flex-wrap: nowrap; gap: 6px; min-width: 0;
    margin: -4px -4px 12px; padding: 4px;
    overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scroll-padding-inline: 2.5rem; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.cm-chips::-webkit-scrollbar { display: none; }
.cm-chips[data-more="end"] {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}
.cm-chips[data-more="start"] {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to left, #000 calc(100% - 2.5rem), transparent);
}
.cm-chips[data-more="both"] {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
}
.cm-chip {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px; flex: none;
    min-height: var(--control-h-sm); padding: 6px 14px;
    border: 0; border-radius: var(--radius-full);
    background: var(--bg-primary); box-shadow: inset 0 0 0 1px var(--border-default);
    color: var(--text-secondary);
    font: 600 0.8125rem/1.3 var(--font-sans); white-space: nowrap; cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}
.cm-chip:hover { color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--border-strong); }
.cm-chip-filled { background: var(--bg-secondary); box-shadow: none; }
.cm-chip-filled:hover { background: var(--bg-tertiary); box-shadow: none; }
.cm-chip.active, .cm-chip[aria-pressed="true"] { background: var(--accent-solid); color: var(--on-accent); box-shadow: none; }
.cm-chip:focus-visible { outline: 2px solid var(--border-accent); outline-offset: 2px; }
.cm-chip-count {
    min-width: 1.25rem; padding: 0 6px; border-radius: var(--radius-full);
    background: var(--bg-tertiary); color: var(--text-secondary);
    font-size: 0.72rem; font-weight: 700; line-height: 1.25rem; text-align: center; opacity: 1; margin: 0;
}
.cm-chip.active .cm-chip-count, .cm-chip[aria-pressed="true"] .cm-chip-count { background: rgba(255, 255, 255, 0.22); color: var(--on-accent); }
@media (pointer: coarse) { .cm-chip { min-height: var(--touch-min); } }
@media (max-width: 640px) { .cm-chip { padding: 6px 12px; font-size: 0.75rem; } }

/* A page title's icon is the accent colour and keeps its size beside a title that wraps. */
.page-header-sticky .header-content h1 > svg,
.page-header-sticky .header-content h1 > .material-symbols-rounded { flex: none; color: var(--accent-primary); }
.page-header-sticky .header-content h1 > .material-symbols-rounded { font-size: 1em; }
@media (max-width: 640px) { .page-header-sticky .header-content h1 > .material-symbols-rounded { font-size: 22px; } }

/* Page headers with several actions wrap instead of pushing the page sideways. */
.header-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
/* Phones and short landscape phones: the page header scrolls with the page. Pinned, a title,
   subtitle and stacked actions took 140pt of an 844pt iPhone screen on every page. A page whose
   header holds an action that must stay in reach pins that action alone (AI Settings' Save). */
@media (max-width: 640px), (max-height: 500px) {
    .page-header-sticky { position: static; }
}
/* On a phone the page title is a title, not a card (2026-09-29). The white header card, with its
   border, shadow and padding, took 150-185px before any content on Dashboard, Connect and
   Settings, and read as one more card among the content cards. Now it sits on the page like the
   Inbox's title: 24px, a one-size subtitle, and the bell's corner still kept free. */
@media (max-width: 640px) {
    /* A page that takes its margins from .bento-dashboard alone (Connect, Analytics, Insights) had
       none on top: its title began 4px under the screen edge, where a Thai tone mark touched it,
       and Connect's cards sat 24px in against 16px elsewhere (2026-09-30). Pages that set their
       own padding (Dashboard, Knowledge, Settings, AI Settings) keep it: their rule is more specific. */
    .bento-dashboard { padding: 1rem 1rem 4rem; }
    .page-header-sticky {
        background: transparent; border: 0; box-shadow: none; border-radius: 0;
        padding-top: 0.25rem; padding-bottom: 0; padding-left: 0.25rem;
        margin-bottom: 1.25rem;
    }
    .page-header-sticky .header-content h1 { font-size: 1.5rem; line-height: 1.25; }
    .page-header-sticky .header-content h1 > svg { width: 22px; height: 22px; }
    .page-header-sticky .header-content .subtitle { font-size: 0.875rem; line-height: 1.5; margin-top: 0.25rem; }
    .header-actions { width: 100%; }
    .header-actions > .btn { flex: 1 1 auto; justify-content: center; }
}

/* ── Apple-Inspired Grouped Lists ───────────────────────────── */
.cm-grouped-section {
    margin-bottom: 2rem;
}
.cm-grouped-section-title {
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 0.5rem;
    padding-left: 1rem;
    letter-spacing: 0.05em;
}
.cm-grouped-list {
    background: var(--bg-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.cm-grouped-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    min-height: 44px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-surface);
}
.cm-grouped-row:last-child {
    border-bottom: none;
}
.cm-grouped-row.is-stacked {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 1rem;
}
.cm-grouped-row-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.cm-grouped-row-title {
    font-size: var(--text-base);
    color: var(--text-primary);
    font-weight: 500;
}
.cm-grouped-row-desc {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-top: 0.125rem;
}
.cm-grouped-row-control {
    flex: 0 0 auto;
    margin-left: 1rem;
}
.cm-grouped-row.is-stacked .cm-grouped-row-control {
    margin-left: 0;
    width: 100%;
}
.cm-grouped-footer {
    font-size: var(--text-sm);
    color: var(--text-muted);
    padding: 0.5rem 1rem;
    margin-top: 0.25rem;
    line-height: 1.4;
}

/* Toggles Apple-style */
.cm-toggle {
    appearance: none;
    -webkit-appearance: none;
    width: 50px;
    height: 44px;
    border: 0;
    padding: 0;
    background: transparent;
    border-radius: 15px;
    position: relative;
    cursor: pointer;
    outline: none;
    transition: background 0.25s ease-in-out;
}
.cm-toggle::before {
    content: '';
    position: absolute;
    inset: 7px 0;
    border-radius: 15px;
    background: var(--border-default);
    transition: background 0.25s ease-in-out;
}
.cm-toggle::after {
    content: '';
    position: absolute;
    top: 9px;
    left: 2px;
    width: 26px;
    height: 26px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    transition: transform 0.25s ease-in-out;
}
.cm-toggle:checked::before {
    background: var(--accent-green);
}
.cm-toggle:checked::after {
    transform: translateX(20px);
}
.cm-toggle:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}
.cm-toggle:disabled { opacity: .55; cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) {
    .cm-toggle, .cm-toggle::before, .cm-toggle::after { transition: none; }
}
@media (max-width: 768px) {
    :is(.page, .cm-section, .cm-dashboard, .aiops-page) :is(input:not([type="checkbox"]):not([type="radio"]), textarea, select),
    .cm-grouped-list :is(input:not([type="checkbox"]):not([type="radio"]), textarea, select) {
        font-size: 16px !important;
    }
}

/* ── Workspace page kit (2026-10-07) ─────────────────────────────
   Team, Team dashboard, Insights, Analytics, Sales Hub and Connect share these: a hairline panel
   with its own heading row, figure tiles, a proportional bar, a status pill and an initials
   avatar. Tokens only, so both themes follow the app's explicit choice. */
.cm-page-stack { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.cm-panel {
    min-width: 0;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-sm);
}
.cm-panel-head {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 0.5rem 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border-subtle);
}
.cm-panel-head > :first-child { min-width: 0; flex: 1 1 14rem; }
.cm-panel-title {
    margin: 0;
    display: flex; align-items: center; gap: 0.5rem;
    font-size: var(--text-md); font-weight: 700; line-height: 1.35; letter-spacing: -0.01em;
    color: var(--text-primary);
}
.cm-panel-title .cm-panel-count { font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.cm-panel-sub { margin: 0.125rem 0 0; font-size: var(--text-sm); line-height: 1.5; color: var(--text-muted); }
.cm-panel-body { padding: 1rem 1.25rem 1.25rem; }
.cm-panel-body > :first-child { margin-top: 0; }
.cm-panel-body > :last-child { margin-bottom: 0; }

.cm-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 11.5rem), 1fr));
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}
.cm-kpi {
    min-width: 0;
    display: flex; flex-direction: column; gap: 0.25rem;
    padding: 1rem 1.125rem;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-sm);
}
.cm-kpi-label {
    display: flex; align-items: center; gap: 0.375rem;
    margin: 0;
    font-size: var(--text-sm); font-weight: 600; line-height: 1.4;
    color: var(--text-secondary);
}
.cm-kpi-label > iconify-icon, .cm-kpi-label > .material-symbols-rounded { flex: none; color: var(--accent-primary); font-size: 18px; }
.cm-kpi-value {
    margin: 0;
    font-size: 1.75rem; font-weight: 700; line-height: 1.15; letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}
.cm-kpi-note { margin: 0; font-size: var(--text-xs); line-height: 1.5; color: var(--text-muted); }
.cm-kpi .cm-skeleton { height: 1.75rem; width: 4rem; border-radius: var(--radius-sm); }
@media (max-width: 640px) {
    .cm-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.625rem; }
    .cm-kpi { padding: 0.875rem; }
    .cm-kpi-value { font-size: 1.375rem; }
}

/* A bar that carries a share: the width comes from --pct, set from the data. */
.cm-bar { position: relative; height: 6px; border-radius: var(--radius-full); background: var(--bg-tertiary); overflow: hidden; }
.cm-bar > span { display: block; height: 100%; width: var(--pct, 0%); border-radius: inherit; background: var(--accent-primary); }

.cm-pill {
    display: inline-flex; align-items: center; gap: 0.25rem;
    min-height: 1.5rem; padding: 0.125rem 0.5rem;
    border-radius: var(--radius-full);
    font-size: var(--text-xs); font-weight: 600; line-height: 1.3; white-space: nowrap;
    background: var(--bg-secondary); color: var(--text-secondary);
}
.cm-pill > iconify-icon, .cm-pill > .material-symbols-rounded { flex: none; font-size: 14px; }
.cm-pill--ok { background: var(--accent-green-bg); color: var(--accent-green-text); }
.cm-pill--warn { background: var(--accent-amber-bg); color: var(--accent-amber-text); }
.cm-pill--danger { background: var(--accent-red-bg); color: var(--accent-red-text); }
.cm-pill--info { background: var(--accent-blue-bg); color: var(--accent-blue-text); }
.cm-pill--accent { background: var(--accent-light); color: var(--link); }

.cm-avatar {
    flex: none;
    width: 40px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    overflow: hidden;
    border-radius: 50%;
    background: var(--accent-light); color: var(--link);
    font-size: var(--text-base); font-weight: 700;
}
.cm-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cm-avatar--sm { width: 32px; height: 32px; font-size: var(--text-sm); }
