:root {
    --bg: #081120;
    --bg-soft: #101a33;
    --panel: rgba(15, 22, 43, 0.84);
    --panel-2: rgba(18, 27, 51, 0.96);
    --panel-border: rgba(255, 255, 255, 0.08);
    --text: #edf2ff;
    --muted: #a9b5d3;
    --primary: #6d8cff;
    --primary-strong: #8aa2ff;
    --success: #1bc47d;
    --warning: #f5a524;
    --danger: #f31260;
    --shadow: 0 30px 80px rgba(0, 0, 0, 0.34);
    --radius-xl: 28px;
    --radius-lg: 22px;
    --radius-md: 16px;
    --radius-sm: 12px;
    --max-width: 1280px;
    --admin-sidebar-width: 290px;

    /*
     * Tell the user-agent we are running a DARK theme. Modern browsers
     * (Chrome 81+, Firefox 96+, Safari 13+) use this hint to render
     * NATIVE controls — date pickers, scrollbar tracks, autofill
     * backgrounds, and the popover that appears when a <select>
     * dropdown opens — in their dark variants.
     *
     * Without this, the OS draws a white-background dropdown list with
     * a blue selection highlight inside our dark admin theme, which
     * was the jarring mismatch the user reported. With it, the
     * dropdown options inherit a dark surface matching the rest of
     * the chrome.
     */
    color-scheme: dark;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    min-height: 100%;
    height: 100%;
    font-family: Inter, "Segoe UI", Arial, sans-serif;
    background:
        radial-gradient(circle at top left, rgba(109, 140, 255, 0.22), transparent 28%),
        radial-gradient(circle at top right, rgba(0, 199, 255, 0.14), transparent 24%),
        linear-gradient(180deg, #07101f 0%, #0c1328 48%, #111b36 100%);
    color: var(--text);
}

body {
    min-height: 100vh;
}

body.admin-body {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    padding: 0;
}

/*
 * Desktop admin pages use an internal content scroller. Keeping the body fixed
 * to the viewport prevents overflow from an admin child from creating a second
 * document-level scroll range and exposing the root canvas below the shell.
 * Mobile intentionally returns to normal document scrolling at <=920px.
 */
@media (min-width: 921px) {
    body.admin-body {
        position: fixed;
        inset: 0;
        min-height: 0;
    }
}

a {
    color: inherit;
    text-decoration: none;
}

button,
input,
textarea,
select {
    font: inherit;
}

img {
    display: block;
    max-width: 100%;
}

pre {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: anywhere;
}

.app-shell {
    width: 100%;
    min-height: 100vh;
    padding: 24px;
}

.topbar {
    width: 100%;
    max-width: var(--max-width);
    margin: 0 auto 36px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 18px 22px;
    border: 1px solid var(--panel-border);
    background: rgba(12, 20, 40, 0.72);
    backdrop-filter: blur(16px);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    transition: 0.25s ease;
}

.brand {
    display: flex;
    align-items: center;
    gap: 14px;
}

.brand-logo,
.auth-logo {
    width: 46px;
    height: 46px;
    object-fit: contain;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.04);
    padding: 6px;
    flex-shrink: 0;
}

/*
 * Shared Admin brand mark. The frame owns the rounded presentation and safe
 * padding; the replaced image owns only aspect-ratio-preserving containment.
 * Keeping those responsibilities separate prevents uploaded artwork from
 * being clipped by a border radius or compressed by padding on the <img>.
 */
.admin-brand-logo-frame {
    width: 52px;
    height: 52px;
    padding: 5px;
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    border-radius: 15px;
    background: rgba(255, 255, 255, 0.04);
    overflow: hidden;
}

.sidebar-logo,
.admin-mobile-brand-logo {
    display: block;
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    max-width: 100%;
    max-height: 100%;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    object-fit: contain;
    object-position: center;
}

.brand-copy,
.sidebar-brand-copy {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.brand-title,
.sidebar-title,
.auth-brand-title {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.brand-subtitle,
.sidebar-subtitle,
.auth-brand-subtitle {
    font-size: 0.86rem;
    color: var(--muted);
}

.topbar-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.primary-link,
.ghost-button,
.button,
.table-link {
    border: 0;
    cursor: pointer;
    transition: 0.25s ease;
}

.primary-link,
.button-primary,
.table-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 18px;
    border-radius: 999px;
    font-weight: 700;
    color: #ffffff;
    background: linear-gradient(135deg, var(--primary), var(--primary-strong));
    box-shadow: 0 12px 28px rgba(109, 140, 255, 0.28);
    /* Keep short admin labels (e.g. "Back to Files", "Export Excel")
       on a single line; their text is short by design so this never
       overflows the container. */
    white-space: nowrap;
}

.primary-link:hover,
.button-primary:hover,
.table-link:hover {
    transform: translateY(-1px);
    filter: brightness(1.04);
}

.ghost-button,
.button-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 18px;
    border-radius: 999px;
    font-weight: 700;
    color: var(--text);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    /* Match .button-primary so short labels never wrap inside the pill. */
    white-space: nowrap;
}

.ghost-button:hover,
.button-secondary:hover {
    transform: translateY(-1px);
    background: rgba(255, 255, 255, 0.07);
}

/*
 * Disabled-state modifier used by paginators (Previous/Next when there
 * is no adjacent page) and any other admin control that should render
 * as a flat, non-interactive button. Keeping this as a class instead
 * of inline styles makes the dimming consistent across the admin and
 * removes the need for `style="..."` markup duplication.
 */
.button.is-disabled,
.button-secondary.is-disabled,
.ghost-button.is-disabled,
.primary-link.is-disabled {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
    transform: none;
    filter: none;
}

/*
 * Keyboard-focus visibility for every clickable surface in the admin
 * chrome. Required by WCAG 2.1 SC 2.4.7 (Focus Visible) — without
 * this rule the buttons / links / table-link CTAs above had a `:hover`
 * state but NO focus indicator, so a keyboard-tabbing operator could
 * not tell which control was active.
 *
 * `:focus-visible` (not `:focus`) is deliberate: it scopes the ring
 * to keyboard users only, so mouse clicks don't leave a lingering
 * blue ring behind (which the design language prefers to avoid). The
 * ring uses the same brand-coloured glow as `.form-input:focus`
 * (line ~568) so the focus signal reads as a single coherent system
 * across forms and actions.
 */
.button:focus-visible,
.button-primary:focus-visible,
.button-secondary:focus-visible,
.ghost-button:focus-visible,
.primary-link:focus-visible,
.table-link:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(109, 140, 255, 0.45),
        0 0 0 6px rgba(109, 140, 255, 0.18);
}

.inline-form {
    margin: 0;
}

.hero-layout {
    width: 100%;
    max-width: var(--max-width);
    margin: 0 auto;
}

.hero-card {
    border: 1px solid var(--panel-border);
    background: var(--panel);
    backdrop-filter: blur(16px);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow);
    padding: 44px;
}

.hero-badge,
.auth-badge,
.section-kicker,
.settings-meta-badge {
    display: inline-flex;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(109, 140, 255, 0.14);
    border: 1px solid rgba(109, 140, 255, 0.22);
    color: #dbe3ff;
    font-size: 0.82rem;
    margin-bottom: 18px;
    max-width: 100%;
    word-break: break-word;
}

.hero-card h1,
.auth-copy h1,
.page-header h1 {
    margin: 0 0 16px;
    font-size: clamp(2rem, 4vw, 3.2rem);
    line-height: 1.05;
    letter-spacing: -0.03em;
    overflow-wrap: anywhere;
}

.hero-text,
.auth-copy p,
.page-header p {
    margin: 0;
    max-width: 780px;
    color: var(--muted);
    font-size: 1.02rem;
    line-height: 1.8;
    overflow-wrap: anywhere;
}

.hero-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
    margin-top: 34px;
}

.feature-card,
.panel-card,
.stat-card,
.chunk-card,
.summary-box,
.source-card {
    padding: 22px;
    border-radius: var(--radius-lg);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    min-width: 0;
}

.feature-card h3,
.panel-head h2,
.chunk-card h3,
.settings-section h3 {
    margin: 0 0 10px;
    font-size: 1.05rem;
    overflow-wrap: anywhere;
}

.settings-subsection-heading {
    grid-column: 1 / -1;
    margin-top: 4px;
    padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.settings-subsection-heading:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.settings-subsection-heading h4 {
    margin: 0;
    color: var(--muted);
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0;
}

.feature-card p,
.panel-head p,
.chunk-card p,
.summary-box p,
.source-card p {
    margin: 0;
    color: var(--muted);
    line-height: 1.7;
    font-size: 0.96rem;
    overflow-wrap: anywhere;
}

.hero-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 28px;
}

.status-pill,
.badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    padding: 0 12px;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 700;
    max-width: 100%;
    text-align: center;
}

.status-pill,
.badge.success {
    color: #dcffea;
    background: rgba(27, 196, 125, 0.12);
    border: 1px solid rgba(27, 196, 125, 0.18);
}

.badge.neutral {
    color: var(--text);
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.badge.warning {
    color: #fff2d5;
    background: rgba(245, 165, 36, 0.14);
    border: 1px solid rgba(245, 165, 36, 0.22);
}

.badge.danger {
    color: #ffdfe9;
    background: rgba(243, 18, 96, 0.14);
    border: 1px solid rgba(243, 18, 96, 0.22);
}

.auth-body {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 28px;
}

.auth-shell {
    width: 100%;
    max-width: 560px;
}

.auth-card {
    border: 1px solid var(--panel-border);
    background: var(--panel);
    backdrop-filter: blur(18px);
    border-radius: 28px;
    box-shadow: var(--shadow);
    overflow: hidden;
}

.auth-card-inner {
    padding: 34px;
}

.auth-brand {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 24px;
}

.auth-copy {
    margin-bottom: 24px;
}

.auth-form,
.upload-form,
.settings-form {
    display: grid;
    gap: 18px;
    min-width: 0;
}

.form-group {
    display: grid;
    gap: 10px;
    min-width: 0;
}

.form-grid,
.filter-grid,
.settings-section-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: 18px;
    min-width: 0;
}

.filter-grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr) auto;
    align-items: end;
}

.form-label {
    font-size: 0.92rem;
    color: var(--text);
    font-weight: 600;
}

.form-input {
    width: 100%;
    min-width: 0;
    min-height: 52px;
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    padding: 0 16px;
    outline: none;
    transition: 0.22s ease;
    unicode-bidi: plaintext;
    text-align: start;
}

textarea.form-input,
.form-textarea {
    min-height: 112px;
    padding-top: 14px;
    padding-bottom: 14px;
    resize: vertical;
}

.form-file-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    opacity: 0;
    overflow: hidden;
    white-space: nowrap;
}

.file-picker {
    width: 100%;
    min-width: 0;
    min-height: 52px;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px;
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.04);
    transition: border-color 0.22s ease, box-shadow 0.22s ease, background 0.22s ease;
}

