/* ==========================================================================
   Agentic Support System — Admin Panel Stylesheet
   Handcrafted, no CSS framework. Dark theme; the application root is ALWAYS
   RTL (the System Language is Persian, which is RTL; bounded technical values
   render LTR inside it), very low border radius, thin borders, compact
   spacing. Class names are UpperCamelCase. Primary buttons are white with
   black text. The palette is BLACK / NEUTRAL GRAY only — there is no blue
   accent anywhere.

   Typography
   ----------
   Persian is the only System Language, so there is exactly one Admin UI font
   and no per-language re-fonting. Three roles, and only three:

   - Estedad (--fontStackPersian, bound to --fontStack) is the Admin UI font.
     It also carries Persian and Arabic-script CUSTOMER prose shown inside the
     Persian interface: Arabic-script content is still detected and displayed,
     it simply does not get a separate UI font.
   - Inter (--fontStackEnglish) is used only where the direction-aware
     presentation deliberately switches for natural Latin/English prose — an
     LTR customer message, or an English value inside the trace modal.
   - Space Mono (--monoFont) carries technical values: ids, hashes, model ids,
     request ids, raw JSON and code. These never take a prose font.

   There is no selectable Arabic Admin UI stack, and no font beyond the three
   named above is imported or referenced anywhere in this file.


   Conventions
   -----------
   - UpperCamelCase class names; design tokens live in :root custom properties.
   - One property per line (no minified one-line rule blocks).
   - Section banners use Title Case; explanatory prose stays sentence case.

   Section Map (In File Order)
   ---------------------------
   - 1. Font Imports and Design Tokens
   - 2. Reset, Base Elements and Scrollbars
   - 3. Application Shell and Navigation
   - 4. Page Layout, Headers, Breadcrumbs and Top Bar
   - 5. Buttons and Actions
   - 6. Forms, Inputs, Field Helpers and Validation
   - 7. Cards, Stats and Empty States
   - 8. Tables, Filters, Row Menus and Pagination
   - 9. Badges, Chips, Status Labels and Inline Metadata
   - 10. Dialogs, Modals, Toasts and Help Boxes
   - 11. Authentication UI: Login, TOTP and Admin Authenticator
   - 12. Knowledge UI: FAQ, Articles, Review Warnings and AI Helpers
   - 13. Conversation UI: Chat Bubbles, Direction, History and Handoff Markers
   - 14. Trace UI: Trace Modal, Tabs, JSON Blocks and Sent-to-Model View
   - 15. Conversation Lab UI
   - 16. Feedback UI
   - 17. ChatWoot Integration UI
   - 18. Reports, Dashboard and Charts
   - 19. Utility Classes
   - 20. Responsive Rules
   ========================================================================== */

/* --- 1. Font Imports and Design Tokens -------------------------------------- */

/* Estedad: the Admin UI font, and the font for Persian and Arabic-script
   customer prose shown inside it. */
@import url('https://fonts.googleapis.com/css2?family=Estedad:wght@100;200;300;400;500;600;700;800;900&display=swap');
/* Space Mono: the technical monospace (raw JSON, ids, secrets) — never the app font. */
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
/* Inter: natural Latin/English PROSE where the direction-aware presentation
   deliberately switches — an LTR customer message, or an English value in the
   trace modal. Technical values keep Space Mono. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  /* ONE axis typography token for every chart: readable,
     consistent, always smaller than the 13px chart titles. */
  --chartAxisFontSize: 12px;
  /* Pure black / neutral-gray palette — uber-like. Every channel is balanced
     (R = G = B), so there is no blue / navy / blue-gray tint anywhere. */
  --backgroundBase: #141414;
  --backgroundSurface: #141414;
  --backgroundRaised: #212121;
  --backgroundInput: #0a0a0a;
  --backgroundHover: #1d1d1d;
  --border: #222222;
  --borderStrong: #353535;
  /* Neutral filled surface for a borderless control (knowledge tags, trace
     action links). A BACKGROUND role: it happens to share a value with
     --borderStrong today, but they are not the same thing and must not be
     substituted for each other. */
  --backgroundNeutralControl: #353535;
  --textPrimary: #ffffff;
  --textSecondary: #cbcbcb;
  --textMuted: #ababab;
  --accent: #ffffff;
  --accentText: #050505;
  --ok: #4ade80;
  --okBackground: rgba(74, 222, 128, 0.12);
  --warn: #fffdfa;
  --warnBackground: rgba(255, 255, 255, 0.12);
  --danger: #f4615f;
  --dangerBackground: rgba(244, 97, 95, 0.12);
  --information: #d4d4d4;
  --informationBackground: rgba(212, 212, 212, 0.10);
  --muted: #8a8a8a;
  --mutedBackground: rgba(138, 138, 138, 0.12);
  --radius: 3px;
  --radiusLarge: 5px;
  --sidebarWidth: 252px;
  /* Three font roles, and only three. Persian is the only System Language, so
     --fontStack never varies by language: every component uses var(--fontStack)
     for UI text, --fontStackEnglish only where the presentation deliberately
     switches to natural Latin prose, and --monoFont for technical values. */
  --fontStackPersian: "Estedad", Tahoma, Arial, ui-sans-serif, system-ui, sans-serif;
  /* Natural Latin/English prose. Never applied to the Persian UI, and never to
     a technical identifier. */
  --fontStackEnglish: "Inter", "Segoe UI", Arial, ui-sans-serif, system-ui,
    sans-serif;
  --fontStack: var(--fontStackPersian);
  --monoFont: "Space Mono", "Cascadia Mono", "SFMono-Regular", Consolas, monospace;
  --shadow: 0 8px 28px rgba(0, 0, 0, 0.6);
  /* Extracted from component rules (no raw colors outside :root). */
  --overlayStrong: rgba(255, 255, 255, 0.18);
  --overlaySoft: rgba(255, 255, 255, 0.06);
  --overlayFaint: rgba(255, 255, 255, 0.04);
  --backdrop: rgba(0, 0, 0, 0.6);
  --backdropSoft: rgba(0, 0, 0, 0.55);
  --dangerBorderSoft: rgba(248, 113, 113, 0.4);
  --dangerBorder: rgba(248, 113, 113, 0.6);
  --dangerBorderFaint: rgba(248, 113, 113, 0.25);
  --dangerAccentSoft: rgba(244, 97, 95, 0.4);
  --dangerAccentStrong: rgba(244, 97, 95, 0.6);
  --warningTintBackground: rgba(245, 158, 11, 0.07);
  --warningTintBorder: rgba(245, 158, 11, 0.35);
  --redTintBackground: rgba(239, 68, 68, 0.08);
  --redTintBorder: rgba(239, 68, 68, 0.4);
  --okBorderSoft: rgba(74, 222, 128, 0.25);
  --skyBorderSoft: rgba(125, 211, 252, 0.25);
  --warnBorderSoft: rgba(255, 254, 253, 0.25);
  --mutedBorderSoft: rgba(138, 138, 147, 0.22);
  --scrollbarThumb: #2a2a2a;
  --scrollbarThumbHover: #3a3a3a;
  --borderFocus: #45454f;
  --accentSoft: #e6e6e6;
  --codeBackground: #101010;
  --codeText: #858585;
  --codeBlockBackground: #060608;
  --codeBlockText: #93a1a1;
  --overlaySurface: #1e1e1e;
  --overlayMedium: rgba(255, 255, 255, 0.08);
  --overlayFainter: rgba(255, 255, 255, 0.03);
  --overlayFaintest: rgba(255, 255, 255, 0.02);
  --dangerTintBackground: rgba(248, 113, 113, 0.06);
  --dangerBorderMuted: rgba(248, 113, 113, 0.3);
  --accentHover: #c9c9c9;
  --accentHoverStrong: #d6d6d6;
  --accentSoftStrong: #f1f1f1;
  --backgroundDeep: #060608;
  --codeBlockAccent: #073642;
  /* Global operational announcement bar (AI-provider availability). Deep red
     with pure white text (≈6:1 contrast) for blocking modes; amber for the
     non-blocking suspected state. */
  --announcementDangerBackground: #b91c1c;
  --announcementWarningBackground: #92600a;
  --announcementText: #ffffff;
  --announcementLinkBackground: rgba(255, 255, 255, 0.16);
  --announcementLinkBackgroundHover: rgba(255, 255, 255, 0.24);
}

/* The UI font is bound once. Persian is the only System Language, so there is
   no per-language rebinding: --fontStack is already the Persian stack in
   :root, and this rule simply keeps the binding explicit at the root element
   that Layout.html stamps from the validated catalog metadata. */
html:lang(fa) {
  --fontStack: var(--fontStackPersian);
}

* {
  box-sizing: border-box;
}

/* --- 2. Reset, Base Elements and Scrollbars --------------------------------- */

html,
body {
  margin: 0;
  padding: 0;
  background: var(--backgroundBase);
  color: var(--textPrimary);
  font-family: var(--fontStack);
  font-size: 14px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* Application viewport: on Admin shell pages (body.AppBody, set by
   layout.html) the DOCUMENT never scrolls — the Main panel and the sidebar
   navigation each own their own scrollbar. Standalone pages (Login) keep the
   normal document scroll. */
html {
  height: 100%;
}

body.AppBody {
  height: 100%;
  overflow: hidden;
}

/* Apply the active language's font stack explicitly to elements that do not
   inherit font-family by default (form controls), plus tables and dialogs. */
input,
button,
select,
textarea,
table,
dialog {
  font-family: var(--fontStack);
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 700;
}

p {
  margin: 0 0 8px;
}

::selection {
  background: var(--overlayStrong);
}

/* Minimal dark scrollbar applied to EVERY scrollable area — page body, tables,
   modals, trace panels, textareas, chat areas, dropdown lists, etc..
   The .SidebarNavigation block below keeps the same look for the sidebar. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbarThumb) transparent;
}

*::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background: var(--scrollbarThumb);
  border-radius: 6px;
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbarThumbHover);
}

/* --- 3. Application Shell and Navigation ------------------------------------ */

/* App container: the fixed Application viewport. The document does not
   scroll (body.AppBody); the Main panel and the sidebar navigation are the
   only two Application-level scroll containers. */
.App {
  display: flex;
  height: 100vh;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

.Sidebar {
  width: var(--sidebarWidth);
  flex: 0 0 var(--sidebarWidth);
  background: var(--backgroundSurface);
  border-inline-end: 1px solid var(--border);
  height: 100%;
  display: flex;
  flex-direction: column;
  /* The sidebar itself does not scroll; only .SidebarNavigation does, so the
     brand header and footer stay fixed. */
  overflow: hidden;
}

/* Brand row: the two text lines on the physical left, a fixed 35x35 logo on
   the physical right. The row is dir="ltr" in the template so that order holds
   in every UI language, while the text block restores the reading direction.
   The logo never shrinks and never moves: it is flex: 0 0 auto with a fixed
   box, so a long application name wraps inside its own column instead of
   pushing the mark off the edge. */
.SidebarBrand {
  padding: 18px 20px 14px;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 15px;
  flex: 0 0 auto;
}

.SidebarBrandText {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}

.SidebarBrandName {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.2px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.SidebarBrandTag {
  font-size: 11px;
  color: var(--textMuted);
  min-width: 0;
  overflow-wrap: anywhere;
}

.SidebarBrandLogo {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.SidebarBrandLogoImage {
  width: 36px;
  height: 36px;
  display: block;
  border-radius: var(--radius);
}

/* Only the navigation list scrolls. The element carries dir="ltr" in
   layout.html purely so its scrollbar sits at the PHYSICAL RIGHT edge in both
   page directions; .SidebarNavigationContent restores the page direction for
   the actual content, so nothing else is mirrored. */
.SidebarNavigation {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

.SidebarNavigationContent {
  padding: 10px 10px 16px;
  min-width: 0;
}

/* Minimal dark scrollbar, styled for the dark theme. */
.SidebarNavigation::-webkit-scrollbar {
  width: 6px;
}

.SidebarNavigation::-webkit-scrollbar-track {
  background: transparent;
}

.SidebarNavigation::-webkit-scrollbar-thumb {
  background: var(--scrollbarThumb);
  border-radius: 6px;
}

.SidebarNavigation::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbarThumbHover);
}

.SidebarNavigation {
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbarThumb) transparent;
}

.NavigationGroup {
  margin-bottom: 14px;
}

.NavigationGroupTitle {
  font-size: 11px;
  color: var(--textMuted);
  font-weight: 700;
  padding: 6px 10px;
  letter-spacing: 0.4px;
}

.NavigationItem {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius);
  color: var(--textSecondary);
  font-size: 13.5px;
  margin-bottom: 2px;
  transition: background 0.12s, color 0.12s;
  border: 1px solid transparent;
}

.NavigationItem:hover {
  background: var(--backgroundHover);
  color: var(--textPrimary);
}

.NavigationItem.IsActive {
  background: var(--backgroundRaised);
  color: var(--textPrimary);
}

.NavigationItem .Icon {
  flex: 0 0 18px;
  color: currentColor;
  opacity: 0.85;
}

.NavigationItem.IsActive .Icon {
  opacity: 1;
}

.SidebarFooter {
  flex: 0 0 auto;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--textMuted);
  text-align: center;
}

/* Main area: a fixed flex column — the single sticky header stack
   (Announcement bar + top Bar) sits above .MainScroll, which is the ONLY
   scroll container for page content. */
.MainArea {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.TopBar {
  height: 56px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 22px;
  border-bottom: 1px solid var(--border);
  background: var(--backgroundSurface);
  z-index: 20;
}

/* Global operational announcement bar: the first member of the Main panel's
   fixed header stack (Announcement → top bar → scrolling content). Full
   Main-panel width, never dismissible while active, wraps on narrow
   viewports (no horizontal overflow), and works in both directions. */
.AnnouncementBar {
  flex: 0 0 auto;
  background: var(--announcementDangerBackground);
  color: var(--announcementText);
  padding: 10px 22px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  z-index: 21;
}

.AnnouncementBarWarning {
  background: var(--announcementWarningBackground);
}

.AnnouncementBarHead {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-weight: 700;
}

.AnnouncementBarMode {
  font-weight: 400;
  opacity: 0.92;
}

/* Freshness / in-progress markers. They qualify the state rather than
   restating it, so they read as secondary chips beside the mode label and
   never compete with it for attention. */
.AnnouncementBarFreshness {
  font-size: 11.5px;
  font-weight: 400;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
  opacity: 0.85;
  white-space: nowrap;
}

/* Announcement Bar Actions */
/* The check-now action sits inline with the other body links; the form wrapper
   exists only to carry the CSRF token and must not add layout. */
.AnnouncementBarAction {
  display: inline;
  margin: 0;
}

/* The button lives on a saturated red or amber bar, so it must keep the bar's
   own treatment in every state. The generic ghost-button rules would drag it
   to the dark app palette on hover and active, which is unreadable here — so
   these are scoped to the bar and carry enough specificity to win, rather than
   changing .ButtonGhost globally. */
.AnnouncementBarAction .Button,
.AnnouncementBarAction .ButtonGhost {
  color: var(--announcementText);
  background: var(--announcementLinkBackground);
  border-color: transparent;
}

.AnnouncementBarAction .Button:hover,
.AnnouncementBarAction .ButtonGhost:hover,
.AnnouncementBarAction .Button:focus,
.AnnouncementBarAction .ButtonGhost:focus,
.AnnouncementBarAction .Button:active,
.AnnouncementBarAction .ButtonGhost:active {
  color: var(--announcementText);
  background: var(--announcementLinkBackgroundHover);
  border-color: transparent;
}

/* Removing the border must not remove the keyboard indicator: the ring is
   white so it stays visible against both bar colours. */
.AnnouncementBarAction .Button:focus-visible,
.AnnouncementBarAction .ButtonGhost:focus-visible {
  outline: 2px solid var(--announcementText);
  outline-offset: 2px;
}

.AnnouncementBarBody {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
}

.AnnouncementBarLink {
  color: var(--announcementText);
  background: var(--announcementLinkBackground);
  border-radius: var(--radius);
  padding: 2px 10px;
  font-weight: 700;
  text-decoration: underline;
}

.AnnouncementBarLink:hover,
.AnnouncementBarLink:focus,
.AnnouncementBarLink:active {
  color: var(--announcementText);
  background: var(--announcementLinkBackgroundHover);
}

.AnnouncementBarLink:focus-visible {
  outline: 2px solid var(--announcementText);
  outline-offset: 2px;
}

.AnnouncementBarDetails summary {
  cursor: pointer;
  opacity: 0.92;
}

.AnnouncementBarIDs {
  font-family: var(--monoFont);
  font-size: 12px;
  overflow-wrap: anywhere;
  padding: 4px 0;
}

/* The Main panel's scroll container. dir="ltr" (set in Layout.html) pins the
   scrollbar to the PHYSICAL RIGHT edge in both page directions;
   .MainScrollContent restores the page direction for the content. */
.MainScroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

.MainScrollContent {
  min-height: 100%;
  min-width: 0;
}

.TopBarLeft {
  display: flex;
  align-items: center;
  gap: 12px;
}

.TopBarUser {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--textSecondary);
}

.TopBarUserName {
  color: var(--textPrimary);
  font-weight: 300;
}

.MenuToggle {
  display: none;
}

.PageBody {
  padding: 22px;
  max-width: 1440px;
  width: 100%;
  margin: 0 auto;
}

/* --- 4. Page Layout, Headers, Breadcrumbs and Top Bar ----------------------- */

/* Page Header */
.PageHeader {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.PageHeaderTitle {
  font-size: 19px;
  font-weight: 800;
}

.PageHeaderDescription {
  color: var(--textSecondary);
  font-size: 13px;
  margin-top: 3px;
}

.PageHeaderActions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* Breadcrumbs (Inside.PageBody) */
.Breadcrumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 12px;
  color: var(--textMuted);
  margin-bottom: 14px;
}

.BreadcrumbItem {
  color: var(--textMuted);
}

a.BreadcrumbItem:hover {
  color: var(--textSecondary);
}

.BreadcrumbCurrent {
  color: var(--textPrimary);
  font-weight: 600;
}

/* Red Logout in the Header */
.LogoutButton {
  color: var(--danger) !important;
  border-color: transparent !important;
  background: transparent !important;
}

.LogoutButton .Icon {
  color: var(--danger) !important;
}

.LogoutButton:hover {
  color: var(--danger) !important;
  background: var(--dangerBackground) !important;
  border-color: var(--dangerAccentSoft) !important;
}

/* --- 5. Buttons and Actions ------------------------------------------------- */