.file-picker:focus-within {
    border-color: rgba(109, 140, 255, 0.72);
    box-shadow: 0 0 0 4px rgba(109, 140, 255, 0.12);
}

.file-picker-button {
    min-height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    padding: 0 14px;
    border-radius: 12px;
    color: var(--text);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.12);
    font-weight: 700;
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.file-picker-button:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.18);
}

.file-picker-button:active {
    transform: translateY(1px);
}

.file-picker-name {
    min-width: 0;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-picker.has-file .file-picker-name {
    color: var(--text);
}

.form-input::placeholder {
    color: #8f9bbc;
}

.form-input:focus {
    border-color: rgba(109, 140, 255, 0.72);
    box-shadow: 0 0 0 4px rgba(109, 140, 255, 0.12);
}

/*
 * ===================================================================
 * Native <select> dark-theme treatment
 * ===================================================================
 * Two layers of styling are needed for a `<select>` to look native to
 * the dark admin chrome:
 *
 * 1. The TRIGGER (the closed select control)
 *      `appearance: none` strips the OS default arrow + chrome;
 *      a hand-rolled SVG arrow is painted via `background-image` so
 *      every browser shows the SAME caret regardless of platform.
 *
 * 2. The POPOVER (the open dropdown list)
 *      `color-scheme: dark` tells the browser to render the popover
 *      in its dark variant — dark background, light text, primary-
 *      tinted hover highlight. Without this hint, every OS draws its
 *      default LIGHT popover (white background + blue Windows-style
 *      selection) which clashed with our dark admin theme.
 *      The matching `option { ... }` rule below only applies in
 *      browsers that style native options (Firefox + Chromium fall
 *      back to the OS popover so the color-scheme hint is the
 *      primary lever).
 */
select.form-input {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;

    /* Custom chevron — same look across every OS / browser. */
    background-color: rgba(255, 255, 255, 0.04);
    background-image: url("data:image/svg+xml;charset=utf-8,\
%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'\
%3E%3Cpath d='M5 8l5 5 5-5' stroke='%23a9b5d3' stroke-width='1.8'\
stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 14px 14px;
    /* Reserve room on the inline-end edge so the chevron never
       overlaps the rendered value text. Logical property mirrors
       cleanly for RTL contexts. */
    padding-inline-end: 38px;
    color: var(--text);
    /* Render the popover with the dark theme so it stops drawing as
       a white box with blue selection. */
    color-scheme: dark;
    /* Brand-tint the OS-drawn highlight that paints inside the open
       dropdown. Chromium 93+ / Firefox 92+ honour `accent-color` for
       native form controls — without it, Windows fell back to the
       system highlight color (often near-white on light accents),
       which made the hovered option appear as unreadable white-on-
       white inside our dark popover. */
    accent-color: var(--primary);
    cursor: pointer;
}

/* RTL chevron sits on the visual LEFT — auto-handled by background
   logical positioning in modern browsers via the `right` keyword
   which already maps to inline-end. We add an explicit RTL override
   for Safari < 16.4 which still treats `right` as physical. */
[dir="rtl"] select.form-input {
    background-position: left 14px center;
    padding-inline-end: 38px;
    padding-inline-start: 14px;
}

/*
 * Options styled for the dark theme.
 *
 * Browsers honour these rules at varying levels (Firefox respects
 * most properties on options; Chromium honours background-color +
 * color when paired with `color-scheme: dark` + `accent-color` on
 * the select). The two big rules that MUST hold for cross-browser
 * readability:
 *
 *   1. Use fully OPAQUE `background-color` (not `rgba(... .18)`).
 *      A semi-transparent overlay over an OS-rendered white popover
 *      strip — which Windows draws on hover when `accent-color` is
 *      absent or unsupported — produced unreadable white-on-white
 *      "ghost" text. Fully opaque colors make the row legible even
 *      if the OS painted its own highlight underneath.
 *
 *   2. Force text color to `#fff` on the active row. Some Chromium
 *      builds repaint option text in the system selection color,
 *      which clashed with the brand-blue hover surface.
 */
select.form-input option {
    background-color: #121b33;   /* opaque equivalent of --panel-2 */
    color: var(--text);
}

select.form-input option:checked,
select.form-input option:hover,
select.form-input option:focus {
    background-color: var(--primary);
    color: #ffffff;
    font-weight: 600;
}

/*
 * Date / time / datetime inputs ship a native picker whose styling
 * follows `color-scheme`. We already declared `color-scheme: dark` on
 * `:root`, but keep the explicit declaration here so removing the
 * global hint in the future never silently regresses the picker.
 */
input[type="date"].form-input,
input[type="datetime-local"].form-input,
input[type="time"].form-input,
input[type="month"].form-input,
input[type="week"].form-input {
    color-scheme: dark;
}

.button {
    min-height: 48px;
    border-radius: 999px;
    padding: 0 18px;
    font-weight: 700;
}

.button-block {
    width: 100%;
}

.message-stack,
.toast-stack {
    display: grid;
    gap: 8px;
}

.message-stack {
    margin-bottom: 18px;
}

/* Floating notification stack — pinned top-right but offset down so it
   never lands on top of the page-header controls (segmented-control,
   primary CTA). Tight max width keeps short messages compact; long
   messages still wrap inside the same column. */
.toast-stack {
    position: fixed;
    top: 88px;
    right: 20px;
    z-index: 999;
    width: min(320px, calc(100% - 32px));
    pointer-events: none;  /* container is transparent; items re-enable */
}

.message-banner,
.toast-item {
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 0.875rem;
    line-height: 1.45;
    border: 1px solid transparent;
}

/* Toasts get a real shadow + slightly more solid background so they
   read as a discrete notification rather than a glowing card. The
   blur stays subtle (6px) — enough for glassy depth, not enough to
   bleed into surrounding controls. */
.toast-item {
    pointer-events: auto;
    box-shadow: 0 10px 28px -12px rgba(2, 6, 23, 0.55),
                0 2px 6px rgba(2, 6, 23, 0.35);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* Inline banners (login page) keep a slightly stronger blur because
   they sit inside the auth card frame, not floating over content. */
.message-banner {
    backdrop-filter: blur(12px);
}

.message-banner.success,
.toast-item.success {
    background: rgba(27, 196, 125, 0.22);
    border-color: rgba(27, 196, 125, 0.32);
    color: #e9fff4;
}

.message-banner.error,
.toast-item.error {
    background: rgba(243, 18, 96, 0.22);
    border-color: rgba(243, 18, 96, 0.32);
    color: #ffe6ee;
}

.message-banner.warning,
.toast-item.warning {
    background: rgba(245, 165, 36, 0.22);
    border-color: rgba(245, 165, 36, 0.32);
    color: #fff4d8;
}

.message-banner.info,
.toast-item.info,
.message-banner.debug,
.toast-item.debug {
    background: rgba(109, 140, 255, 0.22);
    border-color: rgba(109, 140, 255, 0.32);
    color: #ecf0ff;
}

.form-help-text {
    font-size: 0.83rem;
    color: var(--muted);
    line-height: 1.5;
}

/*
 * Settings two-column grids: reserve a consistent two-line height for
 * help text so a 1-line hint in one column and a 2-line hint in the
 * other don't desynchronise inputs within a row (and don't shift the
 * next row). Same approach already used by `.upload-fields-grid
 * .form-help-text`; kept as a single scoped rule (no per-field inline
 * styles, no duplication).
 */
.settings-section-grid .form-help-text,
.form-grid .form-help-text {
    margin: 0;
    min-height: 2.5em;
}

.field-error {
    color: #ffb6cb;
    font-size: 0.86rem;
    overflow-wrap: anywhere;
}

.field-warning {
    color: var(--warning);
    font-size: 0.86rem;
    overflow-wrap: anywhere;
}

.form-group-full {
    grid-column: 1 / -1;
}

.checkbox-group {
    align-content: end;
}

.settings-availability-controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
        "widget preview"
        "demo demo";
    align-items: start;
    gap: 16px;
    min-width: 0;
}

.settings-availability-widget {
    grid-area: widget;
}

.settings-availability-demo {
    grid-area: demo;
}

.settings-availability-preview {
    grid-area: preview;
}

.settings-brand-color-field .form-color-input {
    max-inline-size: min(100%, 48rem);
}

.settings-brand-color-field .form-help-text {
    inline-size: 100%;
    max-inline-size: none;
    text-wrap: pretty;
}

.checkbox-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 52px;
    padding: 0 16px;
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.04);
}

.checkbox-row input {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.settings-section {
    display: grid;
    gap: 16px;
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.settings-section:first-of-type {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/*
 * `.settings-stats-grid` used to override the base `.stats-grid` with
 * an `auto-fit` layout. Those rules have been promoted to the base
 * `.stats-grid` selector (see "Universal stats grid" further down) so
 * every page in the app gets the same modern card treatment without
 * duplicating CSS. The class is still applied in the HTML as a
 * page-level marker — useful for adding future settings-only tuning.
 */

.settings-dashboard-grid {
    grid-template-columns: minmax(0, 1.65fr) minmax(340px, 0.95fr);
    gap: 20px;
}

.settings-editor-card,
.settings-snapshot-card {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.032)),
        rgba(12, 20, 40, 0.76);
    border-color: rgba(255, 255, 255, 0.1);
}

/* ===================================================================
 * Bidi/direction helpers for admin content.
 * Admin CHROME stays English/LTR; CONTENT inside records can be Arabic or
 * English and must render in its own natural direction. `.bidi-auto` lets the
 * browser pick direction per content (Arabic→RTL, English→LTR, mixed→first
 * strong glyph). `.technical-value` keeps IDs/UUIDs/URLs/emails/JSON LTR and
 * isolated so an adjacent Arabic run can't reorder them.
 * (Human-text elements also carry `dir="auto"` for non-CSS contexts.)
 * =================================================================== */
.bidi-auto,
.human-text-cell {
    unicode-bidi: plaintext;
    text-align: start;
}
.technical-value {
    direction: ltr;
    unicode-bidi: isolate;
    text-align: start;
}
/* In a human-text table cell the reveal fills the cell and aligns to the content's start edge, so an
   Arabic title right-aligns naturally (RTL) and an English title left-aligns (LTR) — the truncation and
   the hover/focus overlay then read correctly in either direction. */
.human-text-cell .truncate-reveal--text {
    display: block;
    width: 100%;
    text-align: start;
}

.settings-editor-form {
    counter-reset: settings-section;
}

/* ===================================================================
 * Branding asset cards (Bot Settings → Branding).
 * One polished card per asset (Site Logo / Chat Logo / Favicon) showing the
 * uploaded-or-default state, a preview, the current file / fallback path, the
 * upload/replace control, and a labelled remove (Clear) control.
 * =================================================================== */
.brand-assets-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
    margin-top: 6px;
}
.brand-asset-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
}
.brand-asset-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.brand-asset-title {
    font-weight: 700;
    color: var(--text);
}
.brand-asset-status {
    font-size: 0.72rem;
    font-weight: 700;
    padding: 2px 9px;
    border-radius: 999px;
    white-space: nowrap;
}
.brand-asset-status.is-uploaded {
    color: #c7f9d9;
    background: rgba(46, 160, 87, 0.18);
    border: 1px solid rgba(46, 160, 87, 0.4);
}
.brand-asset-status.is-default {
    color: var(--muted);
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.12);
}
.brand-asset-status.is-missing {
    color: #ffd7b0;
    background: rgba(220, 120, 40, 0.18);
    border: 1px solid rgba(220, 120, 40, 0.45);
}
.brand-asset-warning {
    color: #ffd7b0;
}
.brand-asset-preview-box {
    display: grid;
    place-items: center;
    min-height: 76px;
    padding: 10px;
    border-radius: 10px;
    background: rgba(15, 23, 42, 0.5);
    border: 1px dashed rgba(255, 255, 255, 0.12);
}
.brand-asset-preview {
    max-width: 100%;
    max-height: 56px;
    width: auto;
    height: auto;
    object-fit: contain;
}
.brand-asset-preview-sm {
    max-height: 40px;
}
.brand-asset-meta {
    margin: 0;
    font-size: 0.78rem;
    color: var(--muted);
    word-break: break-all;
}
.brand-asset-meta code {
    direction: ltr;
    unicode-bidi: isolate;
}
/* Custom branding file control (BrandingFileInput): a labelled remove checkbox + the upload input,
   replacing Django's default run-on file-widget layout. */
.brand-asset-actions {
    font-size: 0.8rem;
    color: var(--muted);
    line-height: 1.6;
}
.brand-asset-clear {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 8px;
    font-size: 0.78rem;
    color: var(--muted);
    cursor: pointer;
}
.brand-asset-clear input[type="checkbox"] {
    margin: 0;
    flex: 0 0 auto;
}
.brand-asset-file {
    display: block;
    width: 100%;
    font-size: 0.8rem;
    color: var(--muted);
}
.brand-asset-help {
    margin: 0;
    font-size: 0.74rem;
    color: var(--muted);
}

.settings-editor-form .settings-section {
    gap: 18px;
    margin-top: 28px;
    padding-top: 24px;
}

/* The numbered badge is the FIRST flex item inside the summary row (a `::before` on a flex
   container is itself a flex item), so it sits on one horizontal line with the title and chevron
   and is vertically centred by the summary's `align-items: center` — identical for every section
   (01, 02, 03, …), with spacing controlled by the shared flex layout rather than absolute
   positioning or per-section offsets. */
.settings-editor-form .settings-section > .settings-section-summary::before {
    counter-increment: settings-section;
    content: counter(settings-section, decimal-leading-zero);
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: 10px;
    color: #e8edff;
    background: rgba(109, 140, 255, 0.15);
    border: 1px solid rgba(109, 140, 255, 0.24);
    font-size: 0.78rem;
    font-weight: 800;
    /* `line-height: 1` centres the digit pair ("01", "02", …) by its own glyph box rather than a
       leading-padded line-box, for pixel-accurate vertical centring inside the 32×32 pill. */
    line-height: 1;
    /* Tabular figures keep "01" / "10" the same visual width across sections. */
    font-variant-numeric: tabular-nums;
}

.settings-editor-form .settings-section h3 {
    margin-bottom: 2px;
    color: #f6f8ff;
    font-size: 1rem;
}

.settings-editor-form .settings-section-grid {
    gap: 16px;
}

.settings-editor-form .form-group {
    gap: 8px;
}

.settings-editor-form .form-label {
    color: #dfe6ff;
}

.settings-editor-form .form-input,
.settings-editor-form .checkbox-row {
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.035);
}

.settings-editor-form .checkbox-row {
    align-items: center;
    justify-content: flex-start;
    min-height: 54px;
}

.settings-editor-form .checkbox-row span {
    min-width: 0;
    overflow-wrap: anywhere;
}

.settings-save-bar {
    position: static;
    margin: 18px 0 0;
    padding: 20px 0 0;
    align-items: center;
    justify-content: flex-end;
    background: transparent;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    backdrop-filter: none;
}

.settings-snapshot-card {
    position: sticky;
    top: 28px;
    max-height: calc(100vh - 56px);
    overflow-y: auto;
}

.settings-snapshot-grid {
    gap: 18px;
}

.settings-snapshot-group {
    display: grid;
    gap: 10px;
    min-width: 0;
}

.settings-snapshot-group h3 {
    margin: 0;
    color: #dfe6ff;
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0;
}

.settings-snapshot-group .detail-row {
    padding: 12px 14px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.035);
}

.settings-snapshot-group .detail-row strong {
    color: #f6f8ff;
}

.admin-layout {
    height: 100%;
    min-height: 0;
    display: grid;
    grid-template-columns: var(--admin-sidebar-width) minmax(0, 1fr);
    overflow: hidden;
}

/* ===========================================================
   Mobile topbar + slide-in sidebar + backdrop.
   These three elements are display:none on desktop (≥921px) so
   they don't take grid cells. The @media (max-width:920px)
   block at the bottom of this file flips them on and converts
   the sidebar into a fixed slide-in panel toggled via JS.
   =========================================================== */

.admin-mobile-topbar,
.admin-sidebar-backdrop {
    display: none;
}

.admin-sidebar-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    cursor: pointer;
    transition: background 180ms ease, border-color 180ms ease;
}

.admin-sidebar-toggle:hover {
    background: rgba(255, 255, 255, 0.07);
    border-color: rgba(255, 255, 255, 0.16);
}

/* Keyboard focus ring for the mobile-sidebar hamburger toggle —
   matches the same brand glow used by the rest of the admin chrome. */
.admin-sidebar-toggle:focus-visible {
    outline: none;
    border-color: rgba(109, 140, 255, 0.55);
    box-shadow: 0 0 0 3px rgba(109, 140, 255, 0.22);
}

.admin-sidebar-toggle-icon {
    display: inline-flex;
    width: 22px;
    height: 22px;
}

.admin-sidebar-toggle-icon svg {
    width: 100%;
    height: 100%;
    display: block;
}

.admin-brand-logo-frame--mobile {
    width: 34px;
    height: 34px;
    padding: 3px;
    border-radius: 9px;
}

.admin-mobile-brand-title {
    font-weight: 700;
    font-size: 0.96rem;
    color: var(--text);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.admin-sidebar {
    position: sticky;
    top: 0;
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 24px;
    border-right: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(10, 16, 31, 0.9);
    backdrop-filter: blur(18px);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 20px;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.sidebar-nav {
    display: grid;
    gap: 8px;
    margin-top: 24px;
}

.sidebar-link {
    min-height: 46px;
    display: flex;
    align-items: center;
    padding: 0 14px;
    border-radius: 14px;
    color: var(--muted);
    border: 1px solid transparent;
    transition: 0.22s ease;
    overflow-wrap: anywhere;
}

.sidebar-link:hover,
.sidebar-link.is-active {
    color: var(--text);
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.08);
}

/*
 * Keyboard-focus ring for sidebar navigation links. Same WCAG SC 2.4.7
 * reasoning as the global `:focus-visible` rule above on `.button` —
 * navigation links also need a clear keyboard indicator that the
 * `:hover` background alone does not provide.
 */
.sidebar-link:focus-visible {
    outline: none;
    color: var(--text);
    border-color: rgba(109, 140, 255, 0.55);
    box-shadow: 0 0 0 3px rgba(109, 140, 255, 0.22);
}

.sidebar-footer {
    display: grid;
    gap: 16px;
}

.sidebar-user {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    min-width: 0;
}

.sidebar-user:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.1);
}

.sidebar-user-avatar {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-weight: 700;
    background: linear-gradient(135deg, var(--primary), var(--primary-strong));
    color: white;
    flex-shrink: 0;
}

.sidebar-user-name {
    font-weight: 700;
    overflow-wrap: anywhere;
}

.sidebar-user-role {
    color: var(--muted);
    font-size: 0.88rem;
}

.admin-content {
    height: 100%;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 28px;
}

.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    margin-bottom: 24px;
}

.page-header > div,
.page-header-actions {
    min-width: 0;
}

.page-header-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.segmented-control {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 44px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(109, 140, 255, 0.08);
    border: 1px solid rgba(109, 140, 255, 0.16);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.segmented-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 54px;
    /* WCAG 2.5.5 touch target — keeps the dashboard range pills (Today / 7d / 30d / 90d)
       reachable on mobile finger-taps without dancing between adjacent options. */
    min-height: 44px;
    padding: 0 14px;
    border-radius: 999px;
    color: #c5cff0;
    font-weight: 800;
    line-height: 1;
    white-space: nowrap;
    transition: 0.18s ease;
}

.segmented-option:hover,
.segmented-option.is-active {
    color: #ffffff;
    background: linear-gradient(135deg, rgba(109, 140, 255, 0.34), rgba(138, 162, 255, 0.24));
}

.segmented-option.is-active {
    box-shadow: 0 10px 24px rgba(109, 140, 255, 0.22);
}

/* Keyboard focus ring for the segmented filter controls. */
.segmented-option:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(109, 140, 255, 0.45),
        0 0 0 6px rgba(109, 140, 255, 0.18);
}

/*
 * ===================================================================
 * Universal stats grid (modern enterprise SaaS pattern)
 * ===================================================================
 * Single source of truth for every stat-card layout across the app —
 * settings, dashboard, conversations, knowledge files, widget preview,
 * upload, etc. The grid uses `auto-fit + minmax(220px, 1fr)` so cards
 * naturally reflow at every viewport with no manual media-query
 * juggling. Each card is a flex column so the value floats to the
 * vertical centre and the note sits flush at the bottom, giving the
 * whole row a single visual baseline even when content lengths vary.
 *
 * Typography + interaction rhythm: small uppercase label, large value, muted helper note, with a gentle
 * hover lift.
 *
 * Page-specific modifiers (`.dashboard-stats-grid`, etc.) add
 * additional tuning on top without re-implementing the base.
 */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
    align-items: stretch;
}

.stats-grid .stat-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 18px 20px;
    min-height: 132px;
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid rgba(255, 255, 255, 0.07);
    transition: background-color 180ms ease, border-color 180ms ease, transform 180ms ease;
}

.stats-grid .stat-card:hover {
    background: rgba(255, 255, 255, 0.055);
    border-color: rgba(255, 255, 255, 0.12);
    transform: translateY(-1px);
}

.stats-grid .stat-label {
    font-size: 0.74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    margin: 0;
}

/*
 * Big numeric values (Top K, Min Score, message counts, etc.).
 * `flex: 1 1 auto` pushes the note down so all baselines align.
 */
.stats-grid .stat-value {
    font-size: clamp(1.6rem, 1.8vw, 2rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text);
    line-height: 1.1;
    margin: 0;
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    overflow-wrap: anywhere;
}

/* Short string / status values (Bot Name, "Enabled", date strings). */
.stats-grid .stat-value.stat-small {
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.35;
    letter-spacing: -0.01em;
    word-break: break-word;
}