/* Buttons */
.Button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--radius);
  border: 1px solid var(--borderStrong);
  background: var(--backgroundRaised);
  color: var(--textPrimary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.12s, border-color 0.12s, opacity 0.12s;
}

.Button:hover {
  background: var(--backgroundHover);
  border-color: var(--borderFocus);
}

.Button .Icon {
  flex: 0 0 16px;
}

.ButtonPrimary {
  background: var(--accent);
  color: var(--accentText);
  border-color: var(--accent);
}

.ButtonPrimary:hover {
  background: var(--accentSoft);
  border-color: var(--accentSoft);
}

.ButtonGhost {
  background: transparent;
  border-color: transparent;
  color: var(--textSecondary);
}

.ButtonGhost:hover {
  background: var(--backgroundHover);
  color: var(--textPrimary);
}

/* The sidebar menu toggle is a ghost icon button but must NOT show ANY hover/focus/active
   background, border, outline halo, box-shadow, or transition flicker (other ghost buttons hover
   normally). Transitions are disabled so nothing fades in after a delay. The `.Button.MenuToggle`
   compound raises specificity above the generic `.Button:hover` / `.ButtonGhost:hover` rules. A stable,
   non-fading focus-visible outline is kept only for keyboard accessibility. */
.Button.MenuToggle,
.Button.MenuToggle:hover,
.Button.MenuToggle:focus,
.Button.MenuToggle:active {
  background: transparent;
  color: var(--textSecondary);
  border-color: transparent;
  outline: none;
  box-shadow: none;
  transition: none;
}
.Button.MenuToggle:focus-visible {
  outline: 2px solid var(--borderFocus);
  outline-offset: 2px;
}

.ButtonDanger {
  color: var(--danger);
  border-color: var(--dangerBorderSoft);
  background: transparent;
}

.ButtonDanger:hover {
  background: var(--dangerBackground);
  border-color: var(--danger);
}

.ButtonSmall {
  height: 32px;
  padding: 0 10px;
  font-size: 12.5px;
}

.ButtonIcon {
  width: 34px;
  height: 34px;
  padding: 0;
}

.ButtonBlock {
  width: 100%;
}

.Button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* --- 6. Forms, Inputs, Field Helpers and Validation ------------------------- */

/* Forms */
.FormCard {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 20px;
}

.FormSection {
  margin-bottom: 22px;
}

/* PanelListTitle / SnapshotTitle: semantically distinct headings for data
   panels (insight strips, ranked lists, dashboard snapshots) that share the
   section-title look WITHOUT being form sections — the section-description
   contract applies only to real FormSectionTitle elements. */
.FormSectionTitle,
.PanelListTitle,
.SnapshotTitle {
  font-size: 14px;
  font-weight: 700;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

/* Title row with an aligned status tag/badge: flex +
   centered items + a token gap; the badge never shrinks and sits at the
   LOGICAL end of the row (RTL/LTR-safe); long titles wrap cleanly. */
.FormSectionTitleRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.FormSectionTitleRow > .FormSectionTitle {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: 0;
  min-width: 0;
}

.FormSectionTitleRow > .Tag,
.FormSectionTitleRow > .Badge {
  flex-shrink: 0;
  margin-inline-start: auto;
}

.FormSectionDescription {
  color: var(--textMuted);
  font-size: 12px;
  margin-bottom: 14px;
}

/* Inline informational/warning notice inside a settings form. */
.SettingNotice {
  font-size: 11.5px;
  color: var(--textMuted);
  background: var(--overlayFainter);
  border: 1px solid var(--border, var(--overlayMedium));
  border-radius: var(--radius);
  padding: 8px 10px;
  margin: 4px 0 12px;
  line-height: 1.8;
}

/* Informational notice (e.g. the RRF note): neutral border, NOT a red/error warning. Real
   errors use the flash/alert danger styles, which are unaffected by this change. */
.SettingNotice.SettingNoticeWarn {
  color: var(--textSecondary, var(--accentHover));
  border-color: var(--border, var(--warnBackground));
}

/* Knowledge-ingestion Prompt-injection review banner: shown on the FAQ / article edit
   form when the stored content was flagged by the deterministic injection review. Amber for a
   sensitive-content warning, red when Admin review is required (HIGH risk, embedding withheld). */
.KnowledgeReviewBox {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 12.5px;
  line-height: 1.9;
  border-radius: var(--radius);
  padding: 10px 12px;
  margin: 0 0 16px;
  color: var(--textSecondary, var(--accentHoverStrong));
  background: var(--warningTintBackground);
  border: 1px solid var(--warningTintBorder);
}

.KnowledgeReviewBox.KnowledgeReviewBoxHigh {
  background: var(--redTintBackground);
  border-color: var(--redTintBorder);
}

.KnowledgeReviewBox svg {
  flex: 0 0 auto;
  margin-top: 2px;
}

.KnowledgeReviewBox .KnowledgeReviewTitle {
  font-weight: 600;
  color: var(--textPrimary, var(--accentSoftStrong));
}

.KnowledgeReviewBox code {
  font-size: 11.5px;
  background: var(--overlaySoft);
  padding: 1px 5px;
  border-radius: 4px;
}

.FormGrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px 18px;
}

.FormField {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

.FormField.SpanFull {
  grid-column: 1 / -1;
}

.FieldLabel {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--textSecondary);
}

.RequiredMark {
  color: var(--danger);
  margin-inline-start: 3px;
}

/* A form field disabled by a dependency (e.g. reasoning-dependent controls when reasoning is off, or
   the first-Message notification text when notification is off). Dims the whole field — label + control
   + help — and blocks pointer interaction. The control itself also carries the native `disabled`
   attribute, so it is genuinely non-editable and is not submitted; this only styles it. */
.FieldDisabled {
  opacity: 0.5;
}

.FieldDisabled,
.FieldDisabled .SelectField,
.FieldDisabled .InputField,
.FieldDisabled .TextArea,
.FieldDisabled input {
  cursor: not-allowed;
}

.FieldHelp {
  font-size: 11.5px;
  color: var(--textMuted);
}

.FieldError {
  font-size: 11.5px;
  color: var(--danger);
}

.InputField,
.TextArea,
.SelectField {
  width: 100%;
  background: var(--backgroundInput);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--textPrimary);
  font-family: inherit;
  font-size: 13.5px;
  padding: 0 12px;
  height: 38px;
  transition: border-color 0.12s, background 0.12s;
}

.TextArea {
  height: auto;
  min-height: 90px;
  padding: 10px 12px;
  line-height: 1.8;
  resize: vertical;
}

.InputField:focus,
.TextArea:focus,
.SelectField:focus {
  outline: none;
  border-color: var(--borderStrong);
  background: var(--codeBackground);
}

.InputField::placeholder,
.TextArea::placeholder {
  color: var(--codeText);
}

/* Browser autofill: Chrome/edge paint a pale-blue background with dark text via an internal inset
   shadow, which breaks the dark theme. Repaint the field with the theme's input surface + primary
   Text using an inset box-shadow (the only reliable override) and stall the background transition so
   the theme colour wins. Firefox uses its own :-Moz styling and is unaffected. */
.InputField:-webkit-autofill,
.InputField:-webkit-autofill:hover,
.InputField:-webkit-autofill:focus,
.InputField:-webkit-autofill:active,
.TextArea:-webkit-autofill,
.TextArea:-webkit-autofill:hover,
.TextArea:-webkit-autofill:focus,
.SelectField:-webkit-autofill {
  -webkit-text-fill-color: var(--textPrimary);
  caret-color: var(--textPrimary);
  -webkit-box-shadow: 0 0 0 1000px var(--backgroundInput) inset;
  box-shadow: 0 0 0 1000px var(--backgroundInput) inset;
  transition: background-color 5000s ease-in-out 0s;
}

/* Datalist inputs carry technical identifiers (model ids) — never reshape
   their casing. */
.InputField[list] {
  text-transform: none;
}

.FormField.HasError .InputField,
.FormField.HasError .TextArea,
.FormField.HasError .SelectField {
  border-color: var(--dangerBorder);
}

/* Table date-range FILTER inputs only (type="date"), . The thin weight +
   uppercase is intentionally scoped here so it never affects other inputs. */
.TableDateFilterInput {
  font-weight: 100;
  text-transform: uppercase;
}

/* No case transform: options are localized catalog labels (already properly
   cased) or technical identifiers that must stay byte-identical. */
.SelectField {
  appearance: none;
  background-image: none;
  cursor: pointer;
  padding-inline-end: 12px;
}

.SelectWrap {
  position: relative;
}

.SelectWrap .Icon {
  position: absolute;
  inset-inline-start: 10px;
  top: 11px;
  pointer-events: none;
  color: var(--textMuted);
}

.SelectWrap .SelectField {
  padding-inline-start: 32px;
}

/* The chevron sits at the wrap's inline-start (i.e. the page direction). A
   select FORCED to the opposite direction — the dir="ltr" model-name selects
   on the RTL page — has its own inline axis flipped, so its inline-start
   padding lands away from the chevron and the Latin model name crowds it.
   Pad the END instead so the name clears the (right-side) chevron. This is
   TECHNICAL_VALUE direction handling, not language support. */
[dir="rtl"] .SelectWrap .SelectField[dir="ltr"] {
  padding-inline-start: 12px;
  padding-inline-end: 32px;
}

.CheckRow {
  display: flex;
  align-items: center;
  gap: 9px;
}

.CheckRow input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.CheckRow input[type="checkbox"]:disabled {
  opacity: 0.5;
}

.CheckRow label {
  font-size: 13px;
  color: var(--textSecondary);
  cursor: pointer;
}

.FormActions {
  display: flex;
  gap: 10px;
  justify-content: flex-start;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

/* Repeatable rows (FAQ alternates / article Blocks) */
.RepeatList {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.RepeatRow {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--backgroundRaised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
}

.RepeatRow .RepeatRowMain {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.RepeatRowHandle {
  color: var(--textMuted);
  font-size: 12px;
  padding-top: 8px;
  white-space: nowrap;
}

.RepeatRowRemove {
  flex: 0 0 auto;
}

/* Live Word Counters */
.FieldLabelRow {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.WordCounter {
  font-size: 11px;
  color: var(--textMuted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.WordCounter.IsOver {
  color: var(--danger);
  font-weight: 700;
}

.FormField.HasError .InputField,
.InputField.IsOver,
.TextArea.IsOver {
  border-color: var(--dangerAccentStrong);
}

/* --- 7. Cards, Stats and Empty States --------------------------------------- */

/* Cards (Index) */
.CardGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
}

.StatCard {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: border-color 0.12s, background 0.12s;
}

.StatCard:hover {
  border-color: var(--borderStrong);
  background: var(--backgroundRaised);
}

.StatCardTop {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.StatCardLabel {
  color: var(--textSecondary);
  font-size: 12.5px;
  max-width: 165px;
}

.StatCardIcon {
  color: var(--textMuted);
}

.StatCardValue {
  font-size: 26px;
  font-weight: 600;
  margin-top: auto;
}

/* Empty State */
.EmptyState {
  text-align: center;
  padding: 48px 24px;
  color: var(--textMuted);
}

.EmptyState .Icon {
  color: var(--borderStrong);
  margin-bottom: 12px;
}

.EmptyStateTitle {
  font-size: 15px;
  font-weight: 700;
  color: var(--textSecondary);
  margin-bottom: 4px;
}

.EmptyStateText {
  font-size: 13px;
  max-width: 420px;
  margin: 0 auto 14px;
}

/* --- 8. Tables, Filters, Row Menus and Pagination --------------------------- */

/* Filter Bar */
.FilterBar {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 14px 16px;
  margin-bottom: 14px;
}

.FilterRow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}

.FilterField {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 150px;
  flex: 1 1 150px;
}

.FilterField.Grow {
  flex: 2 1 220px;
}

.FilterField .FieldLabel {
  font-size: 11.5px;
}

/* Filter action buttons: ONE row at logical inline-start, aligned with the
   field height. The .FilterField base class stacks its children in a column
   (label above control), so the actions variant must force the row axis —
   otherwise apply/clear stack vertically. Wrapping stays allowed only for
   genuinely too-narrow viewports. */
.FilterActions,
.FilterField.FilterActions {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 8px;
  align-items: flex-end;
}

.FilterActions .Button {
  height: 38px;
}

/* Data Table */
.TableWrap {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  overflow: hidden;
}

.TableScroll {
  overflow-x: auto;
}

/* No case transform: cells hold localized labels and technical identifiers
   (model ids, request ids) that must render byte-identical. */
.DataTable {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.DataTable thead th {
  text-align: start;
  font-weight: 700;
  color: var(--textSecondary);
  background: var(--backgroundRaised);
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  font-size: 12px;
}

.DataTable tbody td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--textPrimary);
  vertical-align: middle;
}

.DataTable tbody tr:last-child td {
  border-bottom: none;
}

.DataTable tbody tr:hover {
  background: var(--backgroundHover);
}

/* Cost-breakdown row variants: A subtle danger tint for category rows
   that contain invalid/failed charged attempts, and a bold total row. */
.DataTable tbody tr.RowWarn {
  background: var(--dangerBackground, var(--dangerTintBackground));
}

.DataTable tbody tr.RowTotal td {
  font-weight: 700;
  color: var(--textSecondary);
  border-top: 1px solid var(--border);
}

/* Sortable Column Headers */
.SortHeader {
  padding: 0;
}

.SortLink {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  padding: 11px 14px;
  color: var(--textSecondary);
  font-weight: 700;
  white-space: nowrap;
}

.SortLink:hover {
  color: var(--textPrimary);
  background: var(--backgroundHover);
}

.SortLink.IsActive {
  color: var(--textPrimary);
}

.SortArrow {
  font-size: 10px;
  line-height: 1;
  opacity: 0.55;
}

.SortLink.IsActive .SortArrow {
  opacity: 1;
}

.CellMuted {
  color: var(--textMuted);
}

.CellPrimary {
  font-weight: 600;
}

.CellSub {
  color: var(--textMuted);
  font-size: 11.5px;
}

/* --- security active sessions (Grouped DataTable) -------------------------
   one FormCard + one DataTable; each row is a session, and each user's session rows share a single
   row-spanned user cell. Cells stack "label: value" lines; long technical values stay LTR and
   truncate/wrap so they never widen a column. The identifiers column shows the user hash + session
   fingerprint as plain uppercase monospace text (no badge background). */
.SessionTable td {
  vertical-align: top;
}

/* A stronger divider between users (first row of each user's group). */
.SessionTable tr.SessionGroupStart > td {
  border-top: 2px solid var(--borderStrong);
}

/* The acting admin's own current-session row: A gentle neutral highlight (the badge marks it too). */
.SessionTable tr.SessionRowCurrent > td {
  background: var(--backgroundHover);
}

.SessionUserCell {
  min-width: 190px;
}

/* Role/group column: keep the badge compact so it never crowds the user column. */
.SessionRoleCell {
  white-space: nowrap;
}

.SessionMetaStack {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.SessionMetaLine {
  display: flex;
  align-items: baseline;
  gap: 5px;
  min-width: 0;
}

.SessionUserName {
  font-weight: 600;
}

.SessionUserEmail,
.SessionMetaLabel,
.SessionCount {
  color: var(--textMuted);
  font-size: 11px;
}

.SessionMetaLabel {
  white-space: nowrap;
}

.SessionMetaValue {
  color: var(--textSecondary);
  font-size: 12px;
  overflow-wrap: anywhere;
}

.SessionIdentifierValue {
  font-family: var(--monoFont);
  font-size: 11.5px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--textSecondary);
  word-break: break-all;
}

.SessionActions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.CellNowrap {
  white-space: nowrap;
}

.CellActions {
  text-align: start;
  white-space: nowrap;
}

.TableActions {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  position: relative;
}

/* Row action dropdown.
   The menu uses position:Fixed and JS-computed coordinates so it overlays the
   page instead of expanding the cell / table or triggering table scroll inside
   the overflow:auto wrapper. */
.RowMenuWrap {
  position: static;
  display: inline-block;
}

.RowMenu {
  display: none;
  position: fixed;
  /* Physical viewport coordinates ON PURPOSE: PositionRowMenu (Script.js)
     computes them per open from the toggle's rect and is explicitly
     direction-aware (aligns inline-end edges in RTL, inline-start in LTR);
     these are only the pre-position defaults. */
  top: 0;
  left: 0;
  min-width: 184px;
  background: var(--backgroundRaised);
  border: 1px solid var(--borderStrong);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 1200;
  padding: 4px;
}

.RowMenu.IsOpen {
  display: block;
}

.RowMenu form {
  margin: 0;
}

.RowMenuItem {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--textSecondary);
  background: none;
  border: none;
  border-radius: var(--radius);
  text-align: start;
  cursor: pointer;
}

.RowMenuItem:hover {
  background: var(--backgroundHover);
  color: var(--textPrimary);
}

.RowMenuItem.IsDanger {
  color: var(--danger);
}

.RowMenuItem.IsDanger:hover {
  background: var(--dangerBackground);
}

.RowMenuDivider {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}

/* Pagination */
.Pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.PaginationInfo {
  font-size: 12px;
  color: var(--textMuted);
}

.PaginationLeft {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.PageSizeControl {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--textMuted);
}

.PageSizeSelect {
  height: 30px;
  /* Logical padding + a custom chevron (appearance:none) so the dropdown arrow keeps consistent
     spacing in both page directions. Background-position has no logical keywords, so the chevron
     is placed at the inline-end edge by ROOT-scoped html[dir=...] rules below. The selectors MUST
     be rooted on the html element: nested dir="ltr" scroll wrappers (.MainScroll) are ancestors of
     every page select, so a bare [dir="ltr"] rule would match even under an RTL root and mirror the
     chevron to the wrong edge. */
  padding-block: 0;
  padding-inline-start: 10px;
  padding-inline-end: 28px;
  background: var(--backgroundInput);
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23ababab' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--textPrimary);
  font-size: 12.5px;
  cursor: pointer;
}

/* ROOT_APPLICATION_DIRECTION: the chevron sits at the inline-end edge of the
   always-RTL Application root (physical left). Rooted on the html element so
   A nested dir="ltr" scroll wrapper (.MainScroll) can never mirror it. */
html[dir="rtl"] .PageSizeSelect {
  background-position: left 10px center;
}

.PaginationControls {
  display: flex;
  gap: 6px;
  align-items: center;
}

.PageLink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding: 0 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--textSecondary);
  font-size: 12.5px;
  background: var(--backgroundSurface);
}

.PageLink:hover {
  background: var(--backgroundHover);
  color: var(--textPrimary);
}

.PageLink.IsActive {
  background: var(--accent);
  color: var(--accentText);
  border-color: var(--accent);
}

.PageLink.IsDisabled {
  opacity: 0.4;
  pointer-events: none;
}

/* OpenRouter Model Table + Datalist */
.ModelToolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.ModelStatus {
  font-size: 12px;
  color: var(--textMuted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.ModelStatus.IsError {
  color: var(--danger);
}

.ModelSearch {
  max-width: 280px;
}

.ModelTableWrap {
  max-height: 420px;
  /* The fixed-layout table is always exactly the wrapper width, so it never
     needs to scroll sideways; only the 420px vertical cap scrolls. */
  overflow-x: hidden;
  overflow-y: auto;
}

/* Embedding-rebuild confirmation dialog: one label/value line per estimate
   figure (content, chunks, tokens, cost). */
.EmbeddingRebuildSummary {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 12px 0;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--backgroundRaised);
}

.EmbeddingRebuildLine {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.EmbeddingRebuildLabel {
  color: var(--textSecondary);
}

.EmbeddingRebuildValue {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.PriceCell {
  font-weight: 200;
  font-variant-numeric: normal;
  white-space: nowrap;
  direction: ltr;
  /* Numbers stay LTR but align to the page's start side (like every other
     column); match-parent resolves against the parent's direction, not this
     cell's forced LTR. */
  text-align: match-parent;
}

/* Placeholder Reference Table */
.PlaceholderToken {
  font-family: var(--monoFont);
  direction: ltr;
  unicode-bidi: embed;
  white-space: nowrap;
}

/* --- 9. Badges, Chips, Status Labels and Inline Metadata -------------------- */

/* Badges */
.Badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: 100px;
  font-size: 11.5px;
  font-weight: 300;
  border: 1px solid transparent;
  white-space: nowrap;
}

.BadgeDot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.BadgeOk {
  color: var(--ok);
  background: var(--okBackground);
  border-color: var(--okBorderSoft);
}

.BadgeInfo {
  color: var(--information);
  background: var(--informationBackground);
  border-color: var(--skyBorderSoft);
}

.BadgeWarn {
  color: var(--warn);
  background: var(--warnBackground);
  border-color: var(--warnBorderSoft);
}

.BadgeDanger {
  color: var(--danger);
  background: var(--dangerBackground);
  border-color: var(--dangerBorderFaint);
}

.BadgeMuted {
  color: var(--muted);
  background: var(--mutedBackground);
  border-color: var(--mutedBorderSoft);
}

.Tag {
  display: inline-block;
  padding: 5px 8px;
  font-size: 11px;
  color: var(--textSecondary);
  background: var(--backgroundRaised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin: 1px 0;
}

/* THE authoritative TagList component: every group of tag chips —
   server-rendered or JS-built — gets a real flex gap in both directions.
   Flex+gap is direction-agnostic (RTL/LTR safe), wraps instead of
   overflowing table cells, and never depends on Jinja whitespace. Chips
   drop their standalone micro-margin inside a list (gap owns spacing) and
   may shrink so long English tags / technical LTR tokens ellipsize instead
   of forcing horizontal overflow. */
.TagList {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-width: 0;
  vertical-align: top;
}

.TagList > .Tag {
  margin: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The status dot hugs the chip's inline-end edge, so only the inline-start
   side keeps its text padding (logical: correct in both directions). */
.Tag.TagHasStatus {
  gap: 10px;
  padding-block: 0;
  padding-inline-start: 10px;
  padding-inline-end: 0;
  border-radius: 50px;
  line-height: 24px;
}

/* Compact "+N hidden tags" badge shown after the first few tags in table/list rows so a
   record with many tags can never break the table layout. */
.Tag.TagMore {
  color: var(--textMuted);
  cursor: default;
}

/* Editable chip (tags/synonyms) with an inline remove button. Text sits at
   inline-start (8px) and the remove button at inline-end (4px); logical
   padding keeps that layout in both directions. */
.TagChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-block: 2px;
  padding-inline-start: 8px;
  padding-inline-end: 4px;
  margin: 2px;
}

.TagChip:hover {
  background: var(--backgroundHover);
}

.TagChipText {
  line-height: 1.4;
}

.TagChipRemove {
  display: inline-flex;
  align-items: center;
  /* A square icon-only button: center the glyph (the old `left` was a
     direction-sensitive physical value with no Start/end intent). */
  justify-content: center;
  height: 16px;
  padding: 0;
  font-size: 21px;
  line-height: 1;
  color: var(--textMuted);
  background: transparent;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  transition: color 0.2s ease;
}

.TagChip:hover .TagChipRemove {
  color: var(--textPrimary);
}

/* Ordered-list markers follow the ACTIVE language's numbering system:
   Persian digits for fa, Arabic-indic for ar (declared after a plain decimal
   so engines without Arabic-indic keep a valid fallback). */
.TraceAlternateList {
  margin: 8px 0 8px;
  padding-inline-start: 20px;
  font-size: 11px;
  line-height: 1.9;
  list-style-type: decimal;
}

html:lang(fa) .TraceAlternateList {
  list-style-type: persian;
}


.TraceAlternateList li {
  margin-bottom: 2px;
}

/* The customer's own question, set apart from the generated alternatives. The
   page is RTL but the label belongs at the PHYSICAL left edge, so the row is an
   explicit LTR grid -- column 1 is the left edge regardless of page direction --
   and each cell restores its own reading direction. Reversed flex would leave
   the position ambiguous once the text wraps. */
.TracePrimaryQueryItem {
  margin-bottom: 6px;
}

.TracePrimaryQueryRow {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  direction: ltr;
  padding: 4px 8px;
  border-radius: var(--radius);
  background: var(--backgroundRaised);
}

.TracePrimaryQueryLabel {
  grid-column: 1;
  justify-self: start;
  direction: rtl;
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--textMuted);
  white-space: nowrap;
}

.TracePrimaryQueryText {
  grid-column: 2;
  min-width: 0;
  direction: rtl;
  text-align: right;
  color: var(--textPrimary);
  overflow-wrap: anywhere;
}

.TracePrimaryQueryText[dir="ltr"] {
  direction: ltr;
  text-align: left;
}

/* Billing and reasoning notes as one group: the wrapper owns the spacing above
   and below, so a second note never doubles the gap and the next section never
   touches the last line. */
.TraceReasoningNotes {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
  margin-bottom: 12px;
}

/* Status Line / Inline Notes */
.InlineNote {
  font-size: 12px;
  color: var(--textMuted);
  display: flex;
  align-items: center;
  gap: 6px;
}

.DividerText {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--textMuted);
  font-size: 12px;
  margin: 14px 0;
}

.DividerText::before,
.DividerText::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.KeyStatus {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--backgroundInput);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 12px;
  font-size: 13px;
}

.KeyMask {
  font-family: var(--monoFont);
  letter-spacing: 2px;
  color: var(--textSecondary);
}

/* Inline, copy-friendly, always-LTR rendering for code-like values (external/provider IDs,
   model names, OpenRouter request/session ids) so they never break the surrounding layout
   in either page direction. */
.CodeInline {
  font-family: var(--monoFont);
  direction: ltr;
  unicode-bidi: isolate;
  word-break: break-all;
  user-select: all;
}

/* --- 10. Dialogs, Modals, Toasts and Help Boxes ----------------------------- */

/* Help / Explanation Boxes */
.HelpBox {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--backgroundRaised);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--borderStrong);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 16px;
  color: var(--textSecondary);
  font-size: 13px;
}