.stats-grid .stat-note {
    font-size: 0.76rem;
    font-weight: 500;
    color: var(--muted);
    line-height: 1.45;
    margin: 0;
    overflow-wrap: anywhere;
}

/*
 * Dashboard cards run a touch taller — they often pair a number with
 * a chart sparkline or icon, so they need a bit more vertical room
 * than the dense settings/knowledge pages.
 */
.dashboard-stats-grid .stat-card {
    min-height: 156px;
}

.knowledge-stats-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

.knowledge-stats-grid .stat-card {
    min-width: 0;
}

.knowledge-diagnostics-card {
    margin-bottom: 20px;
}

.diagnostic-metric-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin-bottom: 16px;
    min-width: 0;
}

.diagnostic-metric-list:last-child {
    margin-bottom: 0;
}

.diagnostic-metric-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    min-width: 0;
    padding: 13px 15px;
    border-radius: 16px;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.052), rgba(255, 255, 255, 0.032)),
        rgba(255, 255, 255, 0.035);
    border: 1px solid rgba(255, 255, 255, 0.075);
}

.diagnostic-metric-label {
    min-width: 0;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.055em;
    line-height: 1.35;
    text-transform: uppercase;
    overflow-wrap: anywhere;
}

.diagnostic-metric-value {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 2.35rem;
    max-width: 100%;
    padding: 5px 10px;
    border-radius: 999px;
    background: rgba(216, 226, 255, 0.1);
    border: 1px solid rgba(216, 226, 255, 0.16);
    color: #f2f6ff;
    font-size: 0.86rem;
    font-weight: 800;
    line-height: 1.2;
    text-align: center;
    overflow-wrap: anywhere;
}

.diagnostic-metric-status.status-ok {
    background: rgba(52, 211, 153, 0.13);
    border-color: rgba(52, 211, 153, 0.28);
    color: #9ff3c7;
}

.diagnostic-metric-status.status-warning {
    background: rgba(245, 158, 11, 0.14);
    border-color: rgba(245, 158, 11, 0.3);
    color: #ffd18a;
}

.diagnostic-metric-status.status-error {
    background: rgba(248, 113, 113, 0.14);
    border-color: rgba(248, 113, 113, 0.3);
    color: #ffc0c0;
}

.dashboard-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.dashboard-analytics-grid {
    /*
     * Two equal columns at desktop — the dashboard surfaces six cards
     * arranged across three thematic rows (Traffic / Health / Insights).
     * Pairing related cards two-per-row gives each visualisation enough
     * horizontal real estate (~600px) for line, bar, meter and list
     * widgets to breathe without scrolling. The responsive rules below
     * already collapse to a single column at narrow viewports.
     */
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
    margin-bottom: 20px;
    align-items: stretch;
}

.analytics-card {
    min-height: 218px;
    display: grid;
    align-content: space-between;
    overflow: hidden;
}

.analytics-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 12px;
}

.analytics-total {
    color: #f7f9ff;
    font-size: 1.8rem;
    line-height: 1;
    font-weight: 800;
}

/*
 * Stacks the big primary number on top of a small "equivalent unit"
 * readout (e.g. "7358 ms" above, "≈ 7.4 s · 0.12 min" below). Used by
 * the Response Quality card where the raw millisecond value is useful
 * for engineers but a seconds/minutes echo is friendlier for ops.
 */
.analytics-total-wrap {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    min-width: 0;
}

.analytics-subtotal {
    margin: 0;
    color: var(--muted);
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
    line-height: 1.2;
}

.line-chart {
    width: 100%;
    height: 86px;
    min-width: 0;
}

.line-chart svg {
    width: 100%;
    height: 100%;
    display: block;
}

.chart-axis {
    stroke: rgba(255, 255, 255, 0.18);
    stroke-width: 1;
    stroke-dasharray: 7 7;
}

.chart-line {
    fill: none;
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.chart-line-teal {
    stroke: #00c2a8;
    filter: drop-shadow(0 0 10px rgba(0, 194, 168, 0.35));
}

.chart-end-dot {
    fill: #081120;
    stroke: #00c2a8;
    stroke-width: 3;
}

.chart-label-row {
    display: flex;
    justify-content: space-between;
    gap: 6px;
    color: var(--muted);
    font-size: 0.72rem;
}

.chart-label-row span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bar-chart-scroll,
.bar-chart-frame {
    overflow: hidden;
    overflow-x: hidden;
    overflow-y: hidden;
    padding-bottom: 0;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.bar-chart {
    /*
     * Taller chart (120px) to match the _bar_series max_bar_height of
     * 96px with comfortable headroom for the hover-lift state. The
     * grid auto-distributes column widths so 24 hours, 30 days or
     * 90 days all fill the same card width without horizontal scroll.
     */
    height: 120px;
    display: grid;
    grid-template-columns: repeat(var(--bar-count, 24), minmax(2px, 1fr));
    align-items: flex-end;
    gap: clamp(1px, calc(80px / var(--bar-count, 24)), 4px);
    padding: 6px 0 0;
    min-width: 0;
}

.bar-column {
    width: 100%;
    min-width: 2px;
    max-width: 14px;
    height: var(--bar-height);
    justify-self: center;
    border-radius: 5px 5px 2px 2px;
    background: linear-gradient(180deg, #a597ff 0%, #6255d9 100%);
    box-shadow: 0 0 18px rgba(132, 111, 255, 0.24);
    transition: filter 160ms ease, transform 160ms ease;
}

.bar-column:hover {
    filter: brightness(1.18);
    transform: translateY(-1px);
}

/*
 * Empty-day marker. The series helper returns `is_empty=True` for any
 * 0-value bucket; the template adds `.bar-column-empty` so the eye
 * reads those buckets as gaps rather than data. Without this rule
 * the 2px minimum height would visually equate quiet days with
 * one-or-two-message days.
 */
.bar-column-empty {
    background: rgba(255, 255, 255, 0.16);
    box-shadow: none;
    border-radius: 2px;
}

.bar-column-empty:hover {
    filter: none;
    transform: none;
}

.chart-baseline {
    height: 1px;
    margin-top: 12px;
    border-radius: 999px;
    background: linear-gradient(
        90deg,
        transparent,
        rgba(255, 255, 255, 0.4) 12%,
        rgba(255, 255, 255, 0.4) 88%,
        transparent
    );
    opacity: 0.5;
}

.bar-chart-label-row {
    min-width: 0;
    margin-top: 10px;
}

.health-meter {
    position: relative;
    display: flex;
    width: 100%;
    height: 20px;
    overflow: hidden;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.08);
}

.health-segment {
    display: block;
    height: 100%;
    min-width: 0;
}

.health-ready {
    background: #12b76a;
}

.health-processing {
    background: #7c6cff;
}

.health-failed {
    background: #f04438;
}

.health-legend {
    display: grid;
    gap: 10px;
    margin-top: 18px;
    color: var(--muted);
    font-size: 0.88rem;
}

.health-legend-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.health-legend-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
    padding: 10px 12px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.health-legend-label-wrap {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 1 1 auto;
}

.health-legend-label {
    color: var(--muted);
    font-size: 0.78rem;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.health-legend-value {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 2rem;
    max-width: 100%;
    padding: 4px 8px;
    border-radius: 999px;
    background: rgba(216, 226, 255, 0.1);
    border: 1px solid rgba(216, 226, 255, 0.16);
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 800;
    line-height: 1.1;
    text-align: center;
    overflow-wrap: anywhere;
}

.legend-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex-shrink: 0;
}

.legend-ready {
    background: #12b76a;
}

.legend-processing {
    background: #7c6cff;
}

.legend-failed {
    background: #f04438;
}

/* ===========================================================
   Quality & engagement panels (Feedback / Distributions)
   -----------------------------------------------------------
   Side-by-side cards under the activity row. They share the
   same `.quality-card` shell so spacing + footers stay in
   visual lockstep; each has its own internal viz (segmented
   feedback meter, deterministic distribution bars).
   =========================================================== */

.dashboard-quality-grid {
    margin-bottom: 22px;
}

.quality-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.analytics-unit {
    font-size: 0.42em;
    font-weight: 700;
    margin-left: 4px;
    color: var(--muted);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.feedback-meter {
    position: relative;
    display: flex;
    width: 100%;
    height: 14px;
    overflow: hidden;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
}

.feedback-segment {
    display: block;
    height: 100%;
    transition: width 320ms ease;
}

.feedback-like-seg {
    background: linear-gradient(90deg, #1bc47d, #34d399);
}

.feedback-dislike-seg {
    background: linear-gradient(90deg, #f5446c, #f31260);
}

.feedback-none-seg {
    background: rgba(255, 255, 255, 0.12);
}

.feedback-legend {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
}

.feedback-legend-item {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding: 10px 12px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.feedback-legend-label {
    flex: 1 1 auto;
    color: var(--muted);
    font-size: 0.78rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.feedback-legend-value {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 2rem;
    max-width: 100%;
    padding: 4px 8px;
    border-radius: 999px;
    background: rgba(216, 226, 255, 0.1);
    border: 1px solid rgba(216, 226, 255, 0.16);
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 800;
    line-height: 1.1;
    text-align: center;
    overflow-wrap: anywhere;
}

.legend-like {
    background: #34d399;
}

.legend-dislike {
    background: #f5446c;
}

.legend-none {
    background: rgba(255, 255, 255, 0.24);
}

/* --- Top routes list ---------------------------------------- */

.route-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.route-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr) auto;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.route-label {
    color: var(--text);
    font-size: 0.88rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.route-bar {
    width: 100%;
    height: 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.05);
    overflow: hidden;
}

.route-bar-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--primary), var(--primary-strong));
    box-shadow: 0 0 12px rgba(109, 140, 255, 0.32);
    transition: width 320ms ease;
}

.route-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.25rem;
    max-width: 100%;
    padding: 4px 9px;
    border-radius: 999px;
    background: rgba(216, 226, 255, 0.09);
    border: 1px solid rgba(216, 226, 255, 0.14);
    color: var(--text);
    font-size: 0.86rem;
    font-weight: 800;
    text-align: center;
    overflow-wrap: anywhere;
}

.route-empty {
    grid-template-columns: 1fr;
    color: var(--muted);
    font-size: 0.86rem;
    text-align: center;
    padding: 18px 0;
}

/* --- Response quality (active visitors + tokens) -- */

/*
 * Subtle hint under a deterministic distribution panel: how many messages in
 * range carry no request_path / execution_result metadata yet (e.g. pre-rebuild
 * rows). Keeps the "unknown" count from being misread as a failure.
 */
.quality-unknown-hint {
    margin: 4px 0 0;
    font-size: 0.74rem;
    line-height: 1.55;
    color: var(--muted);
    font-style: italic;
    opacity: 0.85;
}

/* Card footer rows (link / stats) */

.quality-card-footer {
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.quality-footer-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--primary-strong);
    font-size: 0.82rem;
    font-weight: 600;
    transition: color 160ms ease, transform 160ms ease;
}

.quality-footer-link:hover {
    color: var(--text);
    transform: translateX(2px);
}

.quality-card-footer-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.quality-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 10px 12px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.quality-stat-label {
    color: var(--muted);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.quality-stat-value {
    color: var(--text);
    font-size: 1.05rem;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.dashboard-operations-section,
.dashboard-recent-accounts-section {
    margin-bottom: 20px;
    min-width: 0;
}

.dashboard-operations-card,
.dashboard-recent-accounts-card {
    min-width: 0;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table {
    min-width: 0;
    table-layout: fixed;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table th,
.dashboard-recent-accounts-card .dashboard-recent-accounts-table td {
    white-space: normal;
    overflow-wrap: anywhere;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table th:nth-child(1) {
    width: 25%;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table th:nth-child(2) {
    width: 38%;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table th:nth-child(3) {
    width: 15%;
}

.dashboard-recent-accounts-card .dashboard-recent-accounts-table th:nth-child(4) {
    width: 22%;
}

.dashboard-operations-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
    min-width: 0;
}

.dashboard-operation-entry {
    min-width: 0;
    margin: 0;
}

.dashboard-operation-item,
.dashboard-operation-empty {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr) max-content;
    align-items: center;
    column-gap: 11px;
    min-width: 0;
    min-height: 58px;
    padding: 8px 10px;
    border-radius: 12px;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.042), rgba(255, 255, 255, 0.026)),
        rgba(255, 255, 255, 0.026);
    border: 1px solid rgba(255, 255, 255, 0.065);
}

.dashboard-operation-item {
    color: var(--text);
    transition: background-color 180ms ease, border-color 180ms ease, transform 180ms ease;
}

.dashboard-operation-item:hover {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.058), rgba(255, 255, 255, 0.034)),
        rgba(109, 140, 255, 0.035);
    border-color: rgba(109, 140, 255, 0.18);
    transform: translateY(-1px);
}

.dashboard-operation-item:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(109, 140, 255, 0.45),
        0 0 0 6px rgba(109, 140, 255, 0.18);
}

.dashboard-operation-body {
    min-width: 0;
}

.dashboard-operation-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 9px;
    background: rgba(109, 140, 255, 0.075);
    border: 1px solid rgba(138, 162, 255, 0.14);
    color: #d8e2ff;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.055);
}

.dashboard-operation-svg {
    inline-size: 19px;
    block-size: 19px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    opacity: 0.92;
}

.dashboard-operation-label {
    display: block;
    min-width: 0;
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

.dashboard-operation-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    justify-self: end;
    /*
     * Keep the action as an intrinsic, non-wrapping third grid column. A
     * fixed inline size clips or overflows at browser text zoom, whereas a
     * minimum preserves the compact normal-size rhythm and lets the column
     * grow before the flexible title column gives up its useful width.
     */
    min-inline-size: 76px;
    min-block-size: 28px;
    padding-inline: 9px;
    border-radius: 999px;
    background: rgba(216, 226, 255, 0.085);
    border: 1px solid rgba(216, 226, 255, 0.14);
    color: #d8e2ff;
    font-size: 0.76rem;
    font-weight: 800;
    line-height: 1;
    white-space: nowrap;
}

.dashboard-operation-item:hover .dashboard-operation-action,
.dashboard-operation-item:focus-visible .dashboard-operation-action {
    background: rgba(109, 140, 255, 0.18);
    border-color: rgba(138, 162, 255, 0.3);
    color: #ffffff;
}

.dashboard-operation-empty {
    grid-template-columns: minmax(0, 1fr);
    color: var(--muted);
    margin: 0;
}

.dashboard-operation-empty .dashboard-operation-label {
    color: var(--muted);
    font-weight: 600;
}

.dashboard-ops-strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
}

.ops-mini-card {
    display: grid;
    gap: 8px;
    min-width: 0;
    padding: 18px;
    border-radius: 18px;
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid rgba(255, 255, 255, 0.075);
}

.ops-mini-card strong {
    font-size: 1.5rem;
    line-height: 1;
    color: #f7f9ff;
}

.panel-head {
    margin-bottom: 18px;
}

.table-wrap {
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    border-radius: 16px;
    -webkit-overflow-scrolling: touch;
}

.table-wrap.table-wrap-compact {
    max-height: 48vh;
    overflow-y: auto;
}

.data-table {
    width: 100%;
    min-width: 700px;
    border-collapse: collapse;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: 13px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    font-size: 0.94rem;
    vertical-align: middle;
    white-space: nowrap;
}

.data-table td {
    unicode-bidi: plaintext;
    text-align: start;
}

.data-table th {
    color: #d8e2ff;
    font-weight: 700;
    position: sticky;
    top: 0;
    background: rgba(16, 26, 51, 0.98);
    backdrop-filter: blur(10px);
    z-index: 2;
}

.data-table td {
    color: var(--muted);
}

.data-table th:first-child,
.data-table td:first-child:not(.cell-id) {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Public-ID cell — monospace. Truncation + reveal are handled by the inline
   `.long-id-reveal` component below (NOT a native `title` tooltip, which
   produced a broken floating popup above the row). Used in the Conversation
   Records table where `public_id` is up to 80 chars (Conversation.public_id
   is CharField(max_length=80)). */
.data-table td.cell-id {
    font-size: 0.82rem;
    color: #b8c4e6;
    max-width: 240px;
    vertical-align: middle;
}

@media (max-width: 640px) {
    .data-table td.cell-id {
        max-width: 140px;
    }
}

/* Accessible validation summaries and stable inline error references. */
.form-error-summary {
    margin: 0 0 20px;
    padding: 16px 18px;
    border: 1px solid rgba(255, 93, 143, 0.48);
    border-radius: var(--radius-sm);
    background: rgba(243, 18, 96, 0.1);
    color: var(--text);
}

.form-error-summary:focus {
    outline: 3px solid rgba(255, 182, 203, 0.36);
    outline-offset: 3px;
}

.form-error-summary h2 {
    margin: 0 0 8px;
    font-size: 1rem;
}

.form-error-summary ul {
    margin: 0;
    padding-inline-start: 20px;
}

.form-error-summary a {
    color: #ffd4e2;
}

.field-error span,
.errorlist li {
    display: block;
}

.settings-error-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    min-height: 28px;
    margin-inline-start: auto;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--danger);
    color: #fff;
    font-size: 0.78rem;
    line-height: 1;
}

/* View-only Settings are real copyable content, never disabled controls. */
.settings-read-only-banner {
    margin-bottom: 18px;
    padding: 14px 16px;
    border: 1px solid rgba(109, 140, 255, 0.34);
    border-radius: var(--radius-sm);
    background: rgba(109, 140, 255, 0.1);
    color: var(--text);
}

.settings-read-only-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin: 0;
}

.settings-read-only-item {
    min-width: 0;
    padding: 14px;
    border: 1px solid var(--panel-border);
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.025);
}

.settings-read-only-item dt {
    margin-bottom: 6px;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 700;
}

.settings-read-only-item dd {
    margin: 0;
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    user-select: text;
}

.is-admin-drawer-open {
    overflow: hidden;
}

/* Touch-accessible interactive controls retain their current visual design. */
.file-picker-button,
.brand-asset-clear,
.brand-asset-file,
.settings-section-summary,
.auth-form .button,
.upload-actions .button {
    min-height: 44px;
}

@media (max-width: 640px) {
    .settings-read-only-grid {
        grid-template-columns: 1fr;
    }
}

/* Motion preferences apply to the admin shell, forms, drawers, and tooltips. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        scroll-behavior: auto !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        transition-delay: 0ms !important;
    }
}

/* ===================================================================
 * Reusable in-place truncated-value reveal (Windows-style).
 * The ONE pattern for every clipped value in admin tables/cards (long IDs,
 * titles, file names, request/source/chunk IDs, …). Default: single-line
 * ellipsis aligned with the row text. On hover OR keyboard focus the FULL
 * value appears anchored to THIS span (absolute, relative to the trigger —
 * never the viewport/body, never a top-floating native `title`). Because the
 * reveal is out of flow it does NOT increase row height and does NOT shift
 * column alignment; it may extend over adjacent columns inside the
 * horizontal-scroll table. Works with mouse, keyboard focus, and LTR/RTL.
 *   .truncate-reveal--id   → monospace, LTR-isolated (hash-like IDs)
 *   .truncate-reveal--text → human text/titles (direction follows content;
 *                            the overlay may wrap so long Arabic/English
 *                            titles stay fully readable — still out of flow,
 *                            so the ROW never grows).
 * =================================================================== */
.truncate-reveal {
    position: relative;
    display: inline-block;
    max-width: 100%;
    vertical-align: middle;
    line-height: inherit;
    cursor: default;
    border-radius: 4px;
    outline: none;
}
.truncate-reveal--id {
    font-family: ui-monospace, "SF Mono", Menlo, Monaco, "Cascadia Code", Consolas, monospace;
    direction: ltr;
    unicode-bidi: isolate;
}
.truncate-reveal-short {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}
.truncate-reveal-full {
    display: none;
    white-space: nowrap;
}
/* Keep the truncated text's footprint (visibility, not display) so the cell
   width stays stable while the full value overlays it on the same line. */
.truncate-reveal:hover .truncate-reveal-short,
.truncate-reveal:focus .truncate-reveal-short,
.truncate-reveal:focus-within .truncate-reveal-short {
    visibility: hidden;
}
.truncate-reveal:hover .truncate-reveal-full,
.truncate-reveal:focus .truncate-reveal-full,
.truncate-reveal:focus-within .truncate-reveal-full {
    display: inline-block;
    position: absolute;
    top: 50%;
    /* LTR default: overlay opens from the LEFT (inline-start). The `[dir="rtl"]` rule below flips it to
       the RIGHT for Arabic. `text-align: start` follows the inherited direction (right for RTL text). */
    left: 0;
    right: auto;
    transform: translateY(-50%);
    white-space: nowrap;
    text-align: start;
    padding: 3px 9px;
    background: #101a33;
    color: #e7eefc;
    border: 1px solid rgba(120, 150, 230, 0.45);
    border-radius: 5px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
    z-index: 6;
    /* Viewport caps so a long value can never extend off-screen; if the box would be taller than the
       viewport it scrolls inside itself rather than overflowing. The JS positioner measures this bounded
       box and clamps top/left into the viewport. */
    max-width: calc(100vw - 16px);
    max-height: calc(100vh - 16px);
    overflow-y: auto;
}
/* Human titles: the anchored overlay WRAPS so the full title is readable, and if a very long title is
   taller than the viewport it scrolls vertically inside the box (max-height + overflow-y) — it never
   extends off-screen. Still absolute / out of flow → the row height never changes. */
.truncate-reveal--text:hover .truncate-reveal-full,
.truncate-reveal--text:focus .truncate-reveal-full,
.truncate-reveal--text:focus-within .truncate-reveal-full {
    white-space: normal;
    overflow-wrap: anywhere;
    width: max-content;
    max-width: min(60vw, 420px);
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    line-height: 1.5;
}
.truncate-reveal:focus,
.truncate-reveal:focus-within {
    box-shadow: 0 0 0 2px rgba(120, 150, 230, 0.55);
}
/* RTL (Arabic): the cell/reveal carries an EXPLICIT dir="rtl" (from the `text_dir` filter), so the
   overlay anchors to the RIGHT edge and its text aligns right — it opens toward the left as it grows,
   staying attached to the Arabic text's right edge. `:dir(rtl)` reinforces this for any dir="auto". */