.HelpBox .Icon {
  color: var(--information);
  flex: 0 0 18px;
  margin-top: 1px;
}

/* `min-width: 0` is what actually lets this shrink: a flex item's automatic
   minimum is its MIN-CONTENT width, so on a narrow screen a long guide (or one
   long identifier such as Core.DetectMessageLanguage) would otherwise refuse to
   wrap, overflow the row, and push the dismiss control off the viewport. */
.HelpBox .HelpBoxBody {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: break-word;
  text-align: justify;
}

.HelpBox .HelpBoxBody strong {
  color: var(--textPrimary);
}

/* A button with `display: contents` generates no box at all: its icon still
   paints, so the control looks present, but it cannot be focused or reached by
   keyboard, and its own padding, radius and hover background never apply
   either. The dismiss control must be a real box. */
.HelpBoxClose {
  background: none;
  border: none;
  color: var(--textMuted);
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  padding: 2px;
  border-radius: var(--radius);
  flex-shrink: 0;
}

.HelpBoxClose:hover {
  color: var(--textPrimary);
  background: var(--backgroundHover);
}

.HelpBoxClose:focus-visible {
  outline: 2px solid var(--borderFocus);
  outline-offset: 2px;
}

.HelpBox.IsHidden {
  display: none;
}

/* Flash / Toasts */
.ToastStack {
  /* Bottom inline-end corner (the side away from the sidebar in both page
     directions). New toasts stack upward from the bottom and never overlap
     the sidebar. */
  position: fixed;
  bottom: 16px;
  inset-inline-end: 16px;
  z-index: 1300;
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  max-width: 360px;
}

.Toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--backgroundRaised);
  box-shadow: var(--shadow);
  font-size: 13px;
  animation: toastIn 0.2s ease;
}

.Toast .Icon {
  flex: 0 0 18px;
  margin-top: 1px;
}

.ToastClose {
  background: none;
  border: none;
  color: var(--textMuted);
  cursor: pointer;
  padding: 0;
}

.ToastSuccess {
  border-inline-start: 3px solid var(--ok);
}

.ToastSuccess .Icon {
  color: var(--ok);
}

.ToastError {
  border-inline-start: 3px solid var(--danger);
}

.ToastError .Icon {
  color: var(--danger);
}

.ToastWarning {
  border-inline-start: 3px solid var(--warn);
}

.ToastWarning .Icon {
  color: var(--warn);
}

.ToastInfo {
  border-inline-start: 3px solid var(--information);
}

.ToastInfo .Icon {
  color: var(--information);
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.Toast.IsLeaving {
  opacity: 0;
  transition: opacity 0.3s;
}

/* Dialogs */
dialog.AppDialog {
  border: 1px solid var(--borderStrong);
  border-radius: var(--radiusLarge);
  background: var(--backgroundSurface);
  color: var(--textPrimary);
  padding: 0;
  width: min(480px, 92vw);
  box-shadow: var(--shadow);
}

dialog.AppDialog::backdrop {
  background: var(--backdrop);
}

.DialogHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}

.DialogTitle {
  font-size: 15px;
  font-weight: 700;
}

.DialogBody {
  padding: 18px;
}

.DialogDescription {
  color: var(--textSecondary);
  font-size: 13px;
  margin-bottom: 14px;
}

.DialogActions {
  display: flex;
  gap: 10px;
  justify-content: flex-start;
  padding: 14px 18px;
  border-top: 1px solid var(--border);
}

/* --- 11. Authentication UI: Login, TOTP and Admin Authenticator ------------- */

/* Login Page */
.LoginShell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding: 24px;
  background:
    radial-gradient(900px 500px at 70% -10%, var(--overlayFaint), transparent),
    var(--backgroundBase);
}