[dir="rtl"] .truncate-reveal:hover .truncate-reveal-full,
[dir="rtl"] .truncate-reveal:focus .truncate-reveal-full,
[dir="rtl"] .truncate-reveal:focus-within .truncate-reveal-full,
.truncate-reveal--text:dir(rtl) .truncate-reveal-full {
    left: auto;
    right: 0;
    text-align: right;
}
/* Technical IDs/hashes always stay LTR-anchored and single-line, regardless of any RTL ancestor. A very
   long ID stays nowrap but is width-bounded to the viewport and scrolls horizontally inside the box. */
.truncate-reveal--id .truncate-reveal-full {
    left: 0;
    right: auto;
    text-align: left;
    direction: ltr;
    unicode-bidi: isolate;
    white-space: nowrap;
    max-width: calc(100vw - 16px);
    overflow-x: auto;
    overflow-y: hidden;
}

/* Title column — width cap only. Truncation + full-value reveal are handled by the inline
   `.truncate-reveal--text` component inside the cell (no native `title`, no JS popover). */
.data-table td.cell-title {
    /*
     * Title column max-width. The ceiling (320px) is sized so an
     * 8-column data-table — currently the Knowledge Files list:
     * Title / Type / Status / Language / Chunks / Size / Uploaded /
     * Open — fits inside a 1280px laptop viewport without forcing
     * horizontal scroll. The 7-column Conversations table fits with
     * comfortable headroom at the same ceiling. The 180px floor
     * keeps the title column readable on a 320px phone (where the
     * `.table-wrap` provides natural horizontal scroll anyway), and
     * the 24vw mid-band scales the column proportionally on every
     * intermediate viewport so the visual rhythm of the row stays
     * stable across the breakpoint range.
     */
    max-width: clamp(180px, 24vw, 320px);
    white-space: normal;
    /* `visible` (not hidden) so the inline `.truncate-reveal` overlay can escape
       the cell on hover/focus; the inner `.truncate-reveal-short` does its own
       single-line ellipsis, so the truncated state still clips to the column. */
    overflow: visible;
    unicode-bidi: plaintext;
    vertical-align: middle;
}

/* Knowledge Files keeps its primary title column readable when the responsive
   wrapper scrolls horizontally. This is deliberately scoped to that table:
   other Admin data tables keep their existing intrinsic-column behavior. */
.knowledge-files-table.data-table th.cell-title,
.knowledge-files-table.data-table td.cell-title {
    width: clamp(180px, 24vw, 320px);
    min-width: 180px;
}

.knowledge-files-table.data-table th.cell-title {
    white-space: nowrap;
    overflow-wrap: normal;
    word-break: normal;
}

.knowledge-files-table.data-table td.cell-title {
    overflow-wrap: break-word;
    word-break: normal;
}


/*
 * Action column — fit-content width via the canonical `width: 1%`
 * table trick.
 *
 * Browser tables use the auto-layout algorithm by default. A cell
 * declared with `width: 1%` AND `white-space: nowrap` collapses to
 * the minimum width its content requires (the "Open" pill), while
 * every other column shares the remaining horizontal real estate.
 * The result: long titles can never push the action button off the
 * screen because the action column refuses to grow past its content
 * size and the title column is independently capped above.
 *
 * Earlier iterations of this rule used `position: sticky;
 * inset-inline-end: 0` plus an opaque background + box-shadow so the
 * Open pill would remain visible at the inline-end edge of
 * `.table-wrap` even on mobile / tablet viewports where the table
 * exceeds the viewport width. That satisfied an over-strict
 * automated audit ("action button must be visible without
 * horizontal scrolling") but visually damaged the design: the
 * opaque background painted a permanent dark column even on wide
 * desktops where the sticky behaviour was dormant, and the
 * box-shadow created a permanent vertical seam that read as an
 * overlay rather than a clean table column. On narrow viewports the
 * sticky cell also chewed up scarce horizontal real estate that the
 * title column needed, contributing to Arabic titles being crushed
 * into vertical character fragments.
 *
 * Reverted to a normal, non-sticky action column. On wide viewports
 * the table fits naturally, the Open pill sits at the right edge of
 * its row, and there is no overlay. On viewports narrower than the
 * table's `min-width`, the `.table-wrap` provides the natural
 * horizontal scroll affordance — the Open pill is reachable with a
 * short swipe right. Horizontal scroll is the idiomatic responsive solution for a wider-than-mobile
 * data table, not a sticky overlay.
 */
.data-table th.cell-action,
.data-table td.cell-action {
    width: 1%;
    white-space: nowrap;
}

/*
 * Visually-hidden text — visible to assistive tech, invisible to
 * sighted users. Used for action-column <th> labels and any other
 * context where the visible chrome already conveys the information
 * but a screen reader still needs a textual hook.
 *
 * Implementation matches the WAI / Bootstrap / Tailwind .sr-only
 * convention. The 1×1 clip + absolute positioning prevents the text
 * from contributing to layout, while keeping it in the accessibility
 * tree so axe-core's `empty-table-header` rule is satisfied without
 * any visual side-effect.
 */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/*
 * Focus ring for keyboard-accessible scrollable regions.
 *
 * `enhanceScrollableRegionsForKeyboard()` in main.js adds
 * `tabindex="0"` to every container in the curated scroll allowlist
 * so keyboard users can tab to it and arrow-scroll. By default a
 * tabindex-bearing element exposes its native (browser-default)
 * outline on `:focus`, which would also render on mouse-click drag.
 *
 * We replace that with a brand-aligned ring that only appears for
 * keyboard focus (`:focus-visible`) — matching the ring already used
 * by buttons, links, and the segmented control. Mouse users see no
 * lingering outline, keyboard users see a clear "this region is now
 * focused" cue.
 */
.table-wrap,
.scroll-block,
.scroll-block-lg,
.content-scroll-sm,
.content-scroll-md,
.chunk-list,
.json-preview,
.metadata-json-text,
.settings-snapshot-card {
    outline: none;
}

.table-wrap:focus-visible,
.scroll-block:focus-visible,
.scroll-block-lg:focus-visible,
.content-scroll-sm:focus-visible,
.content-scroll-md:focus-visible,
.chunk-list:focus-visible,
.json-preview:focus-visible,
.metadata-json-text:focus-visible,
.settings-snapshot-card:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(109, 140, 255, 0.45),
        0 0 0 6px rgba(109, 140, 255, 0.18);
    border-radius: var(--radius-sm);
}

.table-link {
    min-width: 84px;
    padding-inline: 20px;
    white-space: nowrap;
    word-break: keep-all;
    overflow-wrap: normal;
    flex-wrap: nowrap;
    line-height: 1;
    text-align: center;
}

.chunk-list,
.conversation-thread,
.summary-stack,
.source-list {
    display: grid;
    gap: 12px;
    min-width: 0;
}

.upload-panel-card,
.filter-panel-card {
    margin-bottom: 20px;
}

.upload-fields-grid {
    align-items: start;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.upload-fields-grid .form-group {
    grid-template-rows: auto 60px minmax(2.8em, auto) auto;
}

.upload-fields-grid .upload-field-title::after {
    content: "";
    min-height: 2.8em;
}

.upload-fields-grid .form-input,
.upload-fields-grid .file-picker {
    height: 60px;
    min-height: 60px;
}

.upload-fields-grid .form-help-text {
    margin: 0;
    min-height: 2.8em;
}

.strict-rules-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin: -4px 0 18px;
}

.strict-rule-item {
    min-width: 0;
    padding: 10px 12px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid rgba(255, 255, 255, 0.06);
    color: #dce5ff;
    font-size: 0.88rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.upload-actions,
.pagination-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
}

.pagination-bar {
    justify-content: space-between;
    margin-top: 18px;
}

.pagination-text {
    color: var(--muted);
    font-size: 0.94rem;
}

.details-grid {
    display: grid;
    gap: 12px;
    min-width: 0;
}

.detail-row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 16px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    min-width: 0;
}

.detail-row span {
    color: var(--muted);
    min-width: 0;
}

.detail-row strong {
    text-align: right;
    min-width: 0;
    overflow-wrap: anywhere;
}

.hash-text {
    font-size: 0.82rem;
    max-width: 55%;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.json-preview {
    margin: 0;
    padding: 16px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    color: #dce5ff;
    line-height: 1.7;
    min-height: 180px;
}

.chunk-head,
.thread-bubble-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 12px;
}

.chunk-meta,
.thread-bubble-meta,
.source-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chunk-admin-metadata {
    display: grid;
    gap: 8px;
    margin: 10px 0 12px;
}

.chunk-admin-metadata-title {
    color: var(--muted);
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.chunk-structure-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 8px;
    margin: 0;
}

.chunk-structure-grid span {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    padding: 8px 10px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.035);
    color: #dce5ff;
    overflow-wrap: anywhere;
}

.chunk-structure-grid strong {
    min-width: 92px;
    color: #8fb4ff;
    font-weight: 700;
}

.chunk-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.error-box,
.empty-state-box {
    padding: 16px;
    border-radius: 16px;
    background: rgba(243, 18, 96, 0.12);
    border: 1px solid rgba(243, 18, 96, 0.2);
    color: #ffdfe9;
    margin-top: 16px;
    overflow-wrap: anywhere;
}

.filter-actions {
    display: flex;
    align-items: flex-end;
    min-width: 0;
}

.thread-bubble {
    padding: 20px;
    border-radius: 20px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    min-width: 0;
}

.thread-bubble.is-user {
    background: rgba(109, 140, 255, 0.12);
}

.thread-bubble.is-assistant {
    background: rgba(255, 255, 255, 0.04);
}

.thread-bubble.is-system {
    background: rgba(245, 165, 36, 0.08);
}

.thread-bubble-head strong {
    font-size: 1rem;
}

.thread-bubble-head span,
.thread-bubble-meta span,
.source-meta span,
.summary-label {
    color: var(--muted);
    font-size: 0.86rem;
}

.thread-bubble-body {
    line-height: 1.8;
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
    /*
     * Render Arabic user / assistant messages in their natural RTL
     * direction without forcing a `dir` attribute on the admin chrome.
     * `unicode-bidi: plaintext` tells the browser to derive the
     * paragraph direction from the FIRST strong-directional character
     * of the content itself — so Arabic messages flow RTL, English
     * messages flow LTR, and mixed paragraphs render as the writer
     * intended. Same trick already used by `.data-table td` (admin
     * tables) so the conversation pane and the records list behave
     * the same way for bilingual content.
     */
    unicode-bidi: plaintext;
}

.summary-box p.content-scroll-sm {
    /* Mirror the bubble body treatment for the "Last User / Last
       Assistant" preview text shown at the top of the page — without
       this an Arabic snapshot leaks LTR punctuation into the bubble. */
    unicode-bidi: plaintext;
}

.summary-box p,
.source-card p {
    color: var(--text);
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Visitor feedback badges (assistant messages) */
.feedback-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.feedback-like {
    background: rgba(16, 185, 129, 0.20);
    color: #34d399;
    border: 1px solid rgba(16, 185, 129, 0.34);
}

.feedback-dislike {
    background: rgba(239, 68, 68, 0.18);
    color: #f87171;
    border: 1px solid rgba(239, 68, 68, 0.32);
}

/* Chunk sequence number badge */
.chunk-id-tag {
    background: rgba(99, 102, 241, 0.22);
    color: #a5b4fc;
    border: 1px solid rgba(99, 102, 241, 0.35);
    padding: 1px 8px;
    border-radius: 4px;
    font-family: monospace;
    font-size: 0.82em;
    font-weight: 600;
    white-space: nowrap;
}

.audit-details-grid {
    gap: 8px;
}

.source-full-text {
    margin-top: 8px;
    border-radius: 6px;
    background: rgba(15, 23, 42, 0.28);
}

.source-full-text summary {
    min-height: 34px;
    padding: 7px 10px;
    cursor: pointer;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 700;
    list-style-position: inside;
}

.source-full-text summary:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.source-full-text p {
    margin: 0;
    padding: 0 10px 10px;
}

.detail-row-block {
    grid-column: 1 / -1;
    align-items: stretch;
    flex-direction: column;
}

.metadata-json-text {
    width: 100%;
    max-height: 220px;
    overflow: auto;
    margin: 6px 0 0;
    padding: 10px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(15, 23, 42, 0.45);
    color: var(--text);
    font-family: monospace;
    font-size: 0.82rem;
    /* Structured data stays LTR even when a value contains Arabic. */
    direction: ltr;
    unicode-bidi: isolate;
    line-height: 1.55;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
    max-width: 100%;
}

.panel-card-scroll {
    min-height: 0;
}

.scroll-block {
    max-height: 360px;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    padding-right: 6px;
}

.scroll-block-lg {
    max-height: 560px;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    padding-right: 6px;
}

.content-scroll-sm {
    max-height: 160px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 4px;
}

.content-scroll-md {
    max-height: 260px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 4px;
}

/* ===========================================================
   Universal modern scrollbar — applies to EVERY scrollable
   element on the site (admin pages, sidebar, content panes,
   <pre>, <textarea>, JSON previews, message threads, etc.).

   A slim translucent overlay scrollbar: the chunky native Windows scrollbar (with step-button arrows
   and a solid grey track) is replaced with a thin pill that brightens on hover.

   Design tokens:
   - 10px gutter (slim but easy to grab with a mouse)
   - Transparent track (invisible until needed)
   - Thumb: 16% white -> 46% on thumb hover -> 60% on active drag
   - 2px transparent border + background-clip: padding-box so
     the visible thumb is 6px wide but the hit area stays 10px
   - No buttons, no corners, no arrows
   =========================================================== */

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.22) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 999px;
}

*::-webkit-scrollbar-thumb {
    background-color: rgba(255, 255, 255, 0.16);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
    transition: background-color 220ms ease;
}

*::-webkit-scrollbar-thumb:hover {
    background-color: rgba(255, 255, 255, 0.46);
}

*::-webkit-scrollbar-thumb:active {
    background-color: rgba(255, 255, 255, 0.60);
}

*::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
}

*::-webkit-scrollbar-corner {
    background: transparent;
}

/* Dashboard chart frames intentionally hide their scrollbar entirely —
   the bars themselves communicate the data range, so a scroll affordance
   would just add visual noise. Specificity wins over the universal rule. */
.bar-chart-scroll::-webkit-scrollbar,
.bar-chart-frame::-webkit-scrollbar {
    display: none;
    width: 0;
    height: 0;
}

/* ===========================================================
   Collapsible message sections inside .thread-bubble
   Native <details>/<summary> for full a11y + no-JS fallback.
   The default disclosure marker is hidden and replaced with a
   custom rotating chevron driven by the [open] attribute, so
   keyboard users still get the implicit ARIA expanded state.
   =========================================================== */

.bubble-section {
    margin-top: 12px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.025);
    min-width: 0;
}

.bubble-section + .bubble-section {
    margin-top: 10px;
}

.bubble-section-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    cursor: pointer;
    list-style: none;
    border-radius: var(--radius-md);
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 600;
    user-select: none;
    transition: background 180ms ease;
    min-height: 44px;
    min-width: 0;
}

.bubble-section-summary::-webkit-details-marker {
    display: none;
}

.bubble-section-summary::before {
    /* Explicit +/- collapse indicator: "+" when closed, "−" when open. */
    content: "+";
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    color: var(--muted);
    margin-right: 2px;
}

.bubble-section[open] > .bubble-section-summary::before,
.bubble-subsection[open] > .bubble-section-summary::before {
    content: "\2212"; /* minus sign */
}

/* Nested diagnostic subsections inside the single "Advanced Diagnostics" parent. */
.bubble-subsection {
    margin: 6px 0 0 10px;
    padding-top: 6px;
    border-top: 1px solid var(--border, rgba(127, 127, 127, 0.18));
}
.bubble-subsection > .bubble-section-summary {
    font-size: 12px;
}

/* Lightweight essential-metadata strip under the message (admin-only). */
.message-essential-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.message-essential-meta .essential-chip {
    font-size: 11px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 999px;
    background: var(--surface-2, rgba(127, 127, 127, 0.12));
    color: var(--muted);
    white-space: nowrap;
}

.bubble-section-summary:hover {
    background: rgba(255, 255, 255, 0.05);
}

.bubble-section-summary:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.bubble-section-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.bubble-section-tags {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.bubble-section-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    padding: 1px 8px;
    border-radius: 999px;
    background: rgba(109, 140, 255, 0.18);
    border: 1px solid rgba(109, 140, 255, 0.32);
    color: var(--primary-strong);
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1.4;
}

.bubble-section-body {
    padding: 4px 14px 14px;
    min-width: 0;
}

/* ===========================================================
   Settings section accordion — collapsible <details> wrappers.
   The summary is a flex row holding, in order: the numbered counter
   badge (summary::before), the section title (h3, flex-grows), and a
   custom rotating chevron (summary::after) — all vertically centred.
   =========================================================== */

.settings-section > .settings-section-summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 0;
    margin: 0;
    min-height: 44px;
    border-radius: 10px;
    transition: background 180ms ease;
    min-width: 0;
}

.settings-section > .settings-section-summary::-webkit-details-marker {
    display: none;
}

.settings-section > .settings-section-summary:hover {
    background: rgba(255, 255, 255, 0.04);
}

.settings-section > .settings-section-summary::after {
    content: "";
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(-45deg);
    transition: transform 180ms ease;
    margin-right: 8px;
}

.settings-section[open] > .settings-section-summary::after {
    transform: rotate(45deg);
}

.settings-section > .settings-section-summary > h3 {
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Widget preview page */
.widget-preview-grid {
    grid-template-columns: minmax(320px, 1fr) minmax(320px, 520px);
    align-items: start;
}

.preview-stage-card {
    min-height: 100%;
}

.widget-preview-stage {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    width: 100%;
    padding-top: 8px;
    min-width: 0;
}

.widget-preview-host {
    box-sizing: border-box;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    width: 100%;
    max-width: 448px;
    height: 668px;
    min-height: 368px;
    padding: 24px;
    margin-inline: auto;
    overflow: visible;
}

.settings-embed-options {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

.settings-embed-option {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    width: 100%;
    padding: 18px;
    border: 1px solid var(--border-color);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.025);
}

.settings-embed-option h3 {
    margin: 0 0 8px;
}

.settings-embed-option .settings-embed-code {
    box-sizing: border-box;
    width: 100%;
    min-height: 0;
    max-height: none;
    margin-block: 12px;
    padding: 14px 16px;
    overflow-x: auto;
    overflow-y: visible;
    white-space: pre;
    overflow-wrap: normal;
    word-break: normal;
    font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
    font-size: 0.84rem;
    line-height: 1.6;
    direction: ltr;
    text-align: left;
    unicode-bidi: isolate;
}

.settings-embed-option .button {
    min-height: 44px;
}

.settings-embed-option-note {
    margin: 12px 0 0;
    color: var(--text-muted);
    font-size: 0.86rem;
}

.settings-embed-reminder {
    margin: 14px 0;
    color: var(--text-muted);
}

.settings-embed-advanced {
    margin-top: 16px;
    border: 1px solid var(--border-color);
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.02);
}

.settings-embed-advanced > summary {
    min-height: 44px;
    padding: 12px 14px;
    cursor: pointer;
    color: var(--text);
    font-weight: 700;
}

.settings-embed-advanced > summary:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.settings-embed-advanced-body {
    display: grid;
    gap: 18px;
    padding: 2px 16px 16px;
}

.settings-embed-advanced-body h3 {
    margin: 0 0 6px;
    font-size: 0.95rem;
}

.settings-embed-advanced-body p,
.settings-embed-advanced-body ul {
    margin-block: 6px;
}

.settings-embed-advanced-body code {
    direction: ltr;
    unicode-bidi: isolate;
}

.settings-copy-status {
    min-height: 1.5em;
    margin: 8px 0 0;
    color: var(--text-muted);
}

@media (max-width: 1200px) {
    .filter-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .dashboard-analytics-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .knowledge-stats-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    /* `.settings-stats-grid` uses `auto-fit` at the base declaration —
       it reflows naturally at every viewport, so we don't override
       grid-template-columns here. */

    .filter-actions {
        align-items: stretch;
    }

    .widget-preview-grid {
        grid-template-columns: 1fr;
    }

}

@media (max-width: 1100px) {
    /*
     * `.stats-grid` uses `auto-fit + minmax(220px, 1fr)` at the base
     * declaration — no override needed here. The grid naturally
     * collapses from 4 → 3 → 2 → 1 columns as the viewport shrinks.
     */

    .dashboard-grid {
        grid-template-columns: 1fr;
    }

    .dashboard-ops-strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .settings-snapshot-card {
        position: static;
        max-height: none;
        overflow: visible;
    }

    /* Tablet width — bring the table floor closer to iPad Mini portrait (768px)
       so the horizontal scroll only kicks in when columns truly need it. */
    .data-table {
        min-width: 760px;
    }
}