/* The card is centered in the remaining space; the footer sits at the page bottom. */
.LoginMain {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.LoginCard {
  width: min(400px, 100%);
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 28px 26px;
}

/* Login page system-language note: A compact, non-interactive native-name label
   pinned above the footer at the page bottom (a flex sibling of .LoginMain, so it
   never overlaps the centered card on short viewports). It reports the system
   language; it is not a switch — the system language is changed by an
   authenticated operator on the settings page. */
.LoginLanguageNote {
  flex: 0 0 auto;
  text-align: center;
  padding-top: 14px;
  color: var(--textSecondary);
  font-size: 12.5px;
}

.LoginFooter {
  flex: 0 0 auto;
  text-align: center;
  padding-top: 12px;
  font-size: 11.5px;
  color: var(--textMuted);
}

.LoginBrand {
  text-align: center;
  margin-bottom: 22px;
}

.LoginBrandName {
  font-size: 19px;
  font-weight: 800;
}

.LoginBrandTag {
  font-size: 12.5px;
  color: var(--textMuted);
  margin-top: 4px;
}

.LoginError {
  background: var(--dangerBackground);
  border: 1px solid var(--dangerBorderMuted);
  color: var(--danger);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 12.5px;
  margin-bottom: 14px;
}

.RememberMeText {
  font-size: 12.5px;
  color: var(--textSecondary);
}

/* Admin TOTP Login: 6 Single-digit Boxes */
.TOTPField .TOTPInputs {
  display: flex;
  gap: 8px;
  direction: ltr;
  justify-content: space-around;
}

.TOTPDigit {
  width: 44px;
  height: 48px;
  flex: 0 0 auto;
  text-align: center;
  font-size: 13.5px;
  font-weight: 400;
  color: var(--textPrimary);
  background: var(--backgroundInput);
  border: 1px solid var(--borderStrong);
  border-radius: var(--radius);
}

.TOTPDigit:focus {
  outline: none;
  border-color: var(--accent);
}

/* Error state: turn the TOTP boxes red like other invalid fields (no inline styles). */
.FormField.HasError .TOTPDigit {
  border-color: var(--dangerBorder);
}

.TOTPHelp {
  margin-top: 10px;
}

/* Hide the TOTP error line when it carries no message (kept in the DOM so JS can fill it). */
.TOTPError:empty {
  display: none;
}

@media (max-width: 460px) {
  .TOTPField .TOTPInputs {
    gap: 6px;
  }

  .TOTPDigit {
    width: 40px;
    height: 46px;
    font-size: 18px;
  }
}

/* /Users ADMIN-only authenticator QR/secret modal */
/* The QR sits on a white tile so the dark theme never hides the black QR modules. */
.TOTPQRCode {
  display: flex;
  justify-content: center;
  padding: 10px;
  /* Always a WHITE quiet zone: authenticator cameras need dark-on-light
     modules regardless of the Admin theme. */
  background: #ffffff;
  border-radius: var(--radius);
  margin-bottom: 14px;
}

/* The renderer creates an <img> from the SVG data URL; the svg selector stays
   only for an intentionally supported inline-SVG fallback. */
.TOTPQRCode img,
.TOTPQRCode svg {
  display: block;
  width: 200px;
  height: 200px;
  max-width: 100%;
}

.TOTPQRCodeFallback {
  color: #16181d;
  font-size: 12.5px;
  padding: 24px 12px;
  text-align: center;
}

.TOTPSecretRow {
  display: flex;
  gap: 8px;
  align-items: center;
}

.TOTPSecret {
  flex: 1 1 auto;
  word-break: break-all;
  background: var(--backgroundInput);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  font-family: var(--monoFont);
  font-size: 12px;
  color: var(--textPrimary);
}

/* --- 12. Knowledge UI: FAQ, Articles, Review Warnings and AI Helpers -------- */

/* Admin AI Field Helpers: "Generate with AI" Buttons + Shared Modal */

/* Single-description preview box inside the AI-helper modal. */
.AISuggestionText {
  padding: 8px 10px;
  background: var(--backgroundBase);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  line-height: 1.7;
}

/* Checkbox list of generated tag/synonym suggestions inside the AI-helper modal. */
.AICheckList {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 280px;
  overflow-y: auto;
}

.AICheckRow {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: var(--backgroundRaised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}

.AICheckRow input {
  cursor: pointer;
}

/* FAQ AI Alternative-question Generator Rows */
.FAQGeneratedRow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.FAQGeneratedRow .FAQGeneratedInput {
  flex: 1 1 auto;
}

.FAQGeneratedRow .FAQGeneratedCheck {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
}

/* --- 13. Conversation UI: Chat Bubbles, Direction, History and Handoff Markers --- */

.ChatMeta {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 16px;
  margin-bottom: 8px;
}

.MetaItem {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.MetaLabel {
  font-size: 11px;
  color: var(--textMuted);
}

/* No case transform: meta values include model/request identifiers that
   must stay byte-identical. */
.MetaValue {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ChatThread {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Min-width:0 lets the flex column shrink so a long token never widens the row. */
.ChatMessage {
  display: flex;
  flex-direction: column;
  max-width: 78%;
  min-width: 0;
}

.ChatMessage.RoleUser {
  align-self: flex-start;
}

.ChatMessage.RoleAssistant {
  align-self: flex-end;
}

.ChatBubble {
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 11px 14px;
  background: var(--backgroundSurface);
  font-size: 13.5px;
  font-weight: 300;
  white-space: pre-wrap;
  /* The trace lives in a modal, so it can never reflow the bubble; these keep
     long IDs/JSON/URLs inside the bubble box and its width stable regardless. */
  box-sizing: border-box;
  max-width: 100%;
  min-width: 0;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.ChatMessage.RoleAssistant .ChatBubble {
  background: var(--backgroundRaised);
}

/* Silent first-Message handoff: an audit note shown in place of the (intentionally
   non-delivered) assistant answer, so a suppressed turn never renders an empty bubble. */
.SuppressedHandoffNote {
  border-style: dashed;
  font-style: italic;
  background: var(--backgroundInput);
}

.ChatMessageHead {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
  font-size: 11.5px;
  color: var(--textMuted);
}

.TraceGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
  margin-bottom: 10px;
}

.TraceLabel {
  color: var(--textMuted);
  font-size: 11px;
}

.TraceValue {
  color: var(--textPrimary);
  font-weight: 600;
}

.TraceChunk {
  border-top: 1px solid var(--border);
  padding-top: 8px;
  margin-top: 8px;
}

/* Plain text / context / Prompt / chunk-snapshot preview box. Renamed from the
   misnamed .codeBlock — these never display code. It scrolls rather
   than clips, so the FULL stored text is always reachable. */
.TextBlock {
  background: var(--backgroundDeep);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  font-family: var(--fontStack);
  font-size: 12px;
  color: var(--textSecondary);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  max-height: 360px;
  overflow: auto;
  text-align: start;
}

/* Plain raw-code / raw-JSON block: LTR monospace, single readable colour, NO syntax highlighting and
   NO special/bright colour scheme — it uses the same deep background + secondary text as the rest of the
   Admin blocks (.TextBlock / .ErrorProse), so it never clashes with the UI. Content is always escaped by
   Jinja before it reaches this element. */
.JSONBlock {
  background: var(--backgroundDeep);
  color: var(--textSecondary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  font-family: var(--monoFont);
  font-size: 12px;
  line-height: 1.65;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  tab-size: 2;
  max-height: 480px;
  overflow: auto;
  direction: ltr;
  text-align: start;
}

/* Left-to-right table cell for technical/English content (e.g. the errors list message + details
   columns), so English/stack text reads correctly inside tables in either page direction
   without any inline style. */
.CellLTR {
  direction: ltr;
  text-align: start;
}

/* Monospaced, LTR, hard-wrapping wrapper so long ids never break narrow layouts
  . */
.LinkPlain {
  color: var(--textPrimary);
  text-decoration: none;
}

.LinkPlain:hover {
  text-decoration: underline;
}

/* ---- Error detail page (/Errors/View) ---------------------------------------------------------- */

/* User-state / Sentiment Analysis Line Under User Bubbles */
/* Compact badges + a "تحلیل احساس کاربر" details button, wrapping under the bubble
   without widening it. The Conversation-level card reuses .FormCard. */
.UserStateLine {
  margin-top: 6px;
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}

/* Distinct alert banner under a user message whose sentiment reads as strong dissatisfaction /
   frustration / abuse — makes the "needs human empathy" state impossible for an operator to miss.
   Full-width row below the badges; used in both conversation view and ConversationLab. */
.UserStateWarn {

  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 6px 10px;
  border: 1px solid var(--dangerBorder);
  border-radius: var(--radius);
  background: var(--dangerBackground);
  color: var(--danger);
  font-size: 12px;
}

/* The human-review note is INFORMATIONAL, not an alarm: a human is needed for a
   procedural reason while the customer is calm. Styling it like the severe
   banner would restate the very claim this state exists to avoid making. */
.UserStateReviewNote {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 6px 10px;
  border: 1px solid var(--borderStrong);
  border-radius: var(--radius);
  background: var(--backgroundMuted, var(--backgroundHover));
  color: var(--textSecondary, var(--textMuted));
  font-size: 12px;
}

.UserStateReviewNote svg {
  flex: 0 0 auto;
}

.UserStateWarn svg {
  flex: 0 0 auto;
}

.UserStateLine .Button {
  margin-inline-start: auto;
}

.UserStateCard .ChatMeta {
  margin-bottom: 0;
}

/* Per-turn Intent/Resolution Summary Card */
/* Conversation-detail box listing the IntentResolutionHistory turn summaries. Reuses .FormCard
   for the outer shell; each turn is a bordered block with a small head (turn badge + date +
   language) and stacked label/value rows. Turn summaries only — no Prompt/Constraint audit. */
.IntentResolutionList {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.IntentResolutionItem {
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--borderStrong);
  border-radius: var(--radius);
  padding: 10px 12px;
  background: var(--backgroundRaised, var(--overlayFaintest));
}

.IntentResolutionItemHead {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.IntentResolutionRow {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin-top: 4px;
  line-height: 1.85;
}

.IntentResolutionLabel {
  flex: 0 0 auto;
  min-width: 64px;
  color: var(--textMuted);
  font-size: 12px;
}

.IntentResolutionText {
  flex: 1 1 auto;
  font-size: 13px;
}

.IntentResolutionEmpty {
  padding: 6px 2px;
}

/* Dynamic Message/Textarea Direction and Font */
/* Only chat message bodies and the composer switch direction (per detected
   message language, toggled by Script.js); the rest of the Admin UI follows
   the page direction. Chat CONTENT fonts follow the message, not the Admin UI:
   an RTL body is Perso-Arabic script and takes the Persian stack, while an LTR
   body is natural Latin prose and takes the English stack. */
.MessageTextRTL {
  direction: rtl;
  text-align: start;
  unicode-bidi: plaintext;
  font-family: var(--fontStackPersian);
}


.MessageTextLTR {
  direction: ltr;
  text-align: start;
  unicode-bidi: plaintext;
  font-family: var(--fontStackEnglish);
}

.ChatInputRTL {
  direction: rtl;
  text-align: start;
  font-family: var(--fontStackPersian);
}


.ChatInputLTR {
  direction: ltr;
  text-align: start;
  font-family: var(--fontStackEnglish);
}

/* Handoff Timeline Marker in the Chat*/
.HandoffMarker {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 0;
}

.HandoffMarkerLine {
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}

.HandoffMarkerLabel {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--warn);
  padding: 3px 12px;
  border: 1px solid var(--warn);
  border-radius: 999px;
}

.HandoffMarkerTag {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--textMuted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1px 6px;
}

.SummaryText {
  white-space: pre-wrap;
  max-height: 50vh;
  overflow-y: auto;
  line-height: 1.9;
}

/* --- 14. Trace UI: Trace Modal, Tabs, JSON Blocks and Sent-to-Model View ---- */

/* Integration-report service tabs (reuses the trace-tab look; anchors). */
/* Model-catalog supported-parameter chips: localized, wrapping, one per token
   (never a single raw comma-separated string). */
.ModelParameterChip,
.ModelEffortChip,
.ModelModalityChip {
  display: inline-block;
  margin: 1px 3px 1px 0;
  padding: 1px 6px;
  border-radius: var(--radius);
  background: var(--backgroundRaised);
  border: 1px solid var(--border);
  font-size: 11px;
  white-space: nowrap;
}

.ModelEffortChip {
  font-variant-numeric: tabular-nums;
}

/* --- Grouped-column model catalog table: A two-row grouped header (Model /
   modalities / capacity / pricing / capabilities / details toggle) over one
   data row + one collapsed details row per model. Fixed layout with column
   width hints keeps the table inside its wrapper (which only scrolls
   vertically); tablet/mobile widths collapse rows into stacked cards. --- */
.ModelTable {
  table-layout: fixed;
  width: 100%;
}

.ModelTable th,
.ModelTable td {
  vertical-align: top;
  word-break: break-word;
}

/* The fixed-layout table is always exactly its container width, so cell
   content must fit by WRAPPING (never by widening the table into a sideways
   scroll). Long values break anywhere and the otherwise-nowrap price cell is
   allowed to wrap here, so no cell overflows its column at the widths where
   the table renders. Below the card breakpoint the table reflows to stacked
   cards instead. */
.ModelTable td {
  overflow-wrap: anywhere;
}

.ModelTable .PriceCell {
  white-space: normal;
}

/* Ten leaf columns: headers may wrap instead of forcing overflow. */
.ModelTable thead th {
  white-space: normal;
}

/* Grouped header cells span their sub-columns (scope="colgroup"): centered,
   with a direction-safe Start border marking each group boundary. */
.ModelColumnGroupHeader {
  text-align: center;
  border-inline-start: 1px solid var(--border);
}

/* The sub-column header row reads slightly smaller than the group row. */
.ModelTable thead tr + tr th {
  font-size: 11px;
  font-weight: 600;
}

/* Column width hints for the fixed layout: the model identity and the
   capability chips need room; the seven numeric/modality columns share the
   rest evenly. */
.ModelColumnModel {
  width: 19%;
}

.ModelColumnCapabilities {
  width: 15%;
}

.ModelColumnDetails {
  width: 9%;
}

/* Model name + raw model ID are TECHNICAL LTR values in every UI language:
   left-aligned, never case-transformed, wrapping safely
   instead of overflowing. The raw id stays byte-identical. */
.ModelCellModel {
  direction: ltr;
  text-align: left;
  text-transform: none;
}

.ModelCellModel .CellPrimary,
.ModelCellModel .CellSub {
  overflow-wrap: anywhere;
}

/* Raw id sub-line: the LTR id plus its compact copy button. */
.ModelIDLine {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}

.ModelCopyButton {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
}

/* Numeric capacity/pricing cells: aligned digits, localized placeholder. */
.ModelCellNumber {
  font-variant-numeric: tabular-nums;
}

/* Pricing-line labels (details row only): allowed to wrap so a long
   localized label can never force horizontal overflow at narrow widths or
   200% zoom — the price VALUE keeps its own nowrap + LTR. */
.ModelCellKey {
  color: var(--textMuted);
  font-size: 10.5px;
  font-weight: 600;
}

.ModelChips {
  display: flex;
  flex-wrap: wrap;
}

/* Per-row "more details" disclosure button: chevron flips while expanded;
   keyboard focus matches the Application-wide focus outline. */
.ModelDetailsToggle .Icon {
  transition: transform 0.15s ease;
}

.ModelDetailsToggle[aria-expanded="true"] .Icon {
  transform: rotate(180deg);
}

.ModelDetailsToggle:focus-visible,
.ModelCopyButton:focus-visible {
  outline: 2px solid var(--borderFocus);
  outline-offset: 2px;
}

/* Collapsed details row: four titled groups — parameters | reasoning
   levels | technical modalities | pricing. Desktop: A three-column grid
   with the (chip-heavy) parameters group spanning the full first row;
   minmax(0, 1fr) tracks make overflow impossible. Tablet/mobile (and
   200% zoom, which lands in the ≤900px stacked-card mode) collapse to
   one column. */
.ModelDetailsRow > .ModelDetailsCell {
  background: var(--backgroundRaised);
  border-bottom: 1px solid var(--border);
}

.ModelDetailsLayout {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px 24px;
}

/* Parameters group: Chip-heavy, so it owns the full first grid row. */
.ModelDetailsSectionWide {
  grid-column: 1 / -1;
}

.ModelDetailsSection {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.ModelDetailsSectionTitle {
  color: var(--textMuted);
  font-size: 12px;
  font-weight: 600;
}

.ModelDetailsText {
  font-size: 12px;
  line-height: 1.7;
  overflow-wrap: anywhere;
}

/* Pricing group: one label/value line per price with a FIXED semantic
   alignment — the label sits at the inline Start, the (LTR "$" +
   five-decimal) value at the inline end — identical in LTR and RTL. */
.ModelDetailsPricing {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ModelDetailsPricingLine {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

/* Turn each model row into a stacked card, labeling every cell with its
   "group · column" header (data-Th) so no information is lost when the grouped
   columns collapse. The ten-column pricing table needs ~900px of usable width
   to render every value on one line without clipping; with the app sidebar in
   view that is only available above ~1260px, so the table reflows to cards
   below that AND on tablet/mobile — nothing ever scrolls sideways or clips,
   including at 200% zoom. */
@media (max-width: 1259.98px) {
  .ModelDetailsLayout {
    grid-template-columns: minmax(0, 1fr);
  }

  .ModelTable,
  .ModelTable tbody,
  .ModelTable tr,
  .ModelTable td {
    display: block;
    width: 100%;
  }

  .ModelTable colgroup,
  .ModelTable thead {
    display: none;
  }

  /* Collapsed details rows must stay hidden even though the card layout
     forces row display (the hidden attribute wins here). */
  .ModelTable tr[hidden] {
    display: none;
  }

  .ModelRow {
    border: 1px solid var(--border);
    border-radius: var(--radiusLarge);
    padding: 8px 12px;
    margin-bottom: 10px;
  }

  /* An expanded details row reads as the continuation card of its row. */
  .ModelDetailsRow {
    border: 1px dashed var(--border);
    border-radius: var(--radiusLarge);
    padding: 8px 12px;
    margin: -4px 0 10px;
  }

  .ModelDetailsRow > .ModelDetailsCell {
    background: transparent;
    border-bottom: none;
  }

  .ModelTable td {
    border: none;
    padding: 4px 0;
  }

  .ModelTable td[data-Th]::before {
    content: attr(data-Th);
    display: block;
    color: var(--textMuted);
    font-size: 10.5px;
    font-weight: 700;
    margin-bottom: 2px;
  }
}

.ReportDomainTabs,
.SettingTabs {
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.ReportDomainTabs .TraceTab,
.SettingTabs .TraceTab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
}

/* --- report page SECTIONS (The flat replacement for sub-Tabs) ------------ */
.ReportSection {
  border-top: 1px solid var(--border);
  padding-top: 14px;
}

.ReportSectionHead {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}

.ReportSectionTitle {
  font-size: 14.5px;
  font-weight: 700;
}

/* Metric-scope tag: period vs snapshot vs all-time, always visible. */
.ScopeTag {
  font-size: 10.5px;
  color: var(--textMuted);
}

.ReportCallout {
  margin-bottom: 10px;
}

.ChecklistRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}

.ChecklistRow:last-child {
  border-bottom: none;
}

.ChecklistLabel {
  color: var(--textSecondary);
  font-size: 13px;
}

.ProgressPanel {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 12px 16px;
}

.ProgressHead {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
  color: var(--textSecondary);
  margin-bottom: 8px;
}

.ProgressTrack {
  height: 8px;
  border-radius: 999px;
  background: var(--backgroundRaised);
  overflow: hidden;
}

.ProgressFill {
  height: 100%;
  border-radius: 999px;
  background: var(--accent, #4ade80);
}

.RankedList {
  margin: 0;
  padding-inline-start: 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.RankedItem {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.RankedLabel {
  color: var(--textSecondary);
  font-size: 13px;
}

.RankedValue {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Chart prose: the rendered description (above) and caption (below). */
.ChartDescription {
  color: var(--textMuted);
  font-size: 12px;
  margin-bottom: 8px;
}

.ChartCaption {
  color: var(--textMuted);
  font-size: 11.5px;
  margin-top: 8px;
}

/* Disabled-dependency collapsed section on /Setting/Models. */
.DisabledDependencyDetails {
  margin-top: 10px;
}

.DisabledDependencyDetails > summary {
  cursor: pointer;
}

.DisabledDependencyList {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 2px 0;
}

.DisabledDependencyRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  color: var(--textMuted);
  font-size: 12.5px;
}

/* Only the tab bar itself may scroll horizontally on very narrow screens; the
   page never overflows. */
.SettingTabs {
  overflow-x: auto;
}

/* Trace tabs (Sent-To-Model vs internal trace)*/
.TraceTabs {
  display: flex;
  gap: 6px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.TraceTab {
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--textMuted);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 8px 12px;
  cursor: pointer;
}

.TraceTab.IsActive {
  color: var(--textPrimary);
  border-bottom-color: var(--textPrimary);
}

.IDText {
  text-transform: none;
  font-family: var(--monoFont);
  direction: ltr;
  unicode-bidi: embed;
  word-break: break-all;
  overflow-wrap: anywhere;
}

/* Response-trace Dashboard Modal */
dialog.AppDialog.TraceDialog {
  width: min(1100px, 95vw);
  max-height: 92vh;
}

.TraceDialog .DialogBody {
  max-height: 76vh;
  overflow-y: auto;
}

.TraceSection {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 12px;
  overflow: hidden;
}

.TraceSectionHead {
  padding: 9px 12px;
  background: var(--backgroundRaised);
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  font-size: 12.5px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.TraceSectionBody {
  padding: 12px;
}

.TraceKeyValueGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 10px;
}

.TraceKeyValueGrid + * {
  margin-top: 10px;
}

/* The token-arithmetic sentence sits INSIDE the key/value grid, directly under
   the figures it explains. It must span every column: dropped into a single
   auto-fill cell it would wrap to a 190px column and read as a stray value. */
.TraceKeyValueGrid > .TraceTokenEquation {
  grid-column: 1 / -1;
  margin-top: 2px;
}

.TraceKeyValue {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.TraceKeyValue .Key {
  font-size: 11px;
  color: var(--textMuted);
}

/* No case transform: trace values carry technical identifiers. */
.TraceKeyValue .Value {
  font-size: 12px;
  color: var(--textPrimary);
  font-weight: 400;
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Timing tab: muted nested sub-measurements (search timers, provider roundtrip) and the
   full-width wall-clock summary rows, so parent stages stay visually distinct from children. */
.TraceKeyValueSub {
  grid-column: 1 / -1;
  flex-direction: row;
  justify-content: space-between;
  gap: 12px;
  padding-inline-start: 16px;
}

.TraceKeyValueSub .Key,
.TraceKeyValueSub .Value {
  font-size: 11px;
  color: var(--textMuted);
}

/* Interval-span tree (Timing tab): a grandchild span (e.g. the provider round
   trip inside generation inside its parent) indents one extra step under the
   muted child styling. Indentation is logical — it follows the text direction. */
.TraceKeyValueSub.TraceTimingSpanNested {
  padding-inline-start: 32px;
}

.TraceKeyValueSummary {
  grid-column: 1 / -1;
  flex-direction: row;
  justify-content: space-between;
  gap: 12px;
}

.TraceKeyValueSummary .Key {
  font-size: 12px;
}

.TraceKeyValueTotal {
  border-top: 1px solid var(--border);
  padding-top: 8px;
  margin-top: 2px;
}

.TraceKeyValueTotal .Key,
.TraceKeyValueTotal .Value {
  font-weight: 600;
  color: var(--textPrimary);
}

/* --- API key table (scopes / Conversation access Split) --------------------
   scope tags and the Conversation-access badge stack vertically, one item per
   line, so long scope lists stay readable and rows align. The key PREVIEW is
   uppercased purely visually — the DOM text keeps the key's exact case. */
.TagStack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.KeyPreviewUpper {
  text-transform: uppercase;
}

/* The final destructive action in an action cell is separated from the ordinary
   actions above it, so "permanently revoke" never sits flush against a routine
   control. Logical spacing keeps this correct in both RTL and LTR. */
.ActionDestructive {
  margin-block-start: 8px;
  padding-block-start: 8px;
  border-block-start: 1px solid var(--border);
}

/* --- trace data tables (Language / timing Redesign) ------------------------
   one real table renderer behind the language and timing tabs: Consistent
   headers, borders, row heights and alignment. Wide tables scroll inside their
   own wrapper (the page never scrolls horizontally); on narrow screens each row
   stacks into a labelled card via the per-cell data-label attribute. */
.TraceTableWrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.TraceKeyValueGrid + .TraceTableWrap,
.TraceTableWrap + .TraceKeyValueGrid {
  margin-top: 10px;
}

.TraceDataTable {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.TraceDataTable th,
.TraceDataTable td {
  padding: 8px 10px;
  text-align: start;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
  min-height: 34px;
}

.TraceDataTable thead th {
  background: var(--backgroundRaised);
  color: var(--textMuted);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.TraceDataTable tbody tr:last-child td {
  border-bottom: none;
}

.TraceDataTable td {
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Numeric columns: tabular digits, aligned to the reading end. */
.TraceDataTable th.IsNumeric,
.TraceDataTable td.IsNumeric {
  text-align: end;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --- Technical-value modifiers ---------------------------------------------
   the trace modal's canonical technical cell is .TraceMonospaceEllipsis (see the
   base rule further down), with semantic modifiers per identifier kind. These
   modifiers only vary the maximum width, never the family/size/direction, so two
   identifiers in the same modal can never look like different kinds of data. */
.TraceRequestIDCell,
.TraceHashCell {
  max-width: 22ch;
}

.TraceIdentifierCell {
  max-width: 28ch;
}

/* --- Timing timeline relationship indentation -----------------------------
   A child stage is indented through this semantic class, never by injecting a
   decorative arrow into the Text. Indentation is a VISUAL reinforcement only:
   the execution column always states the relationship explicitly, so the fact
   survives for screen-reader users and in the stacked mobile layout. */
.TraceTimelineStage {
  display: inline-block;
}

.TraceTimelineChild {
  padding-inline-start: 18px;
  position: relative;
  color: var(--textMuted);
}

.TraceTimelineChild::before {
  content: "";
  position: absolute;
  inset-inline-start: 6px;
  top: 0.55em;
  width: 6px;
  height: 6px;
  border-inline-start: 1px solid var(--border);
  border-block-end: 1px solid var(--border);
}

/* Stacked mobile rows: the indent would fight the card layout, so relationship
   is carried by the execution cell alone. */
@media (max-width: 720px) {
  .TraceTimelineChild {
    padding-inline-start: 0;
  }

  .TraceTimelineChild::before {
    display: none;
  }
}

.TraceTermStatus {
  display: inline-flex;
  gap: 4px;
  flex-wrap: wrap;
}

/* Narrow screens: stack each row into a labelled card instead of forcing a
   nine-column table into 390px. Every cell prints its column header from
   data-label, so nothing loses meaning when the grid collapses. */
@media (max-width: 720px) {
  .TraceDataTable thead {
    display: none;
  }

  .TraceDataTable,
  .TraceDataTable tbody,
  .TraceDataTable tr,
  .TraceDataTable td {
    display: block;
    width: 100%;
  }

  .TraceDataTable tr {
    border-bottom: 1px solid var(--border);
    padding: 6px 0;
  }

  .TraceDataTable tbody tr:last-child {
    border-bottom: none;
  }

  .TraceDataTable td {
    border-bottom: none;
    padding: 4px 10px;
  }

  .TraceDataTable td.IsNumeric {
    text-align: start;
  }

  .TraceDataTable td::before {
    content: attr(data-Label);
    display: block;
    font-size: 10.5px;
    color: var(--textMuted);
    margin-bottom: 2px;
  }
}

/* --- translation comparison (Language tab, section B) ----------------------
   original message, faithful system-language translation and normalized search
   query side by side; stacks vertically when space runs out. Each value block
   decides its own direction (dir="auto") so perso-Arabic reads RTL and a Latin
   original reads LTR inside the same row. */
.TraceCompareGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}

.TraceCompareCell {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  background: var(--backgroundRaised, var(--overlayFaintest));
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.TraceCompareLabel {
  font-size: 11px;
  font-weight: 700;
  color: var(--textMuted);
}

/* Query / translation text: wraps, never overflows, direction from content. */
.TraceQueryText {
  font-size: 12px;
  line-height: 1.7;
  color: var(--textPrimary);
  word-break: break-word;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* Numbered query list (legacy layout, still used by older sections). */
.TraceQueryList {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.TraceQueryItem {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
}

.TraceQueryItemHead {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--textMuted);
  margin-bottom: 4px;
}

.TraceQueryItemMeta {
  margin-top: 6px;
  font-size: 11px;
  color: var(--textMuted);
}

/* Collapsible trace sections (native details/summary). */
.TraceSectionCollapsible > summary.TraceSectionHead {
  cursor: pointer;
  list-style: none;
}

.TraceSectionCollapsible > summary.TraceSectionHead::-webkit-details-marker {
  display: none;
}

.TraceSectionCollapsible > summary.TraceSectionHead::before {
  content: "◂";
  font-size: 11px;
  color: var(--textMuted);
  transition: transform 0.15s ease;
}

.TraceSectionCollapsible[open] > summary.TraceSectionHead::before {
  transform: rotate(-90deg);
}

.TraceChunkCard {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  margin-bottom: 8px;
}

/* Redesigned sent-chunk card: A clean header (icon + title + subtitle on one side; status,
   rerank rank + FAQ match-count badges on the other), a single muted meta line, an icon link line,
   the hydrated body, then collapsible matched questions + scoring details. No tag-wall; dark theme. */
.TraceSentCard {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  margin-bottom: 10px;
  background: var(--backgroundRaised, var(--overlayFaintest));
}

.TraceSentCardHeader {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.TraceSentCardTitleWrap {
  display: flex;
  align-items: start;
  min-width: 0;
}

.TraceSentCardTitleText {
  min-width: 0;
}

.TraceSentCardTitle {
  font-size: 13px;
  line-height: 25px;
  font-weight: 600;
  color: var(--textPrimary);
}

.TraceSentCardSubtitle {
  font-size: 11.5px;
  color: var(--textMuted);
}

.TraceSentCardBadges {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* Retrieval candidate badges. The row wraps naturally, so a card shows only
   the badges it actually has: an absent optional badge appends nothing rather
   than reserving an empty column. The selection-status badge is always
   present because it always carries a real status. */
.TraceSentCardBadges.TraceCandidateBadges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}


/* AI-call card header: purpose badge + call-kind badge + sequence badge as
   ONE coherent pill row. The order is PHYSICAL (direction:ltr + order): the
   purpose badge is anchored at the physical LEFT edge — including on RTL
   Persian pages — and the sequence badge sits at the physical right; each
   badge's own text restores the page direction. */
/* --- AI-call card header (Two physical Zones) ------------------------------
   the header is a GRID with explicit physical columns rather than flex `order`
   values, which invert confusingly under RTL. The container is physically LTR so
   "Column 1" always means the physical left; each badge re-establishes its own
   Text direction so Persian/Arabic labels still read correctly inside it.

     Physical left  : call purpose (e.g. Combined pre-retrieval Analysis)
     physical right : sequence number + call kind, kept adjacent as one cluster

   Column 1 takes the free space, so the right cluster is pinned to the right
   edge and its two badges never drift apart. */
.TraceChunkCard .TraceAICallCardHeader {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 8px;
  direction: ltr;
}

html[dir="rtl"] .TraceAICallCardHeader > * {
  direction: rtl;
}

.TraceAICallCardHeader .TraceAICallPurposeBadge {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  /* A long purpose truncates on one line; the complete text stays available
     through the title tooltip and the accessible name. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Physical order, right to left: sequence, then kind, then free space, then
   the purpose pinned to the left edge. The grid is explicitly LTR so these
   column numbers are physical positions, not logical ones -- column 3 is the
   right edge on an RTL page too. */
.TraceAICallCardHeader .TraceAICallKindBadge {
  grid-column: 2;
  grid-row: 1;
}

.TraceAICallCardHeader .TraceAICallSequenceBadge {
  grid-column: 3;
  grid-row: 1;
}

/* Narrow screens: the two zones stack, purpose first (it is the primary
   identity), then the sequence + kind cluster on its own row. */
@media (max-width: 560px) {
  /* The free-space column is kept so the second row's cluster stays pinned to
     the physical right; justify-content: start would drag it left instead. */
  .TraceChunkCard .TraceAICallCardHeader {
    grid-template-columns: 1fr auto auto;
  }

  /* Rows are stated explicitly: auto-placement would follow DOM order and put
     the purpose last, giving three rows instead of two. Row 1 is the purpose
     across the full width; row 2 is the kind + sequence cluster, still pinned
     to the physical right by the free-space column. */
  .TraceAICallCardHeader .TraceAICallPurposeBadge {
    grid-column: 1 / -1;
    grid-row: 1;
    white-space: normal;
  }

  .TraceAICallCardHeader .TraceAICallKindBadge {
    grid-column: 2;
    grid-row: 2;
  }

  .TraceAICallCardHeader .TraceAICallSequenceBadge {
    grid-column: 3;
    grid-row: 2;
  }
}

/* The sequence + purpose badges share the .Badge pill geometry (height,
   padding, border, typography) so the header never mixes a bare tag with
   pill badges. */
.TraceAICallSequenceBadge,
.TraceAICallPurposeBadge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: 100px;
  font-size: 11.5px;
  font-weight: 300;
  line-height: 1.6;
  border: 1px solid var(--border);
  background: var(--backgroundRaised);
  white-space: nowrap;
}

.TraceAICallSequenceBadge {
  color: var(--textMuted);
  font-variant-numeric: tabular-nums;
}

.TraceAICallPurposeBadge {
  color: var(--textPrimary);
}

.TraceSentCardMeta {
  font-size: 11.5px;
  color: var(--textMuted);
  margin-bottom: 8px;
  line-height: 1.85;
}

.TraceSentCardLinks {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.TraceSentCardBody {
  margin-bottom: 6px;
}

.TraceSentCardDetails,
.TraceMatchedQuestions {
  margin-top: 6px;
}

.TraceSentCardDetails>summary,
.TraceMatchedQuestions>summary {
  cursor: pointer;
  font-size: 12px;
  color: var(--textMuted);
  padding: 4px 0;
  user-select: none;
}

.TraceSentCardDetails>summary:hover,
.TraceMatchedQuestions>summary:hover {
  color: var(--textPrimary);
}

.TraceSentCardDetails[open]>summary,
.TraceMatchedQuestions[open]>summary {
  margin-bottom: 8px;
}

.TraceMatchedQuestions ul {
  margin: 4px 0 0;
  padding-inline-start: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.TraceMatchedQuestions li {
  font-size: 12.5px;
  color: var(--textPrimary);
  line-height: 1.7;
}

/* Handoff-reason checklist (trace modal): every possible handoff reason rendered as a DISABLED
   checkbox; the reason(s) that actually fired this turn are checked + active-styled, the rest stay
   muted. Dark checkbox styling keeps the disabled boxes clearly visible on the dark surface. */
.TraceReasonChecklist {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.TraceReasonCheck {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundInput);
  font-size: 12.5px;
  color: var(--textMuted);
  cursor: default;
}

.TraceReasonCheck input[type="checkbox"] {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--accent);
  opacity: 0.9;
  cursor: default;
}

.TraceReasonCheck.IsActive {
  border-color: var(--textSecondary);
  background: var(--backgroundRaised);
  color: var(--textPrimary);
  font-weight: 700;
}

/* A configured-but-disabled handoff condition: shown for completeness but dimmed. */
.TraceReasonCheck.IsMuted {
  opacity: 0.55;
}

/* Threshold/value or "disabled" note pinned to the far (inline-end) edge of a condition row. */
.TraceReasonCheck .TraceReasonMeta {
  margin-inline-start: auto;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--textMuted);
  direction: ltr;
  text-align: start;
}

.TraceReasonCheck.IsActive .TraceReasonMeta {
  color: var(--textSecondary);
}

/* Evaluation-case KnowledgeContent search helper: A text box + a clickable result list; clicking a
   result appends its id to the "expected ids" field. */
.EvaluationKnowledgeSearch {
  margin-top: 8px;
}

.EvaluationContentKnowledgeResults {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 6px;
}

.EvaluationContentKnowledgeResult {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  padding: 7px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundInput);
  color: var(--textPrimary);
  font-size: 12.5px;
  text-align: start;
  cursor: pointer;
}

.EvaluationContentKnowledgeResult:hover {
  border-color: var(--textSecondary);
  background: var(--backgroundRaised);
}

.EvaluationContentKnowledgeResultHead {
  display: flex;
  align-items: center;
  gap: 8px;
}

.EvaluationContentKnowledgeResultTitle {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.EvaluationContentKnowledgeResultSnippet {
  font-size: 11.5px;
  color: var(--textSecondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.EvaluationContentKnowledgeResultMeta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.EvaluationContentKnowledgeResultCategory {
  font-size: 11px;
  color: var(--textMuted);
}

.EvaluationContentKnowledgeResultID {
  font-size: 11px;
  color: var(--textMuted);
}

.EvaluationKnowledgeEmpty {
  font-size: 12px;
  color: var(--textMuted);
  padding: 4px 2px;
}

/* Selected expected-content chips: removable pills above the search box. */
.EvaluationContentKnowledgeChips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}

.EvaluationContentKnowledgeChip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundRaised);
  font-size: 12px;
  max-width: 100%;
}

.EvaluationContentKnowledgeChipTitle {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 220px;
}

.EvaluationContentKnowledgeChipID {
  font-size: 10.5px;
  color: var(--textMuted);
}

.EvaluationContentKnowledgeChipRemove {
  border: none;
  background: transparent;
  color: var(--textMuted);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 0 2px;
}

.EvaluationContentKnowledgeChipRemove:hover {
  color: var(--danger);
}

/* Trace warning/note text: compact, readable typography. The spacing comes from the
   .TraceWarnCompact modifier (replacing the old per-element inline style="margin-top:8px"), so the
   base rule stays layout-free and reusable. */
.TraceWarn {
  color: var(--warn);
  white-space: pre-wrap;
  font-size: 12px;
  line-height: 1.8;
  max-width: 100%;
}

.TraceError {
  color: var(--danger);
  white-space: pre-wrap;
  font-size: 12px;
  line-height: 1.8;
  max-width: 100%;
}

.TraceWarnCompact {
  margin-top: 8px;
  margin-bottom: 8px;
}

/* Polite-closure / informational note in the handoff tab: A calm muted line, NOT a
   warning colour, so a thanks/closing turn does not look like a problem. */
.TraceNote {
  color: var(--textSecondary);
  white-space: pre-wrap;
  font-size: 12px;
  line-height: 1.8;
  max-width: 100%;
}

/* Expired-Knowledge fallback badge in the retrieval trace: A small amber pill marking that the
   answer (or the consultation) drew on EXPIRED, past knowledge rather than current Knowledge.
   Theme-aware through the shared warn/border tokens. */
.TraceExpiredBadge {
  display: inline-block;
  color: var(--warn);
  background: var(--warnBackground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
  padding: 1px 8px;
  margin-bottom: 6px;
}

.TraceIntentReasonNote {
  margin-top: 6px;
}

/* Charged AI-attempt ledger table: compact per-attempt list inside the
   cost tab. Invalid/failed rows get a subtle danger tint so they stand out from successful ones. */
.TraceAttemptTable {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.TraceAttemptTable thead th {
  text-align: start;
  font-weight: 600;
  color: var(--textMuted);
  padding: 7px 8px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.TraceAttemptTable tbody td {
  padding: 7px 8px;
  border-bottom: 1px solid var(--border);
  color: var(--textPrimary);
  vertical-align: middle;
}

.TraceAttemptTable tbody tr:last-child td {
  border-bottom: none;
}

.TraceAttemptRowBad {
  background: var(--dangerBackground, var(--dangerTintBackground));
}

/* A paid request from an earlier, superseded run of the same turn. Muted rather
   than hidden: it was billed and must stay auditable, but it did not produce
   this turn's answer. Kept below .TraceAttemptRowBad so a failed superseded
   attempt still reads as failed. */
.TraceAttemptRowSuperseded td {
  opacity: 0.72;
}

/* Chip icon vertical alignment: icons inside tag-styled chips were sitting on
   the text baseline; flex-center them with the label so they line up in both
   LTR and RTL. */
.Tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1;
}

.Tag .Icon {
  flex: 0 0 auto;
}

/* Retrieval-card action row: a quiet strip of small ghost buttons. A card is an
   audit record, so its links stay visually subordinate to the content and the
   card itself is never a click target. */
.TraceCardActions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

/* A filled neutral control rather than an outlined one: the fill carries the
   affordance, so the ghost button's border and background are overridden. The
   focus ring is deliberately untouched -- removing the border must not remove
   the keyboard indicator. */
.TraceCardAction {
  text-decoration: none;
  background: var(--backgroundNeutralControl);
  border: none;
}

.TraceCardAction:hover {
  background: var(--backgroundHover);
}

.TraceCardAction .Icon {
  flex: 0 0 auto;
}

/* Long-technical-value ellipsis: model ids, request ids, content ids and any LTR
   technical token are clipped to a single line with the full value in the title. Applied across the
   trace modal — kv grids, the AI-call ledger table, user-state section, cost tables, hydrated rows. */
.TraceMonospaceEllipsis,
.TraceModelCell,
.TraceRequestIDCell {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

.TraceMonospaceEllipsis,
.TraceModelCell,
.TraceRequestIDCell {
  direction: ltr;
  text-align: start;
  font-family: var(--monoFont);
  font-size: 12px;
}

/* Inside a narrow kv value cell, cap the ellipsis width so a long id can never widen the grid. */
.TraceKeyValue .Value .TraceMonospaceEllipsis,
.TraceKeyValue .Value .TraceModelCell,
.TraceKeyValue .Value .TraceRequestIDCell {
  max-width: 100%;
}

/* Inside tables, cap the model column so the row stays on one line. */
.TraceAttemptTable .TraceModelColumn,
.TraceAttemptTable .TraceModelCell {
  max-width: 150px;
}

.DataTable .TraceMonospaceEllipsis,
.DataTable .TraceModelCell,
.DataTable .TraceRequestIDCell {
  max-width: 150px;
}

/* Dense trace values rendered as stacked label/value lines instead of one packed sentence with
   dash/list separators: no ugly mid-word wrapping in any language, compact, model ids ellipsized. */
.TraceValueLines {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.TraceValueLine {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
  line-height: 1.7;
  overflow-wrap: normal;
  word-break: keep-all;
}

.TraceValueLabel {
  color: var(--textMuted);
  font-size: 12px;
  flex: 0 0 auto;
}

.TraceValueText {
  color: var(--textPrimary);
  font-size: 12.5px;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Sub-heading for a list/table nested inside a trace section (e.g. the multi-turn intent/resolution table inside the history-summarization box —). */
.TraceSubHead {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--textSecondary);
  margin: 12px 0 6px;
}

.TraceIntentTable {
  text-transform: none;
  font-size: 12px;
}

.TraceIntentTable td {
  vertical-align: top;
  font-weight: 300;
}

/* Intent / resolution / summary section: stacked, start-aligned blocks — label above
   Text, no inline crowding; text wraps by word (never broken mid-word). */
.TraceIntentResolutionBlock {
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: start;
}

.TraceIntentResolutionItem {
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: stretch;
}

.TraceIntentResolutionLabel {
  font-size: 12px;
  font-weight: 600;
  color: var(--textMuted);
  text-align: start;
}

.TraceIntentResolutionText {
  font-size: 13px;
  color: var(--textPrimary);
  line-height: 1.85;
  text-align: start;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: normal;
}

/* Category-form AI helper actions kept inline (button + word counter) in the label row. */
.AILabelRowActions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Language-detection signals: one row per signal with a localized label + raw enum token. */
.LanguageSignalList {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.LanguageSignalRow {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.LanguageSignalLabel {
  font-size: 12px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

.LanguageSignalRaw {
  font-size: 10px;
  color: var(--textMuted);
  font-family: var(--monoFont);
}

/* Matched Finglish tokens shown as LTR monospace chips in the trace language section. */
.LanguageChipRow {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.LanguageTokenChip {
  font-size: 11px;
  font-family: var(--monoFont);
  color: var(--textPrimary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1px 6px;
  direction: ltr;
  unicode-bidi: isolate;
}

/* Long technical IDs in the trace modal: ellipsize, keep LTR, full value in title tooltip.
   Still selectable/copyable; hovering shows the full id. */
.TraceID {
  display: inline-block;
  max-width: min(200px, 60vw);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
  direction: ltr;
  font-family: var(--monoFont);
  font-size: 11.5px;
}

/* Unified Trace Modal: Tab Navigation */
.TraceModalTabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: -18px;
  background: var(--backgroundSurface);
  z-index: 1;
}

.TraceModalTab {
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--textMuted);
  padding: 8px 12px;
  cursor: pointer;
  font-size: 12.5px;
  font-family: inherit;
  white-space: nowrap;
}

.TraceModalTab:hover {
  color: var(--textPrimary);
}

.TraceModalTab.IsActive {
  color: var(--textPrimary);
  border-bottom-color: var(--textPrimary);
}

/* Container for every trace tab panel. Establishes the panes' own block context
   so a wide table inside a pane scrolls within its own wrapper instead of
   widening the dialog. */
.TraceModalPanes {
  display: block;
  min-width: 0;
}

.TraceModalPane.IsHidden {
  display: none;
}

.TraceModalPane .JSONBlock {
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  max-height: 440px;
  overflow: auto;
  font-size: 11.5px;
  margin: 0;
  background: var(--backgroundDeep);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
}

/* --- 15. Conversation Lab UI ------------------------------------------------ */

/* Conversation Lab*/
.LabBody {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 14px;
  align-items: start;
}

.LabSessions {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  overflow: hidden;
}

.LabSessionsHead {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.LabSessionList {
  max-height: 60vh;
  overflow-y: auto;
}

/* Each session is a row: A flex link (clickable to open) + a separate delete form, so the
   delete control never triggers the row's navigation. */
.LabSessionRow {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--border);
}

.LabSessionRow:hover {
  background: var(--backgroundHover);
}

.LabSessionRow.IsActive {
  background: var(--backgroundRaised);
}

.LabSessionItem {
  display: block;
  padding: 10px 14px;
  color: var(--textSecondary);
  font-size: 12.5px;
}

/* The link inside a row flexes to fill; the standalone empty-state placeholder keeps a border. */
.LabSessionRow .LabSessionItem {
  flex: 1 1 auto;
  min-width: 0;
}

.LabSessionList>.LabSessionItem {
  border-bottom: 1px solid var(--border);
}

.LabSessionItem:hover {
  color: var(--textPrimary);
}

.LabSessionRow:hover .LabSessionItem,
.LabSessionRow.IsActive .LabSessionItem {
  color: var(--textPrimary);
}

.LabSessionMeta {
  font-size: 11px;
  color: var(--textMuted);
  margin-top: 2px;
}

/* Small per-row delete button: dimmed until row hover/focus, but always reachable on touch. */
.LabSessionDelete {
  display: flex;
  align-items: center;
  padding-inline-end: 8px;
}

.LabSessionDeleteButton {
  opacity: 0.5;
  color: var(--danger);
}

.LabSessionRow:hover .LabSessionDeleteButton,
.LabSessionDeleteButton:focus {
  opacity: 1;
}

/* Pinned "active conversation not on this page" indicator. */
.LabSessionPin {
  font-size: 10px;
  color: var(--textMuted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 5px;
  margin-inline-start: 4px;
}

/* Lab session list pagination controls. */
.LabSessionPager {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}

.LabSessionPagerNavigation {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.LabSessionPagerInfo {
  font-size: 11.5px;
  color: var(--textMuted);
}

.LabSessionPagerSize {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.LabSessionSizeLink {
  font-size: 11.5px;
  color: var(--textMuted);
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.LabSessionSizeLink:hover {
  color: var(--textPrimary);
  background: var(--backgroundHover);
}

.LabSessionSizeLink.IsActive {
  color: var(--textPrimary);
  border-color: var(--borderStrong);
}

.Button.IsDisabled {
  opacity: 0.4;
  pointer-events: none;
}

.LabChat {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  display: flex;
  flex-direction: column;
  /* Resilient height: fill most of the viewport but never collapse.
     `min-height` is the floor so the panel grows (and the page scrolls) when the bars above the
     timeline are tall, instead of squeezing .LabChatScroll to near-zero on short screens. */
  min-height: calc(100vh - 170px);
  max-height: calc(100vh + 300px);
  overflow: hidden;
}

.LabModelBar {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--backgroundSurface);
  background: var(--backgroundRaised);
}

.LabModelBar .FormField {
  margin-bottom: 0;
}

/* Per-Conversation reasoning / thinking override bar. */
.LabReasoningBar {
  padding: 10px 14px;
  background: var(--overlaySurface);
  font-size: 12.5px;
}

.LabReasoningBar .FormField {
  margin-bottom: 0;
}

.LabReasoningBar .CheckRow {
  margin: 0;
}

.LabReasoningBar #LabReasoningControls {
  align-items: flex-end;
  margin-top: 8px;
  line-height: 38px;
}

.LabReasoningBar #LabReasoningControls .FormField {
  flex-direction: row;
}

.LabReasoningBar #LabReasoningControls input:disabled+span {
  opacity: 0.5;
}

.LabReasoningBar #LabReasoningControls #LabReasoningNote {
  margin-top: -10px;
}

.LabChatScroll {
  flex: 1 1 auto;
  /* A floor so the timeline stays clearly visible/usable even when the model + reasoning bars
     and user-state card above it are tall. */
  min-height: 450px;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.LabComposer {
  /* Full-width send button BELOW the input — clean and aligned on desktop and
     mobile, never detached from the message box. */
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: stretch;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: var(--backgroundRaised);
}

.LabComposer textarea {
  width: 100%;
  min-height: 48px;
  max-height: 200px;
  resize: vertical;
}

.LabComposer .Button {
  width: 100%;
  justify-content: center;
}

.LabClosedNote {
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: var(--backgroundRaised);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  color: var(--textMuted);
  font-size: 13px;
}

.LabEmpty {
  margin: auto;
  text-align: center;
  color: var(--textMuted);
  padding: 30px;
}

.Thinking {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--textMuted);
  font-size: 12.5px;
}

.ThinkingDots {
  display: inline-flex;
  gap: 3px;
}

.ThinkingDots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--textMuted);
  animation: thinkingPulse 1s infinite ease-in-out;
}

.ThinkingDots i:nth-child(2) {
  animation-delay: 0.15s;
}

.ThinkingDots i:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes thinkingPulse {

  0%,
  80%,
  100% {
    opacity: 0.25;
  }

  40% {
    opacity: 1;
  }
}

.ChatMessageActions {
  margin-top: 6px;
  display: flex;
  gap: 8px;
  align-items: center;
}

/* Lab Message Processing / Failed-retry State */
.MessageProcessing {
  margin-top: 6px;
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 12px;
}

.MessageProcessing.IsFailed {
  color: var(--danger);
}

/* Recovery-Worker continuation state (clarification E): neutral/muted, NOT a failure colour. */
.MessageProcessing.IsRecovering {
  color: var(--textMuted);
}

/* --- 16. Feedback UI -------------------------------------------------------- */

/* Feedback Feature*/

/* A single feedback action form on the feedback detail page. */
.ActionPanel {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundRaised);
  padding: 12px;
  margin-bottom: 10px;
}

.ActionPanel:last-of-type {
  margin-bottom: 0;
}

/* --- 17. ChatWoot Integration UI -------------------------------------------- */

/* ChatWoot Webhook URL Field: Force LTR, Never Break Layout */
#ChatwootWebhookUrl {
  direction: ltr;
  unicode-bidi: plaintext;
  text-align: start;
  overflow-wrap: anywhere;
  word-break: break-all;
  min-width: 0;
  flex: 1 1 auto;
}

/* --- 18. Reports, Dashboard and Charts -------------------------------------- */

/* Charts (reports + dashboard, plain SVG) */
.ChartGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 14px;
}

.ChartCard {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 14px 16px;
}

.ChartTitle {
  font-size: 13px;
  font-weight: 700;
  color: var(--textSecondary);
  margin-bottom: 10px;
}

.ChartBox {
  width: 100%;
  overflow-x: auto;
}

.ChartSVG {
  width: 100%;
  height: auto;
  display: block;
}

.ChartEmpty {
  color: var(--textMuted);
  font-size: 12.5px;
  padding: 26px 8px;
  text-align: center;
}

.ChartLabelText {
  fill: var(--textMuted);
  font-size: var(--chartAxisFontSize);
  font-family: var(--fontStack);
}

.DonutWrap {
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
}

.DonutSVG {
  width: 160px;
  height: 160px;
  flex: 0 0 160px;
}

.DonutTotal {
  fill: var(--textPrimary);
  font-size: 15px;
  font-weight: 700;
  font-family: var(--fontStack);
}

.ChartLegend {
  display: flex;
  flex-direction: column;
  gap: 5px;
  flex: 1 1 150px;
  min-width: 150px;
}

.LegendItem {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
}

.LegendDot {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex: 0 0 10px;
}

.LegendLabel {
  color: var(--textSecondary);
  flex: 1 1 auto;
}

.LegendValue {
  color: var(--textPrimary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Rich axis-chart primitives: gridlines, axis tick labels, baseline, the
   positioned hover tooltip, and the screen-reader data table. */
.ChartPlot {
  position: relative;
  width: 100%;
}

.ChartGridLine {
  stroke: var(--border);
  stroke-width: 1;
  stroke-dasharray: 2 3;
  opacity: 0.6;
}

.ChartAxisLine {
  stroke: var(--border);
  stroke-width: 1;
}

.ChartAxisText {
  fill: var(--textMuted);
  font-size: var(--chartAxisFontSize);
  font-family: var(--fontStack);
  font-variant-numeric: tabular-nums;
}

.ChartInteractive {
  cursor: pointer;
  transition: opacity 0.12s ease;
}

.ChartInteractive:hover,
.ChartInteractive:focus {
  opacity: 0.82;
  outline: none;
}

.ChartInteractive:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.ChartTooltip {
  position: absolute;
  transform: translate(-50%, -100%);
  pointer-events: none;
  z-index: 5;
  max-width: 220px;
  padding: 4px 8px;
  border-radius: 6px;
  background: var(--overlaySurface);
  border: 1px solid var(--border);
  color: var(--textPrimary);
  font-size: 12px;
  white-space: nowrap;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.28);
}

.DonutEmptyRing {
  stroke: var(--border);
}

/* The emphasized zero baseline on a signed axis. */
.ChartZeroLine {
  stroke: var(--textSecondary);
  stroke-width: 1.25;
}

/* Small optional axis titles rendered inside the SVG. */
.ChartAxisTitle {
  fill: var(--textMuted);
  font-size: 10px;
  font-weight: 600;
  font-family: var(--fontStack);
}

/* Valid all-zero data: rendered as a real zero chart plus this note — never
   confused with the "no data" empty state. */
.ChartAllZeroNote {
  color: var(--textMuted);
  font-size: 11.5px;
  margin-bottom: 6px;
}

/* Visible, expandable per-chart data table ("View data table"). */
.ChartDataDetails {
  margin-top: 8px;
}

.ChartDataDetails > summary {
  cursor: pointer;
  color: var(--accent, var(--textSecondary));
  font-size: 12px;
}

.ChartDataTable {
  width: 100%;
  margin-top: 8px;
  border-collapse: collapse;
  font-size: 12px;
}

.ChartDataTable caption {
  text-align: start;
  color: var(--textMuted);
  font-size: 11.5px;
  padding-bottom: 6px;
}

.ChartDataTable th,
.ChartDataTable td {
  border: 1px solid var(--border);
  padding: 4px 8px;
  text-align: start;
}

.ChartDataTable td {
  font-variant-numeric: tabular-nums;
}

/* Legend labels keep their FULL text (ellipsis only when space runs out; the
   complete name lives in the title attribute and the bound tooltip). */
.LegendLabel {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Visually hidden but present for assistive technology. */
.VisuallyHidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Dashboard Sections*/
.DashboardSection {
  margin-top: 18px;
}

/* Domain snapshots: two calm at-a-glance panels (Quality + operations). */
.SnapshotGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
}

.SnapshotHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.SnapshotItems {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.SnapshotItem {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  /* Flex items default to min-width:Auto, which refuses to shrink below their
     content and pushes long values off the page instead of wrapping them. */
  min-width: 0;
}

.SnapshotItemLabel {
  color: var(--textSecondary);
  font-size: 12.5px;
  min-width: 0;
}

.SnapshotItemValue {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  /* Values are usually short numbers, which never wrap anyway — but some are
     full mode labels ("Handoff only (the AI provider is unavailable)"). With
     nowrap those ran past the container AND past the viewport edge at 1024px
     and narrower, where the page does not scroll horizontally, so the end of
     the sentence was simply unreadable. Wrapping is the honest behaviour. */
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: end;
  min-width: 0;
}

/* Modality/capability chips carry an inline SVG icon beside the label. */
.ModelModalityChip,
.ModelParameterChip,
.ModelEffortChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.ModelModalityChip .Icon {
  flex: 0 0 auto;
}

/* Catalog filter bar: wrapping labeled controls; never wider than the page. */
.ModelFilterBar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 10px;
  margin-bottom: 12px;
}

.ModelFilterField {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 130px;
  flex: 0 1 auto;
}

.ModelFilterField .SelectField {
  font-size: 12.5px;
  padding-block: 6px;
}

.ModelResultCount {
  color: var(--textMuted);
  font-size: 12px;
  white-space: nowrap;
  height: 32px;
  line-height: 32px;
}

/* Dashboard quick-actions: A wrapping row of ghost buttons.*/
.ShortcutRow {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.DashboardTwoColumn {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

/* Integrations overview only: the provider cards render
   one below the other at the full content width. Page-specific by design —
   .DashboardTwoColumn keeps its two-column behavior for its other legitimate uses. */
.IntegrationOverviewStack {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.IntegrationOverviewStack > .DashboardCard {
  inline-size: 100%;
}

.DashboardCard {
  background: var(--backgroundSurface);
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  padding: 14px 16px;
}

.RecentRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}

.RecentRow:last-child {
  border-bottom: none;
}

.RecentMain {
  color: var(--textSecondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

@media (max-width: 900px) {
  .DashboardTwoColumn {
    grid-template-columns: 1fr;
  }
}

/* --- 19. Utility Classes ---------------------------------------------------- */

/* Utilities */
.Stack8 {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.Row {
  display: flex;
  gap: 10px;
  align-items: center;
}

.RowWrap {
  display: flex;
  gap: 2px;
  align-items: center;
  flex-wrap: wrap;
}

.Spacer {
  flex: 1 1 auto;
}

.TextMuted {
  color: var(--textMuted);
}

.TextSmall {
  font-size: 12px;
}

.MarginBottomNone {
  margin-bottom: 0;
}

.MarginTop16 {
  margin-top: 16px;
}

.Hidden {
  display: none !important;
}

/* Non-important hidden state for elements toggled by JS via style.display (so an
   inline display set by script still overrides this initial-hidden class). */
.IsHidden {
  display: none;
}

/* Spacing / layout / Text utilities — extracted from template inline styles.
   UpperCamelCase + numeric; reuse one of these before adding a new utility. */
.MarginNone {
  margin: 0;
}

.MarginTop8 {
  margin-top: 8px;
}

.MarginTop10 {
  margin-top: 10px;
}

.MarginTop12 {
  margin-top: 12px;
}

.MarginTop20 {
  margin-top: 20px;
}

.MarginBottom6 {
  margin-bottom: 6px;
}

.MarginBottom8 {
  margin-bottom: 8px;
}

.MarginBottom10 {
  margin-bottom: 10px;
}

.MarginBottom12 {
  margin-bottom: 12px;
}

.MarginBottom14 {
  margin-bottom: 14px;
}

.MarginBottom16 {
  margin-bottom: 16px;
}

.MarginTop4 {
  margin-top: 4px;
}

.MarginBottom4 {
  margin-bottom: 4px;
}

/* Gap utilities override a flex container's default gap (e.g. .RowWrap's 2px); defined after the
   layout containers so a single-class .gapN wins by source order. Extracted from JS inline styles. */
.Gap6 {
  gap: 6px;
}

.Gap8 {
  gap: 8px;
}

.MarginInlineStartAuto {
  margin-inline-start: auto;
}

.MarginInlineStart6 {
  margin-inline-start: 6px;
}

.Gap8 {
  gap: 8px;
}

.Gap6 {
  gap: 6px;
}

.Padded24 {
  padding: 24px;
}

.Flex1 {
  flex: 1;
}

.FullBasis {
  flex-basis: 100%;
}

.InlineBlock {
  display: inline-block;
}

.InlineForm {
  display: inline;
}

.FlexBetween {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Direction-safe alignment. .TextRight aligns a value to the PAGE's
   start side even when the element itself is dir="ltr" (ids, costs, token counts):
   match-parent resolves start against the parent's direction. .TextLeft Start-aligns
   technical content relative to the element's own dir="ltr". */
.TextRight {
  text-align: match-parent;
}

.TextLeft {
  text-align: start;
}

.TextWarn {
  color: var(--warn);
}

.FontBold {
  font-weight: 700;
}

.CursorPointer {
  cursor: pointer;
}

.CursorDefault {
  cursor: default;
}

.ScrollBox300 {
  max-height: 300px;
  overflow: auto;
}

.FlushTop {
  margin-top: 0;
  border-top: none;
  padding-top: 0;
}

.BorderDanger {
  border-color: var(--danger);
}

.MaxWidth120 {
  max-width: 120px;
}

.MinWidth260 {
  min-width: 260px;
}

.ControlHeight38 {
  height: 38px;
}

.SpacedTitle {
  margin: 12px 0 6px;
}

/* Semantic one-offs extracted from inline styles. */
.AuthenticationCard {
  max-width: 560px;
  margin: 6vh auto;
  text-align: center;
}

.ReportTableTitle {
  padding: 12px 14px 0;
  border: none;
}

.ReportTableDescription {
  padding: 0 14px 12px;
}

.FormFootRow {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* Date/time value (Bidi-safe) */
/* Numeric date/time strings (e.g. "۲۰۲۶-۰۶-۱۷ ۰۰:۵۸:۰۴") get visually
   reordered by the bidi algorithm inside an RTL page. Forcing LTR with
   plaintext bidi keeps them in correct visual order while aligning with the
   surrounding table/cell content in either page direction. Emitted
   automatically by the dateTime/dateOnly Jinja filters, so it applies
   everywhere a date is rendered. */
.DateTimeValue {
  direction: ltr;
  unicode-bidi: plaintext;
  text-align: match-parent;
  display: inline-block;
  font-weight: 200;
  font-variant-numeric: normal;
  white-space: nowrap;
}

/* Copy row (URL + copy Button) */
.CopyRow {
  display: flex;
  align-items: center;
  gap: 8px;
}

.CopyRow .CopyTarget {
  overflow-x: auto;
  white-space: nowrap;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundRaised);
}

/* --- 20. Responsive Rules --------------------------------------------------- */

/* Responsive */
@media (max-width: 900px) {

  /* Mobile drawer: anchored to the inline-start edge (the sidebar side of
     the always-RTL Application root — physical right), slides in from that
     edge. translateX has no logical equivalent; the off-screen offset below
     is the RTL one. */
  .Sidebar {
    position: fixed;
    top: 0;
    inset-inline-start: 0;
    inset-inline-end: auto;
    width: var(--sidebarWidth);
    max-width: 86vw;
    height: 100vh;
    height: 100dvh;
    z-index: 1100;
    transform: translateX(100%);
    /* A closed drawer is not merely off-screen, it is CLOSED. Without
       visibility:Hidden its nineteen navigation links stay in the tab order
       and in the accessibility tree, so keyboard and screen-reader users walk
       through a menu they cannot see and did not open. The zero-duration
       visibility transition is delayed by the slide duration so the drawer
       stays visible while it animates out. */
    visibility: hidden;
    transition: transform 0.22s ease, visibility 0s linear 0.22s;
    box-shadow: var(--shadow);
    border-inline-end: 1px solid var(--border);
  }

  .Sidebar.IsOpen {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.22s ease, visibility 0s;
  }

  .MenuToggle {
    display: inline-flex;
  }

  .FormGrid {
    grid-template-columns: 1fr;
  }

  .ChatMessage {
    max-width: 92%;
  }

  .SidebarOverlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--backdropSoft);
    z-index: 1090;
  }

  .SidebarOverlay.IsOpen {
    display: block;
  }

  /* ConversationLab on narrow screens: stack the session list ABOVE the chat
     instead of hiding it, so session switching + pagination stay usable. Both
     panels go full width (single grid column), the list is capped so the chat
     stays reachable, and the chat grows with content (the page scrolls) so the
     composer/buttons remain usable with no horizontal overflow. */
  .LabBody {
    grid-template-columns: 1fr;
  }

  .LabSessions {
    width: 100%;
  }

  .LabSessionList {
    max-height: 40vh;
  }

  /* Let the chat grow with content (page scrolls) on narrow screens — no viewport cap here. */
  .LabChat {
    height: auto;
    min-height: 60vh;
    max-height: none;
  }
}

/* Full-width chart card (Layout: FULL_WIDTH) — the dashboard trend owns its
   whole row instead of one auto-fill column. */
.ChartCardFull {
  grid-column: 1 / -1;
}

/* Intentional column counts for the semantic chart layouts. Large desktop: three columns — a WIDE card spans two of them,
   FULL_WIDTH spans all, a default/compact card spans one. Minmax(0, 1fr)
   keeps long legends/tables from forcing horizontal overflow. */
@media (min-width: 1200px) {
  .ChartGrid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .ChartCardWide {
    grid-column: span 2;
  }
}

/* Medium screens: two columns; A WIDE chart takes its own full row. */
@media (min-width: 761px) and (max-width: 1199.98px) {
  .ChartGrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ChartCardWide {
    grid-column: 1 / -1;
  }
}

/* Mobile: every chart is full width. */
@media (max-width: 760px) {
  .ChartGrid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Healthy needs-attention state: ONE slim status line, no reserved height. */
.HealthyStrip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radiusLarge);
  color: var(--textSecondary);
  font-size: 12.5px;
  background: var(--backgroundSurface);
}

.HealthyStrip .Icon {
  color: var(--accent, #4ade80);
}

/* Typed value STATES: A localized state label replaces a missing value —
   Python none can never be stringified into the page. */
.ValueState {
  font-size: 13px;
  font-weight: 600;
  color: var(--textMuted);
  cursor: help;
}

.ValueStateERROR {
  color: var(--danger, #f4615f);
}

.ValueStateLOADING {
  font-style: italic;
}

/* Table date/time column: A stable practical minimum width so the timestamp
   never compresses into the action column; the action column stays compact
   and shrink-to-fit. */
.DataTable td.CellDate,
.DataTable .CellDate {
  min-width: 158px;
}

.DataTable .CellActions {
  width: 1%;
  white-space: nowrap;
}

/* Structured per-report help: A collapsed-by-default guide with eight clear
   sections — never one giant paragraph. */
.ReportHelpDetails {
  min-width: 0;
}

.ReportHelpSummary {
  cursor: pointer;
  list-style-position: inside;
}

.ReportHelpMore {
  color: var(--accentText, #7aa2ff);
  font-size: 12px;
  white-space: nowrap;
}

.ReportHelpSections {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 10px 18px;
  margin-top: 12px;
}

.ReportHelpSection {
  min-width: 0;
}

.ReportHelpSectionTitle {
  font-size: 12px;
  font-weight: 700;
  margin: 0 0 3px;
  color: var(--textPrimary);
}

.ReportHelpSectionBody {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--textSecondary);
}

.ReportHelpSectionBody + .ReportHelpSectionBody {
  margin-top: 6px;
}

/* Structured guide content: item lists, ordered steps, notes and warnings.
   RTL-first — the marker sits on the inline start, so the same rule is correct
   in an LTR sub-tree without an override. */
.ReportHelpItems,
.ReportHelpSteps {
  margin: 6px 0 0;
  padding-inline-start: 18px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--textSecondary);
}

.ReportHelpItems {
  list-style: disc;
}

.ReportHelpSteps {
  list-style: decimal;
}

.ReportHelpItem {
  margin: 0 0 2px;
  overflow-wrap: anywhere;
}

/* Notes and warnings carry a border AND a distinct marker, so the distinction
   survives without colour. */
.ReportHelpNotes,
.ReportHelpWarnings {
  list-style: none;
  padding-inline-start: 0;
  margin-top: 8px;
}

.ReportHelpNotes > .ReportHelpItem,
.ReportHelpWarnings > .ReportHelpItem {
  border-inline-start: 2px solid var(--border);
  padding: 2px 0 2px 0;
  padding-inline-start: 8px;
  margin-bottom: 4px;
}

.ReportHelpNotes > .ReportHelpItem::before {
  content: "•";
  margin-inline-end: 6px;
  color: var(--textMuted);
}

.ReportHelpWarnings > .ReportHelpItem {
  border-inline-start-color: var(--textPrimary);
}

.ReportHelpWarnings > .ReportHelpItem::before {
  content: "!";
  font-weight: 700;
  margin-inline-end: 6px;
  color: var(--textPrimary);
}

.ReportHelpExample {
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--textMuted);
  border-inline-start: 2px dashed var(--border);
  padding-inline-start: 8px;
  overflow-wrap: anywhere;
}

/* Knowledge inspection: findings list, side-by-side comparison, signals.*/
.InspectionFinding {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 8px;
  padding: 0;
}

.InspectionFindingSummary {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  cursor: pointer;
  padding: 10px 12px;
  list-style-position: inside;
}

.InspectionFindingType {
  font-weight: 700;
  font-size: 12.5px;
}

.InspectionFindingTitles {
  flex: 1 1 240px;
  min-width: 0;
  font-size: 12.5px;
  color: var(--textSecondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.InspectionFindingBody {
  padding: 0 12px 12px;
  border-top: 1px solid var(--border);
}

.InspectionCompare {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
  margin: 10px 0;
}

.InspectionStatusRow {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.InspectionStatusRow .InputField {
  flex: 1 1 220px;
}

/* Chart height guard: the renderer designs vertical charts to a BOUNDED
   height (<= 360px incl. gutters). Horizontal bars are the
   documented exception (they grow per category) and keep this larger
   belt-and-braces bound. */
.ChartSVG {
  max-height: 420px;
}

/* Compact chart card (e.g. the inspection severity donut). */
.ChartCardCompact {
  max-width: 420px;
}

/* Caption separation: captions sit BELOW the complete SVG/legend/table
   stack with clear breathing room and readable contrast. */
.ChartCaption {
  margin-top: 14px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  line-height: 1.7;
  color: var(--textSecondary);
}

/* The report-help expander control must be readable on the dark theme in
   every state — never the default visited/active black. */
.ReportHelpMore,
.ReportHelpSummary,
.ReportHelpDetails summary {
  color: var(--textPrimary);
}

.ReportHelpDetails summary:hover .ReportHelpMore,
.ReportHelpDetails summary:focus-visible .ReportHelpMore {
  text-decoration: underline;
}

.ReportHelpMore {
  color: #9db8ff;
}

.ReportHelpMore:visited,
.ReportHelpMore:active {
  color: #9db8ff;
}

/* Knowledge inspection additions: Active-run row, signal cards,
   risk pill, AI report blocks, pager, tag groups, lazy detail. */
.ActiveRunRow {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.ActiveRunIcon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
}

.ActiveRunIcon svg {
  animation: ActiveRunSpin 1.4s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .ActiveRunIcon svg {
    animation: none;
  }
}

@keyframes ActiveRunSpin {
  to { transform: rotate(360deg); }
}

.ActiveRunText {
  flex: 1 1 240px;
  min-width: 0;
}

.ActiveRunAction {
  flex: 0 0 auto;
}

.InspectionRiskPill {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12px;
  white-space: nowrap;
}

.InspectionConfidence {
  font-size: 12px;
  color: var(--textSecondary);
  white-space: nowrap;
}

.InspectionSignalGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 8px;
  margin: 10px 0;
}

.InspectionSignalCard {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.InspectionSignalCard.IsRisky {
  border-color: rgba(255, 122, 122, 0.55);
}

.InspectionSignalLabel {
  font-size: 11.5px;
  color: var(--textSecondary);
}

.InspectionSignalValue {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.InspectionSignalBar {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}

.InspectionSignalBarFill {
  display: block;
  height: 100%;
  background: var(--accent, #7aa2ff);
}

.InspectionTagGroup {
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
  margin-top: 6px;
}

.InspectionTagGroupTitle {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--textSecondary);
  white-space: nowrap;
}

/* (TagList layout comes from the base .TagList component.) */

/* The findings anchor: verdict chips, filters and the
   pager all land here; Scroll-margin keeps the heading clear of the sticky
   header stack, and the focus outline stays invisible for the programmatic
   announce-focus (keyboard users still get :Focus-visible elsewhere). */
#InspectionFindings {
  scroll-margin-top: 96px;
  outline: none;
}

.InspectionPager {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.InspectionPager [aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}

.InspectionDetailBody {
  margin-top: 8px;
}

.InspectionDetailSide {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.InspectionDetailSideHead {
  font-weight: 700;
  font-size: 12.5px;
}

.InspectionDetailTitle {
  font-weight: 700;
}

.InspectionDetailHeading {
  font-weight: 700;
  font-size: 12.5px;
  margin-top: 4px;
}

.InspectionDetailText,
.InspectionDetailMeta {
  font-size: 12.5px;
  line-height: 1.8;
  overflow-wrap: anywhere;
}

.InspectionDetailLabel {
  font-weight: 700;
  color: var(--textSecondary);
  margin-inline-end: 6px;
}

/* One-line technical values (model ids): never wrap to two lines; Ellipsis
   only when the container is truly too narrow — full value in the title. */
.OneLineValue {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  display: inline-block;
  vertical-align: bottom;
}

/* Risk formula v2 contribution breakdown (finding cards). */
.InspectionRiskBreakdown {
  margin-block: 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  background: transparent;
}
.InspectionRiskBreakdownSummary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.85rem;
}
.InspectionRiskRows {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 4px 16px;
  margin-top: 8px;
}
.InspectionRiskRow {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.82rem;
}
.InspectionRiskRow.IsFinal {
  font-weight: 700;
  border-top: 1px solid var(--border);
  padding-top: 4px;
}
.InspectionRiskValue.IsRaise { color: var(--danger); }
.InspectionRiskValue.IsLower { color: var(--ok); }

/* Comparison sides: fixed 8-slot semantic rows. Subgrid (where supported)
   aligns head/title/category/source/tag/action rows pixel-perfectly across
   the two cards; the flex fallback still yields equal-height cards with the
   action button pinned to the bottom. */
.InspectionCompare {
  align-items: stretch;
}
.InspectionDetailSide {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.InspectionDetailAction {
  margin-top: auto;
  padding-top: 6px;
}
.InspectionDetailAlert:empty,
.InspectionDetailTitleSlot:empty,
.InspectionDetailBody:empty {
  min-height: 0;
}
@supports (grid-template-rows: subgrid) {
  .InspectionCompare > .InspectionDetailSide {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 8;
    align-content: start;
  }
}

/* Finding-body lead help text must not stick to the summary border. */
.InspectionFindingBody > .FieldHelp:first-child {
  margin-top: 12px;
}

/* Tag chips inside comparison meta rows keep a visible gap. */
/* AI adjudication verdict card + quick apply. */
.InspectionAIVerdict {
  margin-block: 8px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--warn, #d97706);
  border-radius: 8px;
  padding: 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.InspectionAIVerdict.IsCONFIRMED { border-inline-start-color: var(--danger); }
.InspectionAIVerdict.IsREJECTED_FALSE_POSITIVE { border-inline-start-color: var(--ok); }
.InspectionAIVerdictHead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.InspectionApplyRow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  border-top: 1px dashed var(--border);
  padding-top: 6px;
}
.InspectionApplyActions { display: flex; gap: 6px; align-items: center; }
.InspectionMemberList { display: flex; flex-direction: column; gap: 4px; margin-block: 8px; }
.InspectionMemberRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 0.85rem;
}
.InspectionMemberText { flex: 1 1 240px; min-width: 0; }

/* AI-verdict summary chips + review-disposition card states.
   The FINAL disposition owns the card's visual weight; the deterministic
   risk pill stays readable as labeled audit evidence. Selection is never
   color-only (active chip: bold + filled background + aria-current). */
.VerdictChipRow {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-block-end: 12px;
}

.VerdictChip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 4px 12px 4px 4px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12.5px;
  color: var(--textSecondary);
  text-decoration: none;
}

.VerdictChip:hover {
  border-color: var(--textMuted);
  color: var(--textPrimary);
}

.VerdictChip.IsActive {
  border-color: var(--accent);
  background: var(--okBackground);
  color: var(--textPrimary);
  font-weight: 700;
}

.VerdictChipCount {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 8px;
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
}

.InspectionFinding.IsCONFIRMED {
  border-inline-start: 3px solid var(--danger);
}

.InspectionFinding.IsNEEDS_HUMAN_REVIEW {
  border-inline-start: 3px solid var(--warn, #d97706);
}

/* An AI-rejected false positive is NOT an actionable problem: mute the whole
   card and strip the danger/warn prominence from its severity badge — the
   severity survives as de-emphasized audit context only. */
.InspectionFinding.IsREJECTED_FALSE_POSITIVE {
  opacity: 0.62;
}

.InspectionFinding.IsREJECTED_FALSE_POSITIVE[open],
.InspectionFinding.IsREJECTED_FALSE_POSITIVE:focus-within {
  opacity: 0.88;
}

.InspectionFinding.IsREJECTED_FALSE_POSITIVE .InspectionSeverityBadge {
  color: var(--textMuted);
  background: transparent;
  border-color: var(--border);
}

.InspectionRiskPill.IsAuditEvidence {
  font-weight: 400;
  color: var(--textMuted);
  border-style: dashed;
}

/* Human-readable RetrievalForm / model presentation. */
.ModelDisplay {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  text-align: end;
  float: inline-end;
}

/* A model name is a Latin technical value: it renders left-to-right and
   truncates from the correct side even inside the RTL panel. */
.ModelDisplayName {
  font-size: 12.5px;
  font-weight: 600;
  text-transform: capitalize;
  direction: ltr;
  text-align: start;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.ModelDisplayRaw {
  font-size: 11px;
}

.InspectionMemberForm {
  font-size: 11.5px;
  color: var(--textMuted);
  white-space: nowrap;
}

.InspectionMemberContentLink {
  text-decoration: none;
}

.InspectionMemberContentLink:hover {
  text-decoration: underline;
}

.InspectionMemberTechnical {
  margin-inline-start: 24px;
  margin-block: 2px 8px;
  font-size: 12px;
}

.InspectionMemberTechnical > summary {
  cursor: pointer;
}

.InspectionDetailMetaLine {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding-block: 2px;
}

/* Six-role model settings matrix. */
.ModelRoleMatrix {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.ModelRoleRow {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.ModelRoleTitleRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.ModelRoleTitle {
  font-size: 13.5px;
  font-weight: 700;
}

.ModelRoleTitleRow > .Tag {
  flex-shrink: 0;
  margin-inline-start: auto;
}

.ModelRoleControls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 10px;
}

.ModelRoleAdvanced {
  margin-top: 8px;
}

.ModelRoleAdvanced > summary {
  cursor: pointer;
}

/* THE shared quick-apply preview dialog: one large
   structured <dialog> per page. Flex column: fixed header, scrollable body,
   fixed action footer — the page never scrolls horizontally because the
   dialog owns its own overflow. */
/* Apply preview rides the canonical AppDialog shell:
   dialog.AppDialog owns border/background/backdrop/padding, DialogHeader/
   DialogTitle/DialogActions own the chrome. Only the SIZE overrides and the
   apply-specific body content styles live here (same pattern as
   dialog.AppDialog.TraceDialog). */
dialog.AppDialog.ApplyPreviewDialog {
  width: min(1000px, calc(100vw - 48px));
  max-height: 90dvh;
}

.ApplyPreviewDialog[open] {
  display: flex;
  flex-direction: column;
}

/* Body content modifier ON the shared .DialogBody: the scrollable flex
   column between the fixed header and footer. */
.DialogBody.ApplyDialogBody {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}

.ApplyDialogBody:focus-visible {
  outline: 2px solid var(--accent, var(--textPrimary));
  outline-offset: -2px;
}

/* Scannable information architecture: one bordered section per group
   (summary / target / comparison / consequences) with a small heading. */
.ApplyDialogSection {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ApplyDialogSection + .ApplyDialogSection {
  border-top: 1px solid var(--border);
  padding-top: 10px;
}

.ApplyDialogSectionTitle {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--textSecondary);
}

.ApplyDialogSummary {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundRaised);
}

/* Compact two-column metadata grid on desktop; stacks on mobile below. */
.ApplyDialogMeta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 16px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundRaised);
}

/* Current + suggested side by side on desktop; stacked on mobile. */
.ApplyDialogTexts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.ApplyDialogTextPane {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  background: var(--backgroundRaised);
}

.ApplyDialogPaneTitle {
  font-size: 12px;
  font-weight: 600;
  color: var(--textSecondary);
  margin-bottom: 6px;
}

.ApplyDialogText {
  font-size: 13px;
  line-height: 1.9;
  overflow-wrap: anywhere;
}

.ApplyDialogText.IsSuggested {
  font-weight: 600;
}

.ApplyDiff {
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-block: 8px;
  font-size: 12.5px;
  line-height: 1.9;
}

.ApplyDiff del {
  color: var(--danger);
  background: var(--dangerBackground);
  text-decoration: line-through;
}

.ApplyDiff ins {
  color: var(--ok, #4ade80);
  background: var(--okBackground, rgba(74, 222, 128, 0.12));
  text-decoration: none;
}

/* Footer modifier ON the shared .DialogActions (flex/gap/padding/border-top
   come from the shell): the apply footer additionally wraps on narrow
   screens and stays pinned below the scrollable body. */
.DialogActions.ApplyDialogActions {
  flex-wrap: wrap;
  align-items: center;
  margin: 0;
  flex: 0 0 auto;
}

@media (max-width: 760px) {
  .ApplyDialogTexts {
    grid-template-columns: 1fr;
  }

  .ApplyPreviewDialog {
    width: calc(100vw - 16px);
    max-height: 94dvh;
  }
}

/* === AI cost-breakdown table contract ===================
   every four-column AI breakdown table on /Reports/AI shares ONE semantic
   colgroup (Name 48% / requests 14% / tokens 20% / cost 18%) selected by the
   table view-model's ColumnLayout — never by title text. Table-layout:Fixed
   makes the colgroup authoritative so corresponding columns across separate
   tables begin and end at identical X coordinates; numeric columns align to
   the logical end with tabular numerals; the first column's wrapped sub
   descriptions can never shift the numeric columns. */
.AICostBreakdownTable {
  table-layout: fixed;
  width: 100%;
}

.AIBreakdownColumnName { width: 48%; }

.AIBreakdownColumnRequests { width: 14%; }

.AIBreakdownColumnTokens { width: 20%; }

.AIBreakdownColumnCost { width: 18%; }

.AICostBreakdownTable th.CellNumericEnd,
.AICostBreakdownTable td.CellNumericEnd {
  text-align: end;
  font-variant-numeric: tabular-nums;
}

.AICostBreakdownTable td {
  overflow-wrap: break-word;
}

.AICostBreakdownTable .CellSub {
  overflow-wrap: break-word;
}

/* Mobile: stacked cards — every value keeps its semantic column label via
   the data-column-label attribute stamped by the shared table macro. */
@media (max-width: 760px) {
  .AICostBreakdownTable,
  .AICostBreakdownTable tbody,
  .AICostBreakdownTable tr {
    display: block;
    width: 100%;
  }

  .AICostBreakdownTable colgroup,
  .AICostBreakdownTable thead {
    display: none;
  }

  .AICostBreakdownTable tbody tr {
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-block-end: 10px;
    padding: 6px 10px;
  }

  .AICostBreakdownTable tbody td {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    border: 0;
    padding: 6px 0;
    text-align: end;
  }

  .AICostBreakdownTable tbody td::before {
    content: attr(data-Column-Label);
    color: var(--textMuted);
    font-size: 12px;
    text-align: start;
  }

  .AICostBreakdownTable tbody td:first-child {
    flex-direction: column;
    gap: 2px;
    text-align: start;
  }
}

/* ==========================================================================
   structured trace text
   ==========================================================================
   The trace modal renders a stored plain-text block either as labelled
   sections or, when the parser declines, as the exact raw block it always had.
   These classes style the structured form only.

   RTL-first: spacing and borders use logical properties, so the same rules are
   correct when a knowledge chunk sets dir="ltr" on itself. Nothing here nests
   another bordered box inside .TraceSection — the structure is expressed with
   headings and whitespace, not with frames inside frames. */
.TraceStructuredText {
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.8;
  color: var(--textSecondary);
}

.TraceStructuredSection {
  min-width: 0;
}

.TraceStructuredSection + .TraceStructuredSection {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.TraceStructuredHeading {
  font-weight: 700;
  font-size: 12px;
  color: var(--textPrimary);
  margin-bottom: 4px;
}

.TraceStructuredSubHeading {
  font-weight: 700;
  font-size: 12px;
  color: var(--textPrimary);
  margin: 8px 0 3px;
}

.TraceStructuredParagraph {
  margin: 0 0 6px;
  overflow-wrap: anywhere;
}

.TraceStructuredParagraph:last-child {
  margin-bottom: 0;
}

.TraceStructuredList {
  margin: 0;
  padding-inline-start: 18px;
  list-style: disc;
}

ol.TraceStructuredList {
  list-style: decimal;
}

.TraceStructuredItem {
  margin: 0 0 3px;
  overflow-wrap: anywhere;
}

.TraceStructuredNote {
  margin: 6px 0 0;
  font-size: 11.5px;
  color: var(--textMuted);
}

/* ==========================================================================
   English prose inside the trace modal
   ==========================================================================
   Natural-language English VALUES read better in Inter than in the Latin
   content stack, but only prose qualifies. The direction resolver already
   stamps dir="ltr" on any value whose first strong character is Latin, so
   these selectors ride that decision rather than guessing from content --
   Persian values keep dir="rtl" and therefore keep Estedad.

   Technical values are excluded on purpose: an id, hash, model id, request id,
   version string or raw JSON block stays on its own technical font so columns
   of identifiers keep aligning and remain visually distinct from prose. */
#TraceModalModelInput .TraceStructuredParagraph[dir="ltr"],
#TraceModalModelInput .TraceContextPropertyLabel[dir="ltr"],
#TraceModalModelInput .TraceContextPropertyValue[dir="ltr"],
#TraceModalModelInput .TraceKnowledgeSectionBody[dir="ltr"],
#TraceModalModelInput .TraceKnowledgeFieldValue[dir="ltr"],
#TraceModalModelInput .TraceAdditionalFieldLabel[dir="ltr"],
#TraceModalModelInput .TraceAdditionalFieldValue[dir="ltr"],
#TraceModalModelInput .TraceAdditionalFieldList[dir="ltr"],
#TraceModalModelInput .TraceStructuredItem[dir="ltr"],
#TraceModalModelInput .TraceKnowledgeQuestion[dir="ltr"] {
  font-family: var(--fontStackEnglish);
}

/* Technical values never take the prose font, even inside the same panel and
   even when they resolve to LTR. */
#TraceModalModelInput .IDText,
#TraceModalModelInput .TraceMonospaceEllipsis,
#TraceModalModelInput .TraceModelCell,
#TraceModalModelInput .TraceRequestIDCell,
#TraceModalModelInput .JSONBlock {
  font-family: var(--monoFont);
}

/* ==========================================================================
   additional prompt-audit fields
   ==========================================================================
   The closing audit fields of the assembled prompt, as label/value pairs
   rather than a run of headings and paragraphs. A field with no value is not
   rendered at all, so nothing here has to style an empty state. Every offset
   is logical, so the same rules hold for an RTL label beside an LTR value. */
.TraceAdditionalFields {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.TraceAdditionalField {
  min-width: 0;
}

.TraceAdditionalFieldLabel {
  margin-bottom: 3px;
  font-size: 11px;
  font-weight: 600;
  color: var(--textMuted);
}

.TraceAdditionalFieldValue {
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.85;
  color: var(--textSecondary);
  overflow-wrap: anywhere;
}

/* A short value reads as a property: brighter and heavier than its label,
   sitting on the same visual line weight as other trace values. */
.TraceAdditionalField:not(.TraceAdditionalFieldWide) > .TraceAdditionalFieldValue {
  font-size: 13px;
  font-weight: 600;
  color: var(--textPrimary);
}

/* A long value -- rules, retrieved-knowledge notes, history, the customer's
   own message -- takes the full width beneath its label. */
.TraceAdditionalFieldWide > .TraceAdditionalFieldValue {
  padding-inline-start: 10px;
  border-inline-start: 1px solid var(--border);
}

/* The customer's own message is quoted content, not a setting: it gets its own
   quiet surface so it reads as a message without any added quotation marks. */
.TraceAdditionalFieldMessage > .TraceAdditionalFieldValue {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundSurface);
  color: var(--textPrimary);
  line-height: 1.9;
}

.TraceAdditionalFieldList {
  margin: 0;
  padding-inline-start: 18px;
}

.TraceAdditionalFieldList > li {
  margin: 0 0 4px;
  overflow-wrap: anywhere;
}

.TraceAdditionalFieldList > li:last-child {
  margin-bottom: 0;
}

/* ==========================================================================
   prompt configuration properties
   ==========================================================================
   Parsed prompt configuration as a real description list: each <dt>/<dd> pair
   is one property card, so the label/value relation survives without a colon
   and without relying on adjacency. Two columns where there is room, one when
   there is not. */
.TraceContextPropertyGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 8px;
  margin: 0;
  min-width: 0;
}

.TraceContextProperty {
  min-width: 0;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--backgroundSurface);
}

.TraceContextPropertyLabel {
  margin: 0 0 2px;
  font-size: 11px;
  font-weight: 600;
  color: var(--textMuted);
}

.TraceContextPropertyValue {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.7;
  color: var(--textPrimary);
  overflow-wrap: anywhere;
}

/* A pair whose value is a whole instruction rather than a setting: same
   semantics, full width, and set at reading weight instead of value weight. */
.TraceContextPropertyWide {
  grid-column: 1 / -1;
}

.TraceContextPropertyWide > .TraceContextPropertyValue {
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.9;
  color: var(--textSecondary);
}

/* ==========================================================================
   structured knowledge records
   ==========================================================================
   One retrieved-knowledge item, rendered identically inside the reconstructed
   system prompt and inside a sent-chunk card. RTL-first: every offset uses a
   logical property, so the same rules hold when a record sets dir="ltr" on a
   Latin value. Deliberately one border level — the record's own — because the
   record already sits inside .TraceSection and a second frame would nest three
   deep. */
.TraceKnowledgeList {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 8px;
  min-width: 0;
}

.TraceKnowledgeRecord {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  min-width: 0;
  background: var(--backgroundRaised);
}

.TraceKnowledgeRecordHead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.TraceKnowledgeRecordNumber {
  font-weight: 700;
  font-size: 12px;
  color: var(--textPrimary);
}

.TraceKnowledgeRecordTitle {
  font-size: 12.5px;
  color: var(--textSecondary);
  min-width: 0;
  overflow-wrap: anywhere;
}

.TraceKnowledgeCount {
  margin-bottom: 4px;
}

/* Compact identification values -- a category, a source, a role. These are
   short, so they read best as a label beside a value and stay visually out of
   the content's way. */
.TraceKnowledgeMeta {
  display: grid;
  grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
  gap: 3px 12px;
  align-items: start;
  min-width: 0;
  margin-bottom: 10px;
}

.TraceKnowledgeField {
  display: contents;
}

.TraceKnowledgeFieldLabel {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--textMuted);
  padding-top: 1px;
}

.TraceKnowledgeFieldValue {
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--textSecondary);
  overflow-wrap: anywhere;
}

/* The content itself. Every part is a full-width titled section, so a question
   is never squeezed into a value column and a long Persian answer never lands
   in a narrow cell. */
.TraceKnowledgeMain {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.TraceKnowledgeSection {
  min-width: 0;
}

.TraceKnowledgeSectionLabel {
  font-size: 11px;
  font-weight: 600;
  color: var(--textMuted);
  margin-bottom: 3px;
}

.TraceKnowledgeSectionBody {
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.85;
  color: var(--textSecondary);
  overflow-wrap: anywhere;
}

/* Hierarchy is carried by weight, brightness and spacing only -- the palette
   stays the neutral one the rest of the trace uses. A question is the handle
   the operator scans for, so it is brighter than the answer beneath it. */
.TraceKnowledgeQuestionSection > .TraceKnowledgeSectionBody {
  color: var(--textPrimary);
}

.TraceKnowledgePrimary > .TraceKnowledgeSectionBody {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.7;
  padding-inline-start: 10px;
  margin-inline-start: 8px;
}

/* Alternative phrasings are supporting evidence, not the question itself. */
.TraceKnowledgeSecondary > .TraceKnowledgeSectionBody {
  font-size: 12px;
  color: var(--textMuted);
}

/* The answer is the payload of the record: the longest text and the one most
   often read end to end. It is inset beneath its own label behind a quiet
   guide line, so it reads as the body of the section rather than as one more
   metadata value sitting level with everything else. Logical properties only,
   so the inset lands on the correct side in RTL and in an LTR value alike. */
.TraceKnowledgeAnswerSection > .TraceKnowledgeSectionBody {
  line-height: 2;
  padding-inline-start: 10px;
  margin-inline-start: 8px;
}

.TraceKnowledgeArticleSection > .TraceKnowledgeSectionBody {
  padding-inline-start: 10px;
  border-inline-start: 1px solid var(--border);
  margin-inline-start: 8px;
}

.TraceKnowledgeArticleSection > .TraceKnowledgeSectionLabel {
  font-size: 12px;
  color: var(--textPrimary);
}

/* Related questions read as children of their own label: inset, numbered, with
   the number hanging outside the text so a wrapped question aligns with itself
   rather than under its own digit. */
.TraceKnowledgeQuestionList {
  margin: 0;
  padding-inline-start: 22px;
  list-style: decimal;
}

/* Persian numerals for the numbered list; decimal stays the fallback where the
   counter style is unavailable. */
ol.TraceKnowledgeQuestionList {
  list-style-type: decimal;
  list-style-type: persian;
}

.TraceKnowledgeSecondary .TraceKnowledgeQuestionList {
  list-style: disc;
  padding-inline-start: 18px;
}

.TraceKnowledgeQuestion {
  margin: 0 0 5px;
  padding-inline-start: 2px;
  overflow-wrap: anywhere;
}

.TraceKnowledgeQuestion:last-child {
  margin-bottom: 0;
}

.TraceKnowledgeAnswer {
  min-width: 0;
}

/* Answer paragraphs carry their own metrics: a fixed 20px line box and no
   margin at all, so consecutive paragraphs of one answer read as one block of
   prose. Scoped to the DIRECT children of an answer -- paragraphs everywhere
   else in the trace keep their own spacing. The former last-child margin reset
   is gone with the margin it used to cancel. */
.TraceKnowledgeAnswer > .TraceStructuredParagraph {
  line-height: 20px;
  margin: 0;
}

/* A list inside the answer is one level deeper than the answer's own inset. */
.TraceKnowledgeAnswer > .TraceStructuredList {
  margin: 0 0 6px;
  padding-inline-start: 20px;
}

.TraceKnowledgeAnswer > .TraceStructuredList:last-child {
  margin-bottom: 0;
}

/* Tags: a quiet wrapping strip, not a colour wall. Legibility comes from the
   chip's own border and padding, never from a fill colour. */
.TraceKnowledgeTags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px 6px;
  padding-top: 1px;
}

.TraceKnowledgeTag {
  font-size: 11.5px;
  line-height: 1.6;
  padding: 2px 8px;
  max-width: 100%;
  border: none;
  border-radius: var(--radius);
  background: var(--backgroundNeutralControl);
  color: var(--textSecondary);
  overflow-wrap: anywhere;
}

/* The category keeps its whole path on one run of text; it wraps only when it
   genuinely must, and never breaks at its own hyphen by preference. */
.TraceKnowledgeCategoryValue {
  color: var(--textPrimary);
  font-weight: 600;
  overflow-wrap: normal;
  word-break: normal;
}

.TraceKnowledgeShape {
  font-size: 11px;
}

/* Text the parser recognised but could not classify. It is still shown, just
   set apart so it reads as leftover rather than as content. */
.TraceKnowledgeAdditional > .TraceKnowledgeSectionBody {
  border-inline-start: 2px dashed var(--border);
  padding-inline-start: 8px;
}

/* A sent-chunk card already frames its own content, so the single record
   inside it must not draw a second border in the card's own background
   colour -- that reads as a stray outline around nothing. A chunk that really
   did split into several records keeps its frames, because there the borders
   separate one record from the next. */
.TraceKnowledgeChunk > .TraceKnowledgeList {
  margin-top: 0;
}

.TraceKnowledgeChunk > .TraceKnowledgeList > .TraceKnowledgeRecord:only-child {
  border: 0;
  border-radius: 0;
  padding: 0;
  background: transparent;
}

/* Narrow screens: the label/value pair stacks, because a 72px label column
   next to a Persian sentence at 390px leaves the value unreadable, and every
   inset shrinks so indentation never eats the reading width. */
@media (max-width: 560px) {
  .TraceContextPropertyGrid {
    grid-template-columns: minmax(0, 1fr);
  }

  .TraceKnowledgeQuestionList {
    padding-inline-start: 17px;
  }

  .TraceKnowledgeSecondary .TraceKnowledgeQuestionList {
    padding-inline-start: 15px;
  }

  .TraceKnowledgeAnswerSection > .TraceKnowledgeSectionBody,
  .TraceKnowledgeArticleSection > .TraceKnowledgeSectionBody {
    padding-inline-start: 7px;
    margin-inline-start: 0;
  }

  .TraceKnowledgeAnswer > .TraceStructuredList {
    padding-inline-start: 16px;
  }

  .TraceAdditionalFieldWide > .TraceAdditionalFieldValue {
    padding-inline-start: 7px;
  }

  .TraceAdditionalFieldMessage > .TraceAdditionalFieldValue {
    padding: 7px 8px;
  }

  .TraceAdditionalFieldList {
    padding-inline-start: 16px;
  }

  .TracePrimaryQueryRow {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 2px;
  }

  .TracePrimaryQueryLabel,
  .TracePrimaryQueryText {
    grid-column: 1;
  }

  .TraceKnowledgeMeta {
    grid-template-columns: minmax(0, 1fr);
    gap: 1px;
  }

  .TraceKnowledgeFieldLabel {
    grid-column: 1 / -1;
    padding-top: 4px;
  }

  .TraceKnowledgeFieldValue {
    grid-column: 1 / -1;
  }

  .TraceKnowledgeRecord {
    padding: 8px 10px;
  }

  .TraceKnowledgePrimary > .TraceKnowledgeSectionBody {
    font-size: 13px;
    padding: 6px 8px;
  }
}