@media (max-width: 920px) {
    .strict-rules-grid {
        grid-template-columns: 1fr;
    }

    body.admin-body {
        height: auto;
        min-height: 100vh;
        overflow: auto;
    }

    .topbar {
        flex-direction: column;
        align-items: stretch;
    }

    .topbar-actions {
        width: 100%;
        justify-content: flex-start;
    }

    .hero-card {
        padding: 28px;
    }

    .hero-grid {
        grid-template-columns: 1fr;
    }

    .admin-layout {
        height: auto;
        min-height: 100vh;
        grid-template-columns: 1fr;
        overflow: visible;
    }

    /* Mobile topbar: fixed at the top, holds the hamburger + brand.
       Pushes the page content down via padding-top on .admin-content. */
    .admin-mobile-topbar {
        display: flex;
        align-items: center;
        gap: 12px;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 40;
        padding: 10px 16px;
        background: rgba(10, 16, 31, 0.94);
        backdrop-filter: blur(16px);
        border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    }

    /* Sidebar becomes a fixed slide-in drawer, off-screen by default. */
    .admin-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        height: 100vh;
        width: min(300px, 86vw);
        max-height: none;
        overflow-y: auto;
        z-index: 50;
        border-right: 1px solid rgba(255, 255, 255, 0.08);
        border-bottom: none;
        transform: translateX(-100%);
        transition: transform 240ms ease;
    }

    .admin-sidebar.is-open {
        transform: translateX(0);
    }

    /* Backdrop dims the page while the sidebar is open. */
    .admin-sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 45;
        background: rgba(0, 0, 0, 0.5);
        opacity: 0;
        pointer-events: none;
        transition: opacity 240ms ease;
    }

    .admin-sidebar.is-open ~ .admin-sidebar-backdrop {
        opacity: 1;
        pointer-events: auto;
    }

    /* Push the content below the fixed topbar so nothing is occluded. */
    .admin-content {
        height: auto;
        min-height: 0;
        overflow: visible;
        padding-top: 80px;
    }

    /* Reposition toasts BELOW the fixed mobile-topbar (height ~64px).
       Toasts have z-index:999 which is higher than the topbar (40), so
       without this they'd sit visually on top of the hamburger button.
       72px clears the topbar with a small gap; on desktop the default
       88px keeps them clear of the page-header buttons too. */
    .toast-stack {
        top: 72px;
        right: 12px;
        width: min(300px, calc(100% - 24px));
    }

    .toast-item {
        padding: 9px 12px;
        font-size: 0.85rem;
        border-radius: 9px;
    }

    .form-grid,
    .filter-grid,
    .settings-section-grid {
        grid-template-columns: 1fr;
    }

    .settings-availability-controls {
        grid-template-columns: 1fr;
        grid-template-areas:
            "widget"
            "demo"
            "preview";
    }

    /* The upload fields no longer share a row once stacked, so desktop-only
       alignment reservations must not create blank space before File. */
    .upload-fields-grid .form-group {
        grid-template-rows: none;
    }

    .upload-fields-grid .upload-field-title::after {
        content: none;
    }

    .dashboard-analytics-grid {
        grid-template-columns: 1fr;
    }

    /* `.settings-stats-grid` uses `auto-fit` — no override needed at
       this breakpoint either; cards reflow to 1-2 columns automatically
       based on the 220px min track size. */

    /* Keep inner scroll containers usable on mobile too.
       The original "max-height: none" rule expanded long blocks
       (Structure Summary JSON, Processed Chunks list, message
       contents) to their full intrinsic height — which on a phone
       turned a 1000-line JSON into endless scroll. Re-cap each
       container with a viewport-relative ceiling so it stays
       internally scrollable and never eats more than ~65% of the
       screen. */
    .table-wrap.table-wrap-compact {
        max-height: min(48vh, 480px);
    }

    .scroll-block {
        max-height: min(55vh, 360px);
    }

    .scroll-block-lg {
        max-height: min(65vh, 560px);
    }

    .content-scroll-sm {
        max-height: min(35vh, 200px);
    }

    .content-scroll-md {
        max-height: min(45vh, 300px);
    }

    .data-table {
        min-width: 760px;
    }
}

@media (max-width: 760px) {
    .knowledge-stats-grid,
    .diagnostic-metric-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 520px) {
    .knowledge-stats-grid,
    .diagnostic-metric-list {
        grid-template-columns: 1fr;
    }

    .diagnostic-metric-item {
        align-items: flex-start;
        flex-direction: column;
    }
}

@media (max-width: 640px) {
    .app-shell,
    .auth-card-inner {
        padding: 20px;
    }

    /* This compact rule follows the <=920px mobile-topbar rule. Keep the
       fixed header clearance instead of resetting it with shorthand padding. */
    .admin-content {
        padding: 80px 20px 20px;
    }

    /* `.stats-grid` uses `auto-fit` at the base declaration — it
       collapses to a single column automatically when only one card
       fits in the viewport, so no override needed here. */

    .dashboard-ops-strip {
        grid-template-columns: 1fr;
    }

    .health-legend-grid,
    .feedback-legend,
    .quality-card-footer-stats {
        grid-template-columns: 1fr;
    }

    .route-item {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 8px 10px;
    }

    .route-bar {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .route-count {
        justify-self: end;
    }

    .analytics-head {
        flex-direction: column;
    }

    .settings-save-bar {
        margin-inline: 0;
        padding-inline: 0;
        justify-content: stretch;
    }

    .settings-save-bar .button {
        width: 100%;
    }

    .page-header,
    .chunk-head,
    .detail-row,
    .thread-bubble-head {
        flex-direction: column;
    }

    .page-header-actions {
        width: 100%;
        justify-content: flex-start;
    }

    .segmented-control {
        width: 100%;
        justify-content: space-between;
    }

    .segmented-option {
        flex: 1;
        min-width: 0;
        padding-inline: 8px;
    }

    .file-picker {
        align-items: stretch;
        flex-direction: column;
        padding: 8px;
    }

    .upload-fields-grid .file-picker {
        height: auto;
        min-height: 52px;
    }

    .file-picker-button {
        width: 100%;
    }

    .file-picker-name {
        width: 100%;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .hash-text {
        max-width: 100%;
        text-align: left;
    }

    .widget-preview-host {
        max-width: 100%;
    }

    .table-wrap {
        border-radius: 14px;
    }

    .data-table {
        min-width: 700px;
    }

    .dashboard-recent-accounts-card .dashboard-recent-accounts-table {
        min-width: 620px;
        table-layout: auto;
    }

    .data-table th,
    .data-table td {
        padding: 13px 10px;
        font-size: 0.92rem;
    }

    .table-link {
        min-width: 80px;
        min-height: 42px;
        padding-inline: 18px;
    }
}

/*
 * A 360px viewport still leaves enough room for the compact icon / title /
 * action row.  Stacking at a broader breakpoint wasted vertical space and
 * made the normal mobile Dashboard harder to scan.  Only the genuinely
 * ultra-narrow range needs the action to move below its title.
 */
@media (max-width: 340px) {
    .dashboard-operations-list {
        gap: 7px;
    }

    .dashboard-operation-item {
        grid-template-columns: 32px minmax(0, 1fr);
        grid-template-areas:
            "icon body"
            "action action";
        align-items: start;
        row-gap: 5px;
        column-gap: 10px;
        min-height: 0;
        padding: 9px 10px;
    }

    .dashboard-operation-icon {
        grid-area: icon;
        inline-size: 30px;
        block-size: 30px;
        border-radius: 9px;
        font-size: 0.8rem;
    }

    .dashboard-operation-body {
        grid-area: body;
        padding-block-start: 1px;
    }

    .dashboard-operation-label {
        overflow-wrap: anywhere;
    }

    .dashboard-operation-action {
        grid-area: action;
        justify-self: stretch;
        inline-size: 100%;
        min-block-size: 26px;
        padding-inline: 8px;
    }

    .dashboard-operation-empty {
        min-height: 0;
        padding: 10px;
    }
}

/* ===========================================================
   Conversation Details inspection page (admin-only) — scoped
   under `.conversation-detail-page` so it cannot regress other
   admin pages. Uses the shared theme tokens (var(--*)).
   =========================================================== */
.conversation-detail-page .conversation-source-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.conversation-detail-page .conversation-source-card + .conversation-source-card {
    margin-top: 12px;
}

/* Context-expansion chunks are visually distinct from primary RRF chunks. */
.conversation-detail-page .conversation-source-card--context {
    background: rgba(255, 255, 255, 0.02);
    border-left: 3px solid var(--warning);
}

.conversation-detail-page .conversation-source-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.conversation-detail-page .conversation-source-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    background: rgba(109, 140, 255, 0.16);
    border: 1px solid rgba(109, 140, 255, 0.30);
    color: var(--primary-strong);
    overflow-wrap: anywhere;
}

.conversation-detail-page .conversation-source-badge.is-muted {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--panel-border);
    color: var(--muted);
}

.conversation-detail-page .conversation-source-badge.is-context {
    background: rgba(245, 165, 36, 0.16);
    border-color: rgba(245, 165, 36, 0.34);
    color: var(--warning);
}

/* Ranking metrics as labelled tiles instead of a run-on inline line. */
.conversation-detail-page .conversation-source-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 8px;
}

.conversation-detail-page .conversation-metric {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid var(--panel-border);
    min-width: 0;
}

.conversation-detail-page .conversation-metric-label {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    opacity: 0.8;
}

.conversation-detail-page .conversation-metric-value {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    overflow-wrap: anywhere;
}

.conversation-detail-page .conversation-metric-na {
    font-weight: 600;
    color: var(--muted);
}

.conversation-detail-page .conversation-source-note {
    margin: 0;
    font-size: 0.78rem;
    color: var(--muted);
    overflow-wrap: anywhere;
}

.conversation-detail-page .conversation-source-excerpt {
    margin: 0;
    /* Server-capped preview: preserve line breaks and wrap safely, no inner scroll trap. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Channel contribution table (Channel | Rank | Contribution). */
.conversation-detail-page .conversation-contribution-wrap {
    overflow-x: auto;
    border-radius: var(--radius-sm);
    border: 1px solid var(--panel-border);
}

.conversation-detail-page .conversation-contribution-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.82rem;
}

.conversation-detail-page .conversation-contribution-table th,
.conversation-detail-page .conversation-contribution-table td {
    padding: 7px 12px;
    text-align: left;
    border-bottom: 1px solid var(--panel-border);
    white-space: nowrap;
}

.conversation-detail-page .conversation-contribution-table th {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    font-weight: 700;
    background: rgba(255, 255, 255, 0.03);
}

.conversation-detail-page .conversation-contribution-table tbody tr:last-child td {
    border-bottom: none;
}

/* Provenance as a compact label/value grid. */
.conversation-detail-page .conversation-provenance-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.conversation-detail-page .conversation-provenance-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.conversation-detail-page .conversation-provenance-label {
    font-size: 0.64rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    opacity: 0.7;
}

.conversation-detail-page .conversation-provenance-value {
    font-size: 0.84rem;
    color: var(--text);
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Long technical values (IDs, paths, contributions) must never widen the viewport. */
.conversation-detail-page .technical-value {
    overflow-wrap: anywhere;
}

/* Mobile: tighten the metric tiles into a two-up grid; the contribution table scrolls
   horizontally inside its contained wrapper rather than overflowing the card. */
@media (max-width: 640px) {
    .conversation-detail-page .conversation-source-metrics {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .conversation-detail-page .conversation-provenance-grid {
        grid-template-columns: 1fr;
    }
}
