/* Hide the asterisk indicator */

.w2ui-field.w2ui-required:not(.w2ui-field-inline) > div::before {
    display: none !important;
}

/* Thread-attached PDF overlay (Apryse-persistent pattern, body-rooted).
   Backgrounds defined here (not inline in JS) so toggling dark / light
   mode at runtime restyles every cached overlay without us needing to
   re-render them — body.appbuilder-dark cascading does the work.
   Built by Builder_Threads._GetOrCreatePdfOverlay (see comments there). */
.thread-ref-overlay-corridor,
.thread-ref-overlay-inner {
    background-color: white;
}
body.appbuilder-dark .thread-ref-overlay-corridor,
body.appbuilder-dark .thread-ref-overlay-inner {
    background-color: #1f1f1f;
}

.w2ui-field-helper + .w2ui-required ~ label,
div[class*="required"] label::after {
  content: "*";
  color: #E96725;
}

.w2ui-tabs {
    height: 36px !important;
}

.w2ui-tabs .w2ui-scroll-wrapper .w2ui-tab {
	height: 34px !important;
	/* height: 28px; */
    padding: 10px 20px 7px 20px !important;
	/* padding: 7px 20px 4px 20px; */
}

.w2ui-tabs .w2ui-scroll-wrapper .w2ui-tab.closable {
  /* padding: 6px 28px 6px 20px; */
  padding: 11px 28px 5px 20px !important;
}

.w2ui-tabs .w2ui-scroll-wrapper .w2ui-tab .w2ui-tab-close {
  top: 10px !important;
}

/* ----------------------------------------------------------------------
 * Tabs inside a FORM DIALOG (w2form `tabs` + per-field `html.page`).
 *
 * ONE NUMBER MATTERS: w2ui's .w2ui-form-tabs adds `padding-top: 4px`, and
 * w2form positions .w2ui-page immediately below the bar's height. So the tab
 * must satisfy  4px + tabHeight <= barHeight  or its bottom edge slides under
 * the page, which is opaque — and the first casualty is the 2px active
 * underline sitting in exactly those last pixels.
 *
 * The app's global gives a 36px bar with 34px tabs: 4 + 34 = 38 > 36. That is
 * the whole bug, and it is why only the blue line vanished while the labels
 * looked fine.
 *
 * So: leave the bar at the global 36px and shorten the TAB to 30px, which
 * leaves 2px of clearance below the border. Measured, not guessed — the tab's
 * bottom edge was landing 2px past the page's top.
 * ---------------------------------------------------------------------- */
.w2ui-form .w2ui-form-tabs .w2ui-tab {
	height: 30px !important;
	padding: 6px 18px 4px 18px !important;
}

/* ONLY the border. The active tab's lighter background comes from w2ui's rule
   in light mode and the app's dark rule in dark mode — an earlier version of
   this forced `background-color: transparent` and flattened both, a worse
   regression than the missing line it was fixing. In dark mode the app's
   global sets only the border COLOUR, so the width has to come from here or
   there is nothing to colour. */
.w2ui-form .w2ui-form-tabs .w2ui-tab.active {
	border-bottom: 2px solid #0175ff !important;
}
body.appbuilder-dark .w2ui-form .w2ui-form-tabs .w2ui-tab.active {
	border-bottom: 2px solid #269DF0 !important;
}
/*
{
	color: black !important;
	font-weight: 700 !important;
}
*/

.w2ui-form {
	height: 100% !important;
	overflow: auto !important;
}


.builder_title {
	position: absolute;
	top: 12px;
	left:16px;
}

.builder_title div {
	user-select: none;
	font-family: OpenSans;
	font-size:20px;
	line-height:24px;
	color: rgb(1, 117, 255);
	padding: 8px;
}

.builder_application_title {
	cursor: pointer;
	display: inline-block;
	border-radius: 12px;
	transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
	outline: none;
}

.builder_application_title:hover {
	background-color: #E8E8E8;
	color: #27251e;
}
.builder_application_title:active {
	transform: scale(0.96);
}

/* Template indicator — amber bullet rendered before the title
   when the currently-open application is a template. */
.builder_template_bullet {
	display: inline-block;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background-color: #E6A817;
	box-shadow: 0 0 0 2px rgba(230, 168, 23, 0.25);
	vertical-align: middle;
	margin: 0 6px 2px 2px;
}
body.appbuilder-dark .builder_template_bullet {
	background-color: #F6C34A;
	box-shadow: 0 0 0 2px rgba(246, 195, 74, 0.25);
}



.builder-table-properties {
	table-layout:fixed;
	width:100%;
	border-collapse: collapse;
	border:1px solid white;
}

.builder-table-properties td {
	border-right:1px solid #EEECEA;
	border-bottom:1px solid #EEECEA;
	padding: 4px;
}

.builder-table-properties tr:last-child td {
  border-bottom: none;
}


.builder-table-properties td:last-child {
  border-right: none;
}

.leftbar_items_gallery {
	position:absolute;
	left:0px;
	top:48px;
	/* Reserve room at the bottom for Admin (bottom:52, h:36) + Disconnect
	   (bottom:8, h:36) plus a small gap, so the scrolling gallery cannot
	   overlap the two pinned commands. */
	height:calc(100% - 144px);
	width:100%;
	display:none;
	overflow:hidden;
	/* No top border — the line below the logo was redundant with the
	   logo's own bottom edge and read as visual noise.
	   No bottom border either — the explicit .leftbar_bottom_sep div
	   now draws the divider above Tower Control / Admin / Disconnect
	   and matches the top .leftbar_pinned_sep in color and weight. */
}

/* Fixed block above the scrolling gallery: holds Home / Threads /
   Dashboards in test mode so they remain visible regardless of how many
   tables overflow the scrollable area below. */
.leftbar_pinned_top {
	position: absolute;
	left: 0px;
	top: 48px;
	width: 100%;
	display: none;
}

/* Two thin dividers framing the per-app section of the sidebar:
   - .leftbar_pinned_sep sits below Home/Threads/Datarooms/Dashboards
   - .leftbar_bottom_sep sits above Tower Control / Admin / Disconnect
   Same color/thickness/inset for both so they read as a matched pair. */
.leftbar_pinned_sep,
.leftbar_bottom_sep {
	height: 1px;
	background-color: #d9d6d0;
	padding: 0;
	border-radius: 0;
	cursor: default;
}
.leftbar_pinned_sep {
	margin: 6px 10px;
}
.leftbar_bottom_sep {
	position: absolute;
	left: 10px;
	right: 10px;
	pointer-events: none;
}
body.appbuilder-dark .leftbar_pinned_sep,
body.appbuilder-dark .leftbar_bottom_sep {
	background-color: #3a3a3a;
}

.leftbar_items_track {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	transition: transform 0.3s ease;
}

.leftbar_item {
	width:36px;
	height:36px;
	font-size: 24px;
	color:#F0F0F0;
	box-sizing: border-box;
	/* Fixed left/right margin instead of `auto` so the icon never
	   moves during the width transition — see collapsible sidebar. */
	margin: 10px 6px;
	/* Reserve 1 px border always so hover doesn't shift layout. */
	border: 1px solid transparent;
	border-radius: 4px;
	/* flex-start + padding-left:1 keeps the glyph center pinned at
	   x = 24 (6 margin + 1 border + 1 padding + 4 i-padding + 12 half
	   glyph) in both collapsed and expanded states — so when the item
	   widens on expand the icon doesn't drift. */
	padding-left: 1px;
	display: flex;
	align-items: center;
	justify-content: flex-start;
	text-align:left;
	cursor: pointer;
	overflow: hidden;              /* clip labels when item is narrow (collapsed) */
	position: relative;            /* anchor for the absolute label */
	transition: width 0.25s ease, background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.leftbar_item i
{
	padding:4px;
	flex-shrink: 0;                /* don't shrink the icon when item gets wider */
}

.leftbar_item:hover
{
	color:#2C2C2C;
	background-color: #F0F0F0;
	border-color: #E0E0E0;
}

/* Active/selected sidebar item (e.g. current home-page panel). */
.leftbar_item.leftbar_item_active {
	color:#2C2C2C;
	background-color: #FFFFFF;
	border-color: #C8C8C8;
}
body.appbuilder-dark .leftbar_item.leftbar_item_active {
	color:#FFFFFF;
	background-color: #3A3A3A;
	border-color: #555555;
}

/* Expanded: item stretches to cover the row so the hover background
   spans icon + label.  The icon stays locked at x=24 thanks to the
   flex-start + padding-left rule above. */
#mySidebar.sidebar-expanded .leftbar_item {
	width: calc(100% - 12px);
}

/* Same treatment for .leftbar_command (base rule lives in
   ChapsV_AppSFA.css: position:absolute, left:6, width:36, height:36).
   Override here to make it flex + padding-left:1 + transitions so
   hover covers the full expanded row and the icon glyph stays locked
   at x=24 just like .leftbar_item. */
.leftbar_command {
	box-sizing: border-box;
	padding-left: 1px;
	border: 1px solid transparent;
	border-radius: 4px;
	display: flex;
	align-items: center;
	justify-content: flex-start;
	text-align: left;
	overflow: hidden;
	transition: width 0.25s ease, background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.leftbar_command i {
	flex-shrink: 0;
}
.leftbar_command:hover {
	border: 1px solid #E0E0E0;     /* keep bg + color from SFA base hover */
}
#mySidebar.sidebar-expanded .leftbar_command {
	width: calc(100% - 12px);
}


.leftbar_gallery_btn {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	width: 28px;
	height: 28px;
	border: none;
	border-radius: 50%;
	box-sizing: border-box;
	background: rgba(60, 60, 60, 0.85);
	color: #c0c0c0;
	font-size: 11px;
	cursor: pointer;
	z-index: 10;
	display: none;
	align-items: center;
	justify-content: center;
	transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
	outline: none;
	user-select: none;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}
.leftbar_gallery_btn:hover {
	background: rgba(80, 80, 80, 0.95);
	color: #ffffff;
}
.leftbar_gallery_btn:active {
	transform: translateX(-50%) scale(0.88);
	background: rgba(100, 100, 100, 0.95);
}
/* Buttons are siblings of the gallery (inside #mySidebar) so the gallery's
   overflow:hidden cannot clip them. Their top/bottom in px are relative to
   #mySidebar: down button sits on the gallery's bottom border (gallery
   bottom = sidebar bottom 52px → center 14px above it = bottom:38px). The
   up button's top is set dynamically from JS since its Y depends on how
   tall the pinned-top block is. */
/* Down button centers on the gallery's bottom border. Gallery bottom is now
   96px from the sidebar bottom (Admin + Disconnect + gap), so the 28px-tall
   button sits at 96 - 14 = 82px. */
.leftbar_gallery_btn.down { bottom: 82px; }

/* ================================================================
 * Collapsible sidebar
 * Default width is 48px (inline style on <td id='mySidebar'>).
 * Expanded state adds .sidebar-expanded which forces 200px with
 * !important to beat the inline style. CSS transition handles the
 * smooth animation both ways.
 * ================================================================ */
#mySidebar {
	transition: width 0.25s ease;
	/* Clip any label that momentarily sticks out past the sidebar
	   while the width transitions (labels are absolute-positioned
	   to the right of icons and fade with opacity). */
	overflow: hidden;
}
#mySidebar.sidebar-expanded {
	width: 200px !important;
}

/* Top area: wraps the logo + toggle button so a single :hover on
   this container can swap their visibility (collapsed state). */
.leftbar_top {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 48px;
	user-select: none;
}

/* The logo keeps its current 32×32 position. Collapsed: not clickable
   (the invisible toggle behind it captures clicks so the whole top
   area toggles). Expanded: clickable → goes Home. */
.leftbar_logo {
	transition: opacity 0.15s ease;
}
#mySidebar:not(.sidebar-expanded) .leftbar_logo {
	pointer-events: none;
}

/* Expand/collapse button. Same 32×32 footprint as the logo so they
   overlay each other pixel-for-pixel when collapsed. */
.leftbar_toggle {
	position: absolute;
	top: 12px;       /* 36×36 centered on same Y as the 32×32 logo (center y = 30) */
	width: 36px;     /* match the 36×36 footprint of .leftbar_item / .leftbar_command */
	height: 36px;
	box-sizing: border-box;   /* so a 1 px hover border doesn't grow the box */
	display: flex;
	align-items: center;
	justify-content: center;
	color: #F0F0F0;
	font-size: 20px;
	cursor: pointer;
	border: 1px solid transparent;   /* reserve the 1 px ring so hover doesn't shift */
	border-radius: 4px;
	transition: opacity 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
/* Light-mode hover matches .leftbar_item / .leftbar_command */
.leftbar_toggle:hover {
	color: #2C2C2C;
	background-color: #F0F0F0;
	border: 1px solid #E0E0E0;
}

/* Collapsed: toggle overlays the logo slot, invisible but clickable.
   On hover of the top area, the logo fades out and the toggle fades
   in — visual cue that clicking expands the sidebar.  left:6 matches
   the collapsed item/command position (margin:auto on a 36 px square
   in a 48 px column = 6 px).  No background color here — the logo
   already fades out via opacity, and leaving this transparent lets
   the :hover rule control the bg (otherwise this higher-specificity
   selector would beat `.leftbar_toggle:hover` and force dark). */
#mySidebar:not(.sidebar-expanded) .leftbar_toggle {
	left: 6px;
	opacity: 0;
	pointer-events: auto;
}
#mySidebar:not(.sidebar-expanded) .leftbar_top:hover .leftbar_logo {
	opacity: 0;
}
#mySidebar:not(.sidebar-expanded) .leftbar_top:hover .leftbar_toggle {
	opacity: 1;
}

/* Expanded: toggle docks to the right edge, always visible. Logo
   stays on the left aligned with the other icons.  right:6 gives
   the same 6 px gutter the items/commands have on the left. */
#mySidebar.sidebar-expanded .leftbar_toggle {
	right: 6px;
	left: auto;
	opacity: 1;
}

/* Labels sit INSIDE the item/command, to the right of the icon,
   using left:38 (past the 32 px wide <i> plus a gap) and right:8.
   In collapsed state the item is 36 px wide, so the label has
   negative width and is invisible (also opacity:0).  When the item
   widens during expand, the label has real width and is revealed
   via opacity.  The item's overflow:hidden clips the label while
   the width animates, so no text leaks out.  Positioning the label
   inside the item (instead of to its right) means the hover
   background covers icon + label as a single row. */
.leftbar_item_label,
.leftbar_command_label {
	position: absolute;
	left: 38px;
	right: 8px;
	top: 50%;
	transform: translateY(-50%);
	font-size: 14px;
	font-family: OpenSans, sans-serif;
	color: inherit;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	text-align: left;
	user-select: none;
	pointer-events: none;             /* clicks pass through to the item */
	opacity: 0;
	transition: opacity 0.2s ease;
}

/* Expanded state: labels fade in. */
#mySidebar.sidebar-expanded .leftbar_item_label,
#mySidebar.sidebar-expanded .leftbar_command_label {
	opacity: 1;
}

/* Custom hover tooltip — rendered as a single <div> in <body> by
   JS and positioned via getBoundingClientRect().  Only shown when
   the sidebar is collapsed; when expanded, labels make it
   redundant.  Uses position:fixed to escape the
   .leftbar_items_gallery's overflow:hidden which would clip a
   pseudo-element. */
.leftbar_tooltip {
	position: fixed;
	padding: 4px 10px;
	background: #2C2C2C;
	color: #F0F0F0;
	border: 1px solid #505050;
	border-radius: 4px;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	white-space: nowrap;
	z-index: 10000;
	pointer-events: none;
	transform: translateY(-50%);
	opacity: 0;
	transition: opacity 0.1s ease;
}
.leftbar_tooltip.visible {
	opacity: 1;
}

/* Dark mode */
body.appbuilder-dark .leftbar_toggle {
	color: var(--fg-muted);
}
body.appbuilder-dark .leftbar_toggle:hover {
	color: var(--fg-strong) !important;
	background-color: var(--bg-hover) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .leftbar_tooltip {
	background: var(--bg-elev);
	color: var(--fg);
	border-color: var(--border-strong);
}



.req-row-added    { background-color: #e6ffed !important; }
.req-row-updated  { background-color: #fff9e6 !important; }
.req-row-deleted  { background-color: #ffecec !important; color: #606060 !important; }
.req-row-none    { background-color: transparent !important; }
.req-row-deprecated  { background-color: #F0F0F0 !important; }

.req-cell-deleted { text-decoration: line-through; color: #606060 !important; }
.req-cell-changed { background-color: #fff2cc !important; }
.req-cell-added { background-color: #296839 !important; }

.tag-added {
	background-color: #2ecc71;
	color: #fff;
}

.tag-updated {
	background-color: #f1c40f;
	color: #000;
}

.tag-deleted {
	background-color: #e74c3c;
	color: #fff;
}


.tag-domain {
	background-color: #574964;
	color: #fff;
}

.tag-table {
	background-color: #9F8383;
	color: #fff;
}

.tag-workflow {
	background-color: #C8AAAA;
	color: #fff;
}

.tag-dependency {
	background-color: #FFDAB3;
	color: #000;
}

.tag-metadata {
	background-color: #C8AAAA;
	color: #000;
}

.tag-relationship {
	background-color: #FFDAB3;
	color: #000;
}

.tag-column {
	background-color: #C8AAAA;
	color: #000;
}

.tag-status {
	background-color: #ECF3FE;
	color: #000;
}

.tag-priority {
	background-color: #DDE3E9;
	color: #000;
}

.tag-category {
	background-color: #F4DED1;
	color: #000;
}

.tag-is-main-table {
	background-color: #F4DED1;
	color: #000;
}

.tag-type {
	background-color: #F4DED1;
	color: #000;
}

.tag-related-requirement {
	background-color: #F2F0EC;
	border: 1px solid #c0c0c0 !important;
	color: #000;
}

.chat_button {
	display: inline-block;
	/* Room between chips. One chip never needed it; a welcome that offers five
	   wrapped into a solid block. Margin only, so light and dark are untouched. */
	margin: 3px 6px 3px 0;
	border: 0px;
	font-family: OpenSans;
	font-size: 12px;
	border-radius: 12px;
	line-height: 24px;
	height: auto;
	padding-left: 12px;
	padding-right: 12px;
	padding-top:2px;
	padding-bottom:2px;
	box-sizing: border-box;
	background-color:#269DF0;
	color: white;
	cursor: pointer;
	transition: background-color 0.15s ease, transform 0.1s ease;
	outline: none;
}

/* The welcome line sits closer to its chips in the research panel: the
   paragraph kept its full bottom margin above the first chip, which read as
   a gap between two unrelated things. Scoped to the docked panel, where the
   welcome is the only bubble that carries chips under prose. */
.co_ws_chathost p:has(+ .chat_button) { margin-bottom: 4px; }


.chat_button:hover {
	background-color: #1F84C6;
}
.chat_button:active {
	background-color: #1268A6;
	transform: scale(0.94);
}

/* Per-turn LLM-mode picklist (next to the chat Send button). Compact
   chip override of .wf-pickbtn so it doesn't overwhelm the prompt
   area. Vertically centered against the 36px-square Send button. */
.builder-chatbot-modepick {
	/* Match send button center: send is 36px tall at bottom:8px, so
	   its vertical centre sits at 26px from the bottom. A 28px-tall
	   chip at bottom:12px shares the same centre. */
	bottom: 12px !important;
	display: inline-flex;
	align-items: center;
	height: 28px;
}
.builder-chatbot-modepick .wf-pickbtn {
	/* Width sizes to content (override global .wf-pickbtn width:100%
	   which combined with text-overflow:ellipsis was truncating
	   "Heavy reasoning"). */
	width: auto;
	max-width: 200px;
	height: 28px;
	font-size: 11px;
	padding: 0 10px;
	line-height: 26px;
	border-radius: 14px;
	background: transparent;
	/* Match the calmness of the More (+) button on the left — same
	   subtle gray border, kept CONSTANT across normal/hover/active/
	   focus so clicking never produces a blue ring. */
	border: 1px solid #d9d6d0;
	color: var(--fg-muted, #666);
	box-sizing: border-box;
	transition: background-color 120ms ease;
}
.builder-chatbot-modepick .wf-pickbtn:hover {
	background-color: #F1F1F1;       /* same hover bg as the More (+) button */
	border-color: #d9d6d0;           /* unchanged on hover */
}
.builder-chatbot-modepick .wf-pickbtn:active {
	background-color: #E8E8E8;
	border-color: #d9d6d0;           /* unchanged on click */
}
/* Suppress the global blue 2px focus outline AND keep the border
   color from drifting on focus. Border stays exactly as default. */
.builder-chatbot-modepick .wf-pickbtn:focus,
.builder-chatbot-modepick .wf-pickbtn:focus-visible {
	outline: none !important;
	border-color: #d9d6d0 !important;
	box-shadow: none !important;
}
.builder-chatbot-modepick .wf-pickbtn-text {
	/* Drop the global ellipsis — the chip is content-sized now. */
	overflow: visible;
	text-overflow: clip;
}
.builder-chatbot-modepick .wf-pickbtn-caret { margin-left: 4px; }

/* Dark mode — clearer contrast on hover so the user can see they're
   interacting. Border still constant across states. */
body.appbuilder-dark .builder-chatbot-modepick .wf-pickbtn {
	border-color: var(--border-strong, #505050);
	color: var(--fg-muted, #a0a0a0);
	background: transparent;
}
body.appbuilder-dark .builder-chatbot-modepick .wf-pickbtn:hover {
	background-color: var(--bg-hover, #2f2f2f);
	border-color: var(--border-strong, #505050);
}
body.appbuilder-dark .builder-chatbot-modepick .wf-pickbtn:active {
	background-color: var(--bg-elev, #262626);
	border-color: var(--border-strong, #505050);
}
body.appbuilder-dark .builder-chatbot-modepick .wf-pickbtn:focus,
body.appbuilder-dark .builder-chatbot-modepick .wf-pickbtn:focus-visible {
	border-color: var(--border-strong, #505050) !important;
}

/* Mode-picker dropdown items — label in normal weight on the left,
   muted explanation on the right. Two spans flow inline; the menu
   row spaces them with a small gap. */
.chatmode_menu_label {
	font-weight: 500;
	color: var(--fg, inherit);
}
.chatmode_menu_explain {
	margin-left: 10px;
	font-size: 11px;
	color: var(--fg-muted, #808080);
	font-style: italic;
}
body.appbuilder-dark .chatmode_menu_label   { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .chatmode_menu_explain { color: var(--fg-muted,  #a0a0a0); }

/* Research citations — numbered footnote chips below the prose. */
.chat_citations {
	margin-top: 10px;
	padding-top: 8px;
	border-top: 1px dashed #e2e2e2;
}
.chat_citations_label {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--fg-muted, #808080);
	margin-bottom: 6px;
}
.chat_citations_list {
	display: flex;
	flex-direction: column;
	gap: 4px;
}
.chat_citation {
	display: flex;
	align-items: baseline;
	gap: 6px;
	font-size: 11px;
	color: #1F84C6;
	text-decoration: none;
	padding: 2px 0;
}
.chat_citation:hover { text-decoration: underline; }
.chat_citation_idx {
	flex: 0 0 auto;
	min-width: 18px;
	font-weight: 600;
	color: var(--fg-muted, #808080);
}
.chat_citation_ttl {
	flex: 1 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
body.appbuilder-dark .chat_citations { border-top-color: var(--bg-hover, #333); }

/* Per-domain progress strip — rendered inside the "working" bubble of
   the Datamodel step while domains are being processed in parallel.
   One chip per affected domain; chips flip pending → done | error as
   their workers resolve. The whole strip disappears with the bubble
   when the final `done` message arrives. */
.chat_domain_progress {
	margin: 0 0 8px 0;
	padding: 8px 10px;
	border: 1px solid var(--border-color, #e6e6e6);
	border-radius: 6px;
	background: var(--bg-surface, #fafafa);
	font-size: 12px;
}
.chat_domain_progress_label {
	font-weight: 600;
	margin-bottom: 6px;
	color: var(--text-muted, #666);
}
.chat_domain_progress_chips {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}
.chat_domain_progress_chip {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 3px 8px;
	border-radius: 12px;
	border: 1px solid var(--border-color, #ddd);
	font-size: 11px;
	line-height: 16px;
	background: var(--bg-card, #fff);
	white-space: nowrap;
}
.chat_domain_progress_chip i { font-size: 10px; }
.chat_domain_progress_chip_pending {
	color: var(--text-muted, #888);
	border-style: dashed;
}
.chat_domain_progress_chip_done {
	color: #1f7a3a;
	border-color: #b6e3c4;
	background: #e9f7ee;
}
.chat_domain_progress_chip_error {
	color: #a32121;
	border-color: #ecb4b4;
	background: #fbe9e9;
}
body.appbuilder-dark .chat_domain_progress {
	background: var(--bg-surface, #1f1f1f);
	border-color: var(--bg-hover, #333);
}
body.appbuilder-dark .chat_domain_progress_chip {
	background: var(--bg-card, #2a2a2a);
	border-color: var(--bg-hover, #444);
}
body.appbuilder-dark .chat_domain_progress_chip_done {
	background: #143b22;
	border-color: #2a6a40;
	color: #a8e6bb;
}
body.appbuilder-dark .chat_domain_progress_chip_error {
	background: #3b1414;
	border-color: #7a2a2a;
	color: #f0a8a8;
}

/* Rich error dialog (ShowErrorDetails / ShowAjaxError) — replaces
   the bare ShowError toast when there's diagnostic detail worth
   surfacing. Used by AjaxPost's default error path and by direct
   callers that have a server stack trace or raw LLM response to
   show. The popup itself is a standard w2popup; these rules style
   its body only. */
.errordlg-body {
	font-family: OpenSans, sans-serif;
	padding: 4px 6px;
}
.errordlg-summary {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	padding: 12px 14px;
	border-left: 4px solid #d9534f;
	background: rgba(217, 83, 79, 0.08);
	border-radius: 4px;
}
.errordlg-summary > i {
	font-size: 22px;
	color: #d9534f;
	flex: 0 0 22px;
	line-height: 22px;
}
.errordlg-summary-text {
	flex: 1 1 auto;
	font-size: 14px;
	line-height: 1.4;
	color: #444;
	white-space: pre-wrap;
	word-break: break-word;
}
.errordlg-toggle {
	margin: 10px 0 6px 0;
	display: flex;
	gap: 16px;
	align-items: center;
	font-size: 12px;
}
.errordlg-toggle a {
	color: #4a90e2;
	text-decoration: none;
	cursor: pointer;
}
.errordlg-toggle a:hover { text-decoration: underline; }
.errordlg-copy { margin-left: auto !important; }
.errordlg-details {
	border: 1px solid #e2e2e2;
	border-radius: 4px;
	background: #fafafa;
	max-height: 380px;
	overflow: auto;
}
.errordlg-details > pre {
	margin: 0;
	padding: 10px 12px;
	font-family: Consolas, "Cascadia Mono", "SF Mono", Menlo, monospace;
	font-size: 11px;
	line-height: 1.45;
	color: #333;
	white-space: pre-wrap;
	word-break: break-word;
}
body.appbuilder-dark .errordlg-summary       { background: rgba(217, 83, 79, 0.18); }
body.appbuilder-dark .errordlg-summary-text  { color: #ddd; }
body.appbuilder-dark .errordlg-details       { background: #1f1f1f; border-color: #333; }
body.appbuilder-dark .errordlg-details > pre { color: #ddd; }

/* Closed-question clarification — a single card with: question →
   option chips → (optional multi-select submit) → (optional inline
   free-text escape). Chips reuse .chat_button. */
.chat_clarify_card {
	margin-top: 10px;
	padding: 10px 12px;
	border: 1px solid #e2e2e2;
	border-radius: 8px;
	background-color: rgba(38, 157, 240, 0.04);
}
.chat_clarify_question {
	font-size: 13px;
	font-weight: 500;
	line-height: 1.4;
	margin-bottom: 8px;
}
.chat_clarify_icon {
	color: #269DF0;
	margin-right: 6px;
}
.chat_clarify_hint {
	font-size: 11px;
	font-weight: 400;
	color: #808080;
	margin-left: 6px;
}
.chat_clarify_options {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}
.chat_clarify_option { white-space: normal; }

/* Multi-select — chips behave as toggles. Styled like the muted
   .tag-related-requirement chips on the domain cards (gray/neutral,
   not flashy blue), with a leading FontAwesome checkbox that swaps
   from fa-square-o (unchecked) to fa-check-square (checked) via CSS
   based on the .chat_clarify_option_selected marker class.
   The renderer emits both icons; CSS hides the wrong one. */
.chat_clarify_option_multi {
	background-color: #F2F0EC;
	color: #000;
	border: 1px solid #c0c0c0;
	font-weight: 400;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.chat_clarify_option_multi:hover {
	background-color: #e8e5dd;
	border-color: #a0a0a0;
}
.chat_clarify_option_multi .chat_clarify_check_empty,
.chat_clarify_option_multi .chat_clarify_check_filled {
	font-size: 14px;
	line-height: 1;
	color: #707070;
}
.chat_clarify_option_multi .chat_clarify_check_filled { display: none; }
.chat_clarify_option_selected .chat_clarify_check_empty  { display: none; }
.chat_clarify_option_selected .chat_clarify_check_filled { display: inline; }
.chat_clarify_option_selected,
.chat_clarify_option_selected:hover {
	background-color: #e6e2d8;
	border-color: #808080;
}
.chat_clarify_option_selected .chat_clarify_check_filled { color: #404040; }
.chat_clarify_actions {
	margin-top: 8px;
	display: flex;
	justify-content: flex-end;
}
.chat_clarify_submit { font-size: 12px; }

/* Inline free-text answer (the "Other" escape hatch). */
.chat_clarify_other {
	margin-top: 8px;
	display: flex;
	gap: 6px;
	align-items: center;
}
.chat_clarify_other_input {
	flex: 1 1 auto;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	padding: 6px 8px;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	outline: none;
	background-color: white;
}
.chat_clarify_other_input:focus { border-color: #269DF0; }
.chat_clarify_other_send {
	flex: 0 0 auto;
	background-color: #269DF0;
	color: white;
	border: 0;
	border-radius: 6px;
	padding: 6px 10px;
	cursor: pointer;
}
.chat_clarify_other_send:hover { background-color: #1F84C6; }

/* Stale — the conversation has moved past this clarification, so its
   chips and free-text input are locked. Pointer-events:none guarantees
   no stale clicks even if a handler races the class addition. */
.chat_clarify_card_stale {
	opacity: 0.55;
	pointer-events: none;
	background-color: rgba(154, 160, 166, 0.06);
	border-color: #eee;
}
.chat_clarify_card_stale .chat_clarify_icon { color: #b0b0b0; }
.chat_clarify_card_stale::after {
	content: 'Answered above';
	display: inline-block;
	margin-top: 6px;
	font-size: 10px;
	color: #a0a0a0;
	font-style: italic;
}

body.appbuilder-dark .chat_clarify_card {
	border-color: var(--bg-hover, #333);
	background-color: var(--bg-elev, #1f1f1f);
}
/* Dark mode — mirrors .tag-related-requirement: muted gray fill,
   subtle border, light gray text. The selected state stays in the
   same neutral family; the check icon (FA fa-check-square) does the
   "picked" signalling — no flashy blue fill.
   Selectors compound TWO classes (.chat_clarify_option.chat_clarify_option_multi)
   to outrank the later-declared `body.appbuilder-dark .chat_button`
   rule (same specificity + same !important) that would otherwise win
   on cascade-order alone and force the solid-blue button background. */
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_multi {
	background-color: rgba(180, 180, 180, 0.15) !important;
	border: 1px solid #505050 !important;
	color: #a0a0a0 !important;
}
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_multi:hover {
	background-color: rgba(180, 180, 180, 0.22) !important;
	border-color: #707070 !important;
}
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_multi .chat_clarify_check_empty,
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_multi .chat_clarify_check_filled {
	color: #808080 !important;
}
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_selected,
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_selected:hover {
	background-color: rgba(220, 220, 220, 0.20) !important;
	border-color: #808080 !important;
	color: #e0e0e0 !important;
}
body.appbuilder-dark .chat_clarify_option.chat_clarify_option_selected .chat_clarify_check_filled {
	color: #c0c0c0 !important;
}
body.appbuilder-dark .chat_clarify_card_stale {
	background-color: var(--bg-elev, #1a1a1a);
	border-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .chat_clarify_card_stale::after { color: var(--fg-muted, #707070); }
body.appbuilder-dark .chat_clarify_hint        { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .chat_clarify_other_input {
	background-color: var(--bg-hover, #2a2a2a);
	border-color: var(--bg-hover, #3a3a3a);
	color: var(--fg, #ddd);
}


.builder-tag {
	position: absolute;
	right: 12px;
	top: 6px;
	border-radius: 8px;
	width: auto;
	padding: 3px 12px 3px 12px;
	border: 0px;
	white-space: nowrap;
	cursor: default;
	font-family: OpenSans;
	font-size: 10px;
	line-height: 100%;
	height: 16px;
	box-sizing: border-box;
}

.builder-tags {
	position: absolute;
	right: 12px;
	top: 6px;
}

.builder-tags >div {
	display: inline-block;
	border-radius: 8px;
	width: auto;
	padding: 3px 12px 3px 12px;
	border: 0px;
	white-space: nowrap;
	cursor: default;
	font-family: OpenSans;
	font-size: 10px;
	line-height: 100%;
	height: 16px;
	box-sizing: border-box;
	margin-left:8px;
}


.builder-inline-tags {
	margin-top: 4px;
}

/* Empty-state CTAs inside a domain card. Render the section header in
   muted text + a dashed-outline button inviting "+ New X" so the user
   doesn't have to right-click empty space to discover the menu. */
.module-empty-section {
	margin-top: 8px;
	font-size: 12px;
	color: var(--text-muted, #888);
	opacity: 0.7;
}
.module-empty-cta {
	margin: 4px 0 6px 0;
	padding: 8px 12px;
	border: 1px dashed var(--border-color, #c8c8c8);
	border-radius: 6px;
	font-size: 12px;
	color: var(--text-muted, #666);
	cursor: pointer;
	user-select: none;
	background: transparent;
	transition: background-color 120ms ease, border-color 120ms ease;
}
.module-empty-cta:hover {
	background: var(--bg-hover, #f2f2f4);
	border-color: var(--accent-color, #6789c9);
	color: var(--text-primary, #333);
}
.module-empty-cta > i {
	margin-right: 6px;
}
body.appbuilder-dark .module-empty-cta:hover {
	background: var(--bg-hover, #2a2a2a);
}

.builder-inline-tags >div {
	display: inline-block;
	border-radius: 8px;
	width: auto;
	padding: 3px 12px 3px 12px;
	border: 0px;
	white-space: nowrap;
	cursor: default;
	font-family: OpenSans;
	font-size: 10px;
	line-height: 100%;
	height: 16px;
	box-sizing: border-box;
	margin-right:8px;
}

.builder-objective-flags {
	position: absolute;
	top: 8px;
	right: 16px;
	font-family: OpenSans;
	color: #27251E;
	font-size: 12px;
}


.builder-acceptable-criteria {
	font-family: OpenSans;
	color: #27251E;
}

.builder-acceptable-criteria div[followup] {
	display: flex;
	align-items: flex-start;
	font-family: OpenSans;
	font-size: 12px;
	padding-top: 4px;
	padding-bottom: 4px;
	border-top: 1px solid #DBD9D4;
}

.builder-acceptable-criteria div[followup] > div {
	line-height: 16px;
	cursor: pointer;
	flex: 1 1 auto;
	min-width: 0; 
}

.builder-acceptable-criteria div[followup] > span {
	margin-left: 4px;
	margin-right: 4px;
	flex-shrink: 0;     
}


.builder-drop-files {
	position:absolute;
	top:-1px;
	left:-1px;
	width:100%;
	height:100%;
	z-index:10000;
	background-color: rgba(38, 157, 240, 0.10);
	border:2px dashed #269DF0;
	border-radius: 16px;
}

.builder-drop-files span {
	position:absolute;
	top:50%;
	left:50%;
	transform: translate(-50%, -50%);
	white-space: nowrap;
	font-family: OpenSans;
	font-size: 32px;
	font-weight: bold;
	color: #269DF0;
}

.massimport-dropzone {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	border: 2px dashed #269DF0;
	border-radius: 16px;
	background-color: rgba(38, 157, 240, 0.04);
	color: #269DF0;
	font-family: OpenSans;
	font-size: 16px;
	font-weight: 600;
	text-align: center;
	padding: 20px;
	box-sizing: border-box;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease;
}

.massimport-dropzone:hover,
.massimport-dropzone-hover {
	background-color: rgba(38, 157, 240, 0.10);
	border-color: #1F84C6;
}

.massimport-dropzone span {
	pointer-events: none;
}

.massimport-error {
	width: 100%;
	height: 100%;
	border: 1px solid #E5A4A4;
	border-radius: 12px;
	background-color: #FCF3F3;
	color: #7A1F1F;
	font-family: OpenSans;
	font-size: 13px;
	padding: 16px;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	gap: 12px;
	overflow: hidden;
	min-height: 0;
}

.massimport-error-title {
	font-size: 15px;
	font-weight: 700;
	color: #A02222;
}

.massimport-error-title i {
	margin-right: 8px;
}

.massimport-error-body {
	flex: 1 1 auto;
	min-height: 0;
	white-space: pre-wrap;
	word-break: break-word;
	overflow-y: auto;
	background-color: #FFFFFF;
	border: 1px solid #EED7D7;
	border-radius: 8px;
	padding: 10px;
	font-family: Consolas, "Courier New", monospace;
	font-size: 12px;
	color: #3a3a3a;
	scrollbar-width: thin;
	scrollbar-color: transparent transparent;
}

.massimport-error-body::-webkit-scrollbar {
	width: 10px;
	height: 10px;
}

.massimport-error-body::-webkit-scrollbar-track {
	background: transparent;
}

.massimport-error-body::-webkit-scrollbar-thumb {
	background-color: transparent;
	border-radius: 8px;
	border: 2px solid transparent;
	background-clip: padding-box;
}

.massimport-error-body:hover {
	scrollbar-color: #666666 #F1F1F1;
}

.massimport-error-body:hover::-webkit-scrollbar-track {
	background-color: #F1F1F1;
	border-radius: 8px;
}

.massimport-error-body:hover::-webkit-scrollbar-thumb {
	background-color: #666666;
}

.massimport-error-body:hover::-webkit-scrollbar-thumb:hover {
	background-color: #3a3a3a;
}

.massimport-error-title,
.massimport-error-actions {
	flex: 0 0 auto;
}

.massimport-error-actions {
	display: flex;
	justify-content: flex-end;
}
	
.builder-menu-agents {
	background-size:40px;
	background-repeat:no-repeat;
	background-position:left middle;
	padding-left: 48px;
	height:54px;
	font-family: OpenSans;
}

.builder-menu-agents >div {
	vertical-align: middle;
}

.builder-menu-agents div[name] {
	color: #27251E;
	font-size: 14px;
}

.builder-menu-agents div[position] {
	color: rgb(115, 116, 133);
	font-size: 12px;
}

/* ── Synthetic-agent picker ("Synthetic Users" + menu submenu) and
   the prompt card. Rounded violet initials tile matching Directory's
   members_avatar_user_synth color; text colors carry dark-mode
   variants so the rows read in both themes. ─────────────────────── */
.builder-synth-avatar {
	width: 34px;
	height: 34px;
	flex: 0 0 34px;
	border-radius: 50%;
	background: #8a6cb1;
	color: #fff;
	font-family: OpenSans;
	font-size: 13px;
	font-weight: 600;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
}
body.appbuilder-dark .builder-synth-avatar { background: #5b4a85; }

.builder-synth-menuitem {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 5px 4px;
}
.builder-synth-menuitem-text { min-width: 0; }
.builder-synth-menuitem-name {
	font-family: OpenSans;
	font-size: 14px;
	color: #27251E;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-synth-menuitem-pos {
	font-family: OpenSans;
	font-size: 12px;
	color: rgb(115, 116, 133);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.appbuilder-dark .builder-synth-menuitem-name { color: var(--fg) !important; }
body.appbuilder-dark .builder-synth-menuitem-pos  { color: var(--fg-muted) !important; }

/* Prompt-card avatar — the existing div[icon] already gives a 40×40
   rounded box + absolute position; we just paint it violet and
   center the initials. */
.builder-chatbot-moreinfo-agent div[icon].builder-synth-avatar-card {
	background: #8a6cb1;
	color: #fff;
	font-family: OpenSans;
	font-size: 14px;
	font-weight: 600;
	display: flex;
	align-items: center;
	justify-content: center;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-synth-avatar-card {
	background: #5b4a85;
}

/* Invited-user card avatar — blue, matching Directory's human-user
   avatar (members_avatar_user). */
.builder-chatbot-moreinfo-agent div[icon].builder-user-avatar-card {
	background: #6b7fb3;
	color: #fff;
	font-family: OpenSans;
	font-size: 14px;
	font-weight: 600;
	display: flex;
	align-items: center;
	justify-content: center;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-user-avatar-card {
	background: #4a5a85;
}

/* Direct-WebAgent card avatar — blue with a globe glyph, distinct
   from human-user (initials) and synthetic-agent (violet initials). */
.builder-chatbot-moreinfo-agent div[icon].builder-webagent-avatar-card {
	background: #2F9EEE;
	color: #fff;
	font-size: 18px;
	display: flex;
	align-items: center;
	justify-content: center;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-webagent-avatar-card {
	background: #1F73AE;
}
/* PlanoAgent card — same avatar shape as the webagent card but
   violet-tinted to read as "task / scheduler" rather than "web". */
.builder-chatbot-moreinfo-agent div[icon].builder-planoagent-avatar-card {
	background: #8a6cb1;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-planoagent-avatar-card {
	background: #6a4d96;
}
/* OrchestroAgent card — green-tinted to read as "workflow /
   orchestration" and pair visually with the sitemap icon. Sits
   alongside Web (blue) and Plano (violet) in the Ask-directly menu. */
.builder-chatbot-moreinfo-agent div[icon].builder-orchestroagent-avatar-card {
	background: #3FAE5A;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-orchestroagent-avatar-card {
	background: #2d8243;
}
/* Helm (trading agent) card — amber-tinted so "the book" reads as its
   own thing beside Web (blue), Plano (violet) and Orchestro (green). */
.builder-chatbot-moreinfo-agent div[icon].builder-helmagent-avatar-card {
	background: #C98A2B;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[icon].builder-helmagent-avatar-card {
	background: #9c6a1e;
}

/* Task draft card — chat bubble showing the fields PlanoAgent
   extracted from natural language. Reuses the .builder-thread-tempo-card
   shell (consistent with the existing TASK_CARD / SLOTS surfaces) and
   adds an action row for Confirm / Edit / Discard. */
.builder-thread-task-draft-actions {
	display: flex;
	gap: 6px;
	margin-top: 10px;
}
.builder-thread-task-draft-actions .w2ui-btn {
	font-size: 12px;
	padding: 4px 12px;
}

/* TASK_CONFIRM diff rows (update action) */
.builder-thread-task-confirm-diff-row {
	flex-wrap: wrap;
	gap: 4px;
}
.builder-thread-task-confirm-diff-label {
	font-weight: 600;
	color: #555;
	min-width: 70px;
}
.builder-thread-task-confirm-diff-from {
	text-decoration: line-through;
	color: #b0b0b0;
}
.builder-thread-task-confirm-diff-to {
	color: #2e7d32;
	font-weight: 600;
}
/* delete action: title icon gets a warning tint (applied inline on the <i> element) */
/* delete confirm button adopts a red tint to signal destructive intent */
.builder-thread-task-draft[data-action='delete'] .builder-thread-task-draft-confirm {
	background-color: #c0392b;
	border-color: #922b21;
	color: #fff;
}
.builder-thread-task-draft[data-action='delete'] .builder-thread-task-draft-confirm:hover {
	background-color: #a93226;
}
body.appbuilder-dark .builder-thread-task-confirm-diff-label { color: #ccc; }
body.appbuilder-dark .builder-thread-task-confirm-diff-to    { color: #81c784; }

.builder-chatbot-button-icon {
	width: 20px;
	height: 20px;
	padding: 8px;
	border-radius: 50%;
	border: 1px solid transparent;
	text-align:center;
}

.builder-chatbot-button-icon:hover {
	background-color: #F1F1F1;
}

.builder-chatbot-button-icon il {
	cursor: pointer;
	font-size: 20px;
}



.builder-chatbot-button-icon-alt {
	width: 20px;
	height: 20px;
	padding: 8px;
	border-radius: 50%;
	background-color: #269DF0;
}

.builder-chatbot-button-icon-alt:hover {
	background-color: #1F84C6;
}

.builder-chatbot-button-icon-alt il {
	cursor: pointer;
	font-size: 20px;
	color:white;
}


/* Used while a thread is generating: shows a "Stop" affordance.
   Red background + white square icon so the action reads as
   destructive/abort, not "disabled". */
.builder-chatbot-button-icon-inactive {
	width: 20px;
	height: 20px;
	padding: 8px;
	border-radius: 50%;
	background-color: #c0392b;
	transition: background-color 0.15s ease;
}

.builder-chatbot-button-icon-inactive:hover {
	background-color: #a93226;
}

.builder-chatbot-button-icon-inactive il {
	cursor: pointer;
	font-size: 20px;
	color: #ffffff;
}

/* Inline "Workflows ▾" picker — sits left of the send button
   inside the prompt area, used to launch a workflow in any
   thread context. Subtle blue chip; doesn't compete with the
   primary send affordance. */
.builder-chatbot-workflowpicker {
	position: absolute;
	bottom: 12px;
	height: 24px;
	padding: 0 10px;
	font: 12px OpenSans, sans-serif;
	color: #4a90e2;
	background-color: rgba(74, 144, 226, 0.10);
	border-radius: 12px;
	cursor: pointer;
	user-select: none;
	transition: background-color 0.12s ease, opacity 0.12s ease;
	/* flex centering keeps the "Workflows" text and the FA caret
	   icon vertically aligned regardless of font metrics. */
	display: inline-flex;
	align-items: center;
	gap: 4px;
}
.builder-chatbot-workflowpicker:hover {
	background-color: rgba(74, 144, 226, 0.20);
}
.builder-chatbot-workflowpicker.disabled {
	opacity: 0.4;
	cursor: not-allowed;
}
.builder-chatbot-workflowpicker.disabled:hover {
	background-color: rgba(74, 144, 226, 0.10);
}
body.appbuilder-dark .builder-chatbot-workflowpicker {
	color: #7AB1F0;
	background-color: rgba(122, 177, 240, 0.14);
}
body.appbuilder-dark .builder-chatbot-workflowpicker:hover {
	background-color: rgba(122, 177, 240, 0.25);
}

/* Per-id horizontal placement. Order left → right is
   Workflows, Skills, Sources, Send. Send sits at right:8px;
   Sources sits next to it, then Skills, then Workflows.
   ID rules sit alongside the shared base so every chip inherits
   the rounded-chip look + dark-mode swap automatically. */
#workflowpicker { right: 216px; }
#skillpicker    { right: 142px; }
#sourcespicker  { right: 52px;  }

/* Dropdown menu opened from the picker. Positioned absolute
   over the page; one row per published workflow. */
.builder-wfpicker-menu {
	position: absolute;
	z-index: 10000;
	min-width: 200px;
	max-height: 320px;
	overflow-y: auto;
	background-color: #ffffff;
	border: 1px solid #e0e0e0;
	border-radius: 8px;
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
	padding: 4px 0;
	font: 13px OpenSans, sans-serif;
}
.builder-wfpicker-item {
	padding: 7px 14px;
	cursor: pointer;
	color: #27251e;
	display: flex;
	align-items: center;
	gap: 8px;
}
.builder-wfpicker-item:hover {
	background-color: #f0f4fb;
	color: #4a90e2;
}
.builder-wfpicker-item .fa {
	font-size: 12px;
	opacity: 0.7;
}
.builder-wfpicker-empty {
	padding: 12px 14px;
	color: #888;
	font-style: italic;
}
body.appbuilder-dark .builder-wfpicker-menu {
	background-color: #242424;
	border-color: #3a3a3a;
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
body.appbuilder-dark .builder-wfpicker-item {
	color: #e6e6e6;
}
body.appbuilder-dark .builder-wfpicker-item:hover {
	background-color: rgba(122, 177, 240, 0.18);
	color: #7AB1F0;
}
body.appbuilder-dark .builder-wfpicker-empty {
	color: #888;
}

/* Separator between favorites and the "Select workflow…" entry. */
.builder-wfpicker-sep {
	height: 1px;
	background-color: #ececec;
	margin: 4px 0;
}
body.appbuilder-dark .builder-wfpicker-sep {
	background-color: #3a3a3a;
}

/* "Select workflow…" entry — visually de-emphasized so it reads
   as a meta action, not another workflow. */
.builder-wfpicker-item-pick {
	color: rgb(115, 116, 133);
	font-style: italic;
}
.builder-wfpicker-item-pick:hover {
	color: #4a90e2;
}
body.appbuilder-dark .builder-wfpicker-item-pick {
	color: var(--fg-muted, #a0a0a0);
}

/* "Browse all…" / "Browse workflows…" tag in the New-Thread row.
   Same chip shape as a normal workflow tag, italicized so it
   reads as a meta action. */
.builder-newthread-workflow-tag-browse {
	font-style: italic;
	opacity: 0.85;
}
.builder-newthread-workflow-tag-browse:hover {
	opacity: 1;
}

/* Favorite star button on a published-workflow card. Sits to
   the left of the Run button, neutral when off, gold when on. */
.builder-published-card-fav {
	background: transparent;
	border: 1px solid transparent;
	border-radius: 6px;
	padding: 6px 8px;
	cursor: pointer;
	color: rgb(115, 116, 133);
	font-size: 14px;
	margin-right: 6px;
}
.builder-published-card-fav:hover {
	background-color: #F1F1F1;
	color: #C9A227;
}
.builder-published-card-fav[data-fav='1'] {
	color: #E2B924;
}
body.appbuilder-dark .builder-published-card-fav {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-published-card-fav:hover {
	background-color: var(--bg-hover, #2a2a2a);
	color: #E2B924;
}
body.appbuilder-dark .builder-published-card-fav[data-fav='1'] {
	color: #E2B924;
}

/* ==============================================================
 * Workflow picker modal — searchable list + inline star toggle.
 * Used by the New-Thread "Browse all…" tag and the followup
 * picker's "Select workflow…" entry.
 * ============================================================== */
.wf-picker-toolbar {
	/* No horizontal padding so the search input spans the full
	   popup width — same outer-edge as the workflow rows below.
	   The row's left/right padding (12px) sets the content inset;
	   the search input matches with its own padding so the visible
	   text starts at the same x-coordinate as the row text. */
	padding: 10px 0 8px;
	border-bottom: 1px solid #ececec;
}
.wf-picker-search {
	display: block;
	width: 100%;
	box-sizing: border-box;
	padding: 8px 12px;
	font-family: OpenSans;
	font-size: 14px;
	border: 1px solid #C0C0C0;
	border-left: 0;
	border-right: 0;
	border-radius: 0;
	outline: none;
}
.wf-picker-search:focus {
	border-color: rgb(38, 157, 240);
}
.wf-picker-list {
	overflow-y: auto;
	max-height: 660px;
}
.wf-picker-row {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 10px 12px;
	cursor: pointer;
	border-bottom: 1px solid #f4f4f4;
}
.wf-picker-row:hover {
	background-color: #F5F8FE;
}
.wf-picker-fav {
	flex: 0 0 auto;
	padding: 2px 4px;
	color: rgb(115, 116, 133);
	cursor: pointer;
}
.wf-picker-fav:hover {
	color: #C9A227;
}
.wf-picker-fav[data-fav='1'] {
	color: #E2B924;
}
.wf-picker-text {
	flex: 1 1 auto;
	min-width: 0;
}
.wf-picker-name {
	font-size: 14px;
	font-weight: 600;
	color: #27251E;
}
.wf-picker-desc {
	font-size: 12px;
	color: rgb(115, 116, 133);
	margin-top: 2px;
	line-height: 1.35;
	/* Show up to four lines (what it does + how/engine + rough time +
	   recipe notes), then ellipsis — descriptions are now detailed enough
	   that two lines cut them off. */
	display: -webkit-box;
	-webkit-line-clamp: 4;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.wf-picker-empty {
	padding: 24px;
	text-align: center;
	color: rgb(115, 116, 133);
	font-style: italic;
}
body.appbuilder-dark .wf-picker-toolbar {
	border-bottom-color: var(--border, #333);
}
body.appbuilder-dark .wf-picker-search {
	background-color: var(--bg-elev, #242424);
	border-color: var(--border, #333);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .wf-picker-row {
	border-bottom-color: var(--border, #333);
}
body.appbuilder-dark .wf-picker-row:hover {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .wf-picker-fav {
	color: var(--fg-muted, #a0a0a0);
}
/* Active (pinned) star stays gold in dark mode — the muted
   override above is more specific than the light-mode gold rule
   so we have to restate it under the dark scope. */
body.appbuilder-dark .wf-picker-fav[data-fav='1'] {
	color: #E2B924;
}
body.appbuilder-dark .wf-picker-fav:hover {
	color: #E2B924;
}
body.appbuilder-dark .wf-picker-name {
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .wf-picker-desc {
	color: var(--fg-muted, #a0a0a0);
}

/* --- Recipes: "user recipe" badge + per-row edit/clone/delete actions --- */
.wf-picker-badge {
	display: inline-block;
	margin-left: 6px;
	padding: 1px 6px;
	font-size: 10px;
	font-weight: 600;
	line-height: 1.5;
	vertical-align: middle;
	border-radius: 9px;
	background-color: #EAF2FE;
	color: rgb(38, 157, 240);
}
/* Operator recipes (saved Operator plans) — distinct amber badge so they
   read differently from user skill recipes. */
.wf-picker-badge.wf-picker-badge-op {
	background-color: #FCEFD9;
	color: #B26A00;
}
body.appbuilder-dark .wf-picker-badge.wf-picker-badge-op {
	background-color: rgba(214, 145, 32, 0.20);
	color: #e0a64d;
}
.wf-picker-actions {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 2px;
	/* Always visible so recipe actions (customize / edit / promote / delete)
	   are discoverable — emphasised slightly more on row hover. */
	opacity: 0.8;
	transition: opacity 0.12s ease;
}
.wf-picker-row:hover .wf-picker-actions {
	opacity: 1;
}
.wf-picker-act {
	padding: 4px 6px;
	color: rgb(115, 116, 133);
	cursor: pointer;
	border-radius: 4px;
}
.wf-picker-act:hover {
	background-color: #ECECEC;
	color: #27251E;
}
.wf-picker-act.danger:hover {
	background-color: #FCE8E6;
	color: #D93025;
}
/* "+ New recipe" affordance under the search box, separated from the
   first skill row by a bottom margin so it doesn't read as a list item. */
.wf-picker-new {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin: 10px 12px 12px;
	padding: 6px 10px;
	font-family: OpenSans;
	font-size: 12px;
	font-weight: 600;
	color: rgb(38, 157, 240);
	background: none;
	border: 1px solid rgb(38, 157, 240);
	border-radius: 6px;
	cursor: pointer;
}
.wf-picker-new:hover {
	background-color: #EAF2FE;
}
body.appbuilder-dark .wf-picker-badge {
	background-color: rgba(38, 157, 240, 0.18);
	color: #6fb8f5;
}
body.appbuilder-dark .wf-picker-act {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .wf-picker-act:hover {
	background-color: var(--bg-hover, #2a2a2a);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .wf-picker-act.danger:hover {
	background-color: rgba(217, 48, 37, 0.22);
	color: #f2867d;
}
body.appbuilder-dark .wf-picker-new {
	color: #6fb8f5;
	border-color: #6fb8f5;
}
body.appbuilder-dark .wf-picker-new:hover {
	background-color: rgba(38, 157, 240, 0.14);
}

/* --- Recipe editor modal --- */
.recipe-edit {
	font-family: OpenSans;
	padding: 4px 2px;
}
.recipe-edit-field {
	margin-bottom: 12px;
}
.recipe-edit-field > label {
	display: block;
	font-size: 12px;
	font-weight: 600;
	color: #27251E;
	margin-bottom: 4px;
}
.recipe-edit-field input[type='text'],
.recipe-edit-field textarea {
	width: 100%;
	box-sizing: border-box;
	padding: 8px 10px;
	font-family: OpenSans;
	font-size: 13px;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	outline: none;
	resize: vertical;
}
.recipe-edit-field input[type='text']:focus,
.recipe-edit-field textarea:focus {
	border-color: rgb(38, 157, 240);
}
.recipe-edit-field textarea {
	min-height: 160px;
	line-height: 1.45;
}
/* Instructions (SKILL.md) editor — fixed height, no resize handle. */
.recipe-edit-field textarea#re_brief {
	height: 370px;
	min-height: 370px;
	resize: none;
}
.recipe-edit-row {
	display: flex;
	gap: 16px;
}
.recipe-edit-row > .recipe-edit-field {
	flex: 1 1 0;
	min-width: 0;
}
.recipe-edit-help {
	font-size: 11px;
	color: rgb(115, 116, 133);
	margin: 4px 0 0;
}
.recipe-edit-origin {
	font-size: 11px;
	color: rgb(115, 116, 133);
	margin-bottom: 10px;
}
body.appbuilder-dark .recipe-edit-field > label {
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .recipe-edit-field input[type='text'],
body.appbuilder-dark .recipe-edit-field textarea {
	background-color: var(--bg-elev, #242424);
	border-color: var(--border, #333);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .recipe-edit-help,
body.appbuilder-dark .recipe-edit-origin {
	color: var(--fg-muted, #a0a0a0);
}

/* Single-popup host: the list, editor and confirm views swap inside here. */
.wf-picker-host { font-family: OpenSans; }

/* Built-in (shipped) recipes — neutral green badge, distinct from Custom
   (blue) and Operator (amber). */
.wf-picker-badge.wf-picker-badge-builtin {
	background-color: #E7F1E8;
	color: #2E7D32;
}
body.appbuilder-dark .wf-picker-badge.wf-picker-badge-builtin {
	background-color: rgba(46, 125, 50, 0.20);
	color: #86c98a;
}

/* Action chips now carry a text label (Customize / Edit / Promote / Delete). */
.wf-picker-act i { margin-right: 4px; }

.recipe-edit-head {
	font-family: OpenSans;
	font-size: 16px;
	font-weight: 600;
	color: #27251E;
	margin: 2px 2px 14px;
}
body.appbuilder-dark .recipe-edit-head { color: var(--fg, #e6e6e6); }

.recipe-edit-actions {
	display: flex;
	justify-content: flex-end;
	gap: 10px;
	margin-top: 16px;
}

/* In-popup confirm view (replaces the list while a destructive action is
   confirmed — avoids a stacked w2confirm dialog). */
.recipe-confirm-view { font-family: OpenSans; padding: 28px 10px 10px; }
.recipe-confirm-msg {
	font-size: 14px;
	line-height: 1.55;
	color: #27251E;
	margin-bottom: 20px;
}
body.appbuilder-dark .recipe-confirm-msg { color: var(--fg, #e6e6e6); }

.w2ui-btn.recipe-danger {
	background: #D93025;
	border-color: #D93025;
	color: #fff;
}
.w2ui-btn.recipe-danger:hover { background: #c5271b; border-color: #c5271b; }

/* Instructions label row + "Draft with AI" affordance. */
.recipe-edit-labelrow {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin-bottom: 4px;
}
.recipe-edit-labelrow > label { margin-bottom: 0; }
.recipe-ai-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 10px;
	font-family: OpenSans;
	font-size: 12px;
	font-weight: 600;
	color: #8324B3;
	background: #F6ECFB;
	border: 1px solid #E2C8F0;
	border-radius: 6px;
	cursor: pointer;
}
.recipe-ai-btn:hover { background: #EFDCF8; }
.recipe-ai-btn:disabled { opacity: 0.6; cursor: default; }
body.appbuilder-dark .recipe-ai-btn {
	color: #c89be8;
	background: rgba(131, 36, 179, 0.18);
	border-color: rgba(131, 36, 179, 0.45);
}
body.appbuilder-dark .recipe-ai-btn:hover { background: rgba(131, 36, 179, 0.28); }


.builder-thread-body-gallery {
	position: relative;
	overflow: hidden;
}

.builder-thread-body-images {
	height: 150px;
	display: flex;
	gap: 12px;
	overflow-x: auto;
	overflow-y: hidden;
	/* `proximity` instead of `mandatory` — mandatory snapping
	   eats small wheel deltas (the strip snaps back before the
	   user crosses a snap point), making mousewheel feel
	   unresponsive. proximity only snaps when motion stops. */
	scroll-snap-type: x proximity;
	scroll-behavior: smooth;
	padding-bottom: 4px;
	position: relative;
}

/* Hide the native horizontal scrollbar — the gallery is now
   driven by the left/right buttons, the bar would just be
   visual noise. */
.builder-thread-body-images::-webkit-scrollbar {
	display: none;
}
.builder-thread-body-images {
	-ms-overflow-style: none;
	scrollbar-width: none;
}

.builder-thread-body-images img {
	height: 100%;
	width: auto;
	flex: 0 0 auto;
	display: block;
	scroll-snap-align: start;
	cursor: pointer;
	border-radius: 8px;
}

/* Gallery left/right nav buttons — same visual chip as the
   vertical .builder-thread-scrollto arrows: 20+8+8 = 36px
   circle, #FAF8F5 background, #C0C0C0 border, soft gray glyph,
   #F1F1F1 hover. Only direction differs. Faded in on hover so
   the chat stays visually quiet at rest, and the arrow at the
   end of the scroll range hides via the `at_edge` attribute. */
.builder-thread-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 10000;
	width: 20px;
	height: 20px;
	padding: 8px;
	border-radius: 50%;
	background-color: #FAF8F5;
	border: 1px solid #C0C0C0;
	cursor: pointer;
	color: rgb(115, 116, 133);
	text-align: center;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease, background-color 0.15s ease;
}

.builder-thread-body-gallery:hover .builder-thread-nav {
	opacity: 1;
	pointer-events: auto;
}

.builder-thread-nav[at_edge] {
	opacity: 0 !important;
	pointer-events: none !important;
}

.builder-thread-nav-left {
	left: 8px;
}

.builder-thread-nav-right {
	right: 8px;
}

.builder-thread-nav:hover {
	background-color: #F1F1F1;
}

.builder-thread-nav il {
	font-size: 20px;
}


.builder-threads-sources {
	padding:8px;
	font-family: OpenSans;
	font-size: 14px;
	color: rgb(115, 116, 133);
}


.builder-threads-sources div[title] {
}

.builder-threads-sources div[source] {
	margin-top: 8px;
	padding: 8px;
	cursor: pointer;
}


.builder-threads-sources div[source] > div[header] {
	color: rgb(39, 37, 30);
}	

.builder-threads-sources div[source]:hover {
	background-color: #F1F1F1;
	border-radius: 8px;
}
	


.builder-threads-source {
	table-layout:fixed;
	width:100%;
	height:100%;
	border-collapse: collapse;
	font-family: OpenSans;
}

.builder-threads-source tr[header] {
	height: 44px;
	border-bottom: 1px solid #EFEFEF;
}

.builder-threads-source tr[header] td {
	position: relative;
}

.builder-threads-source tr[header] div[sources] {
	line-height: 44px;
	font-size: 16px;
	padding-left:4px;
	color: rgb(39, 37, 30);
}

.builder-threads-source tr[header] div[close] {
	position: absolute;
	top: 4px;
	right: 8px;
}

.builder-threads-source tr[body] {
}

.builder-thread-body-banner {
	font-family: OpenSans;
	position:relative;
	width:100%;
	height:36px;
}

/* Banner action icons (download / copy / thumbs) are sized down
   from the prompt-area send button. Banner is 36px tall and the
   icon box is 30px (14 + 8 + 8), so top:3px centers vertically.
   The "X sources" pill matches the same 30px height so the row
   reads as one. */
.builder-thread-body-banner div[download] {
	position: absolute;
	left: 4px;
	top: 3px;
}

.builder-thread-body-banner div[copy] {
	position: absolute;
	left: 40px;
	top: 3px;
}

.builder-thread-body-banner div[sources] {
	position: absolute;
	left: 80px;
	top: 3px;
	height: 30px;
	font-size: 14px;
	line-height: 30px;
	padding-left: 10px;
	padding-right: 10px;
	cursor: pointer;
	border-radius: 15px;
}

.builder-thread-body-banner div[sources]:hover {
	background-color: #F1F1F1;
	color: #333333;
}


.builder-thread-body-banner div[up] {
	position: absolute;
	right: 40px;
	top: 3px;
}

.builder-thread-body-banner div[down] {
	position: absolute;
	right: 4px;
	top: 3px;
}

.builder-thread-body-banner .builder-chatbot-button-icon {
	width: 30px;
	height: 30px;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.builder-thread-body-banner .builder-chatbot-button-icon il {
	font-size: 14px;
	line-height: 1;
}

.builder-thread-body-tooltip {
	position:absolute;
	width: 350px;
	border-radius: 12px;                          /* rounded corners */
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);  /* x, y, blur, color */
	background: #fff;
	z-index:10000;
	cursor:pointer;
	font-family: OpenSans;
	padding:12px;
}

.builder-thread-body-tooltip div[title] {
	font-size: 14px;
	color: rgb(39, 37, 30);
}

.builder-thread-body-tooltip div[title]:hover {
	color: rgb(1, 117, 255);
}

.builder-thread-body-tooltip div[snippet] {
	font-size: 12px;
	color: rgb(115, 116, 133);
}

.builder-thread-body-followup {
	font-family: OpenSans;
	color: #27251E;
}

.builder-thread-body-followup div[title] {
	font-size: 16px;
	line-height: 30px;
	font-weight: 600; 
	margin-top: 12px;
	margin-bottom: 8px;
}


.builder-thread-body-followup div[followup] {
	display: flex;
	align-items: flex-start;
	font-family: OpenSans;
	font-size: 14px;
	padding-top: 8px;
	padding-bottom: 8px;
	border-top: 1px solid #DBD9D4;
}

.builder-thread-body-followup div[followup] > div {
	line-height: 24px;
	cursor: pointer;
	flex: 1 1 auto;
	min-width: 0; 
}

.builder-thread-body-followup div[followup] > span {
	margin-left: 4px;
	margin-right: 4px;
	flex-shrink: 0;     
}

.builder-thread-body-followup div[followup] > div:hover {
	color: rgb(1, 117, 255);
}

.builder-allthreads,
.builder-alldashboards {
	width:100%;
	height:100%;
	overflow:hidden;
	overflow-y:auto;
	overflow-x:auto;
}

/* Pulsing "session in progress" indicator next to thread names
   in the Recent leftbar and the History list. Toggled by the
   STARTSESSION / STOPSESSION handlers (live + replay) via
   Builder_Threads._SetThreadActiveDot. Bluish accent so it
   stays calm — the dot draws the eye without competing with
   the rest of the leftbar UI. */
.thread-active-dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	margin-right: 6px;
	vertical-align: middle;
	border-radius: 50%;
	background-color: #4a90e2;
	box-shadow: 0 0 0 0 rgba(74, 144, 226, 0.55);
	animation: thread-active-pulse 1.5s ease-out infinite;
}
body.appbuilder-dark .thread-active-dot {
	background-color: #7AB1F0;
	box-shadow: 0 0 0 0 rgba(122, 177, 240, 0.55);
}
@keyframes thread-active-pulse {
	0%   { box-shadow: 0 0 0 0   rgba(74, 144, 226, 0.55); }
	70%  { box-shadow: 0 0 0 6px rgba(74, 144, 226, 0); }
	100% { box-shadow: 0 0 0 0   rgba(74, 144, 226, 0); }
}

/* Multi-user thread header. Visually mirrors the right-view-panel
   top toolbar (containerThreadsSourcesToolbar) so the two strips
   feel like the same chrome family: 40px tall, warm cream
   background (#FAF8F5), 1px #e2e2e2 bottom border. */
.builder-thread-header {
	display: flex; align-items: center; gap: 8px;
	/* 39px content + 1px border-bottom = 40px total, matching the
	   right-panel toolbar's `size: 40` (which includes its own
	   1px bottom border). */
	height: 39px; min-height: 39px;
	padding: 0 10px;
	background-color: #FAF8F5;
	border-bottom: 1px solid #e2e2e2;
}
body.appbuilder-dark .builder-thread-header {
	background-color: #1A1A1A; border-bottom-color: #3a3a3a;
}
.builder-thread-header-members { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 22px; }
/* Actions cluster sits on the right; flex children align vertically
   in the centre of the 39px header content. Order is mute first,
   search second → mute renders on the LEFT of the search input. */
.builder-thread-header-actions  { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; margin-left: auto; }
.builder-thread-header-btn {
	cursor: pointer; padding: 4px 8px; border-radius: 4px;
	font-size: 13px; line-height: 14px; color: #555;
}
.builder-thread-header-btn:hover { background: #ececec; color: #222; }
.builder-thread-header-btn.active {
	background: #4a90e2; color: #fff;
}
body.appbuilder-dark .builder-thread-header-btn { color: #ccc; }
body.appbuilder-dark .builder-thread-header-btn:hover { background: #3a3a3a; color: #fff; }

/* HTML source preview inside the right sources panel. Slot has an
   8px gutter around the iframe (matches the image branch above it)
   and overflow:hidden so the outer panel never grows its own
   scrollbar — the iframe's built-in scrollbar is the only one. The
   iframe itself gets the app's standard 6px rounded 1px border so
   it reads as a card, matching PDF-preview chrome elsewhere. */
.thread-source-html-slot {
	width: 100%; height: 100%;
	padding: 8px;
	box-sizing: border-box;
	background: #ffffff;
	overflow: hidden;
}
body.appbuilder-dark .thread-source-html-slot { background: #1A1A1A; }
.thread-source-html-slot > iframe {
	width: 100%; height: 100%;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	background: #ffffff;
	display: block;
}
body.appbuilder-dark .thread-source-html-slot > iframe { border-color: #3a3a3a; }

/* Refto-style user picker in the thread header. The wrapper is
   relatively positioned so the leading user icon can sit on top
   of the input's left padding (same trick used by entry-form
   refto fields). 12px text, vertically centered against the 39px
   header content height. */
.builder-thread-invite-search {
	position: relative; display: inline-flex; align-items: center;
}
.builder-thread-invite-search-icon {
	position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
	font-size: 11px; color: #999; pointer-events: none;
}
/* Specificity bump + !important — global `.w2ui-input` rules
   set their own height / padding that would otherwise stretch
   this field to fill the header and collapse the left padding
   over the user icon. We pin both here. */
.builder-thread-header .builder-thread-invite-search input.w2ui-input {
	width: 200px !important;
	height: 28px !important;
	/* line-height kept below the content box (28 − 2px border = 26)
	   so the native text-selection highlight doesn't paint over the
	   1px inset box-shadow that the :focus rule uses to fake the
	   2px blue border. The input still vertically centers its text. */
	line-height: 22px !important;
	padding: 0 8px 0 24px !important;
	font-family: OpenSans !important;
	font-size: 12px !important;
	background-color: #fff;
	background-image: none !important;     /* kill any inherited search glyph */
	border: 1px solid #d8d4cf;
	border-radius: 4px;
	color: #333;
	box-sizing: border-box;
	vertical-align: middle;
}
.builder-thread-header .builder-thread-invite-search input.w2ui-input::placeholder { color: #999; }
body.appbuilder-dark .builder-thread-invite-search-icon { color: #777; }
body.appbuilder-dark .builder-thread-header .builder-thread-invite-search input.w2ui-input {
	background-color: #2a2a2a;
	border-color: #444;
	color: #ddd;
}
body.appbuilder-dark .builder-thread-header .builder-thread-invite-search input.w2ui-input::placeholder { color: #777; }

/* Custom invite-search dropdown. Owned end-to-end (no w2menu)
   so width + position track the input's bounding rect exactly.
   Position is driven by JS in Builder_ThreadInviteSearchClass;
   we only ship visual styling here. */
.thread-invite-popup {
	position: fixed; z-index: 10000;
	display: none;
	background: #fff; color: #333;
	border: 1px solid #d8d4cf; border-radius: 4px;
	box-shadow: 0 4px 12px rgba(0,0,0,0.12);
	font-family: OpenSans; font-size: 12px;
	max-height: 280px; overflow-y: auto; overflow-x: hidden;
	box-sizing: border-box;
}
.thread-invite-popup .thread-invite-popup-row,
.thread-invite-popup .thread-invite-popup-empty {
	display: flex; align-items: center; gap: 8px;
	padding: 6px 10px; min-height: 32px;
	white-space: nowrap; overflow: hidden;
	cursor: pointer;
}
.thread-invite-popup .thread-invite-popup-row .thread-invite-popup-name {
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto;
	min-width: 0;
}
.thread-invite-popup .thread-invite-popup-row .thread-invite-popup-name span {
	display: inline; /* defeat any global span styling that adds spacing */
}
.thread-invite-popup .thread-invite-popup-row img {
	width: 22px; height: 22px; border-radius: 50%; flex: 0 0 22px; object-fit: cover;
}
.thread-invite-popup .thread-invite-popup-row:hover {
	background: #f0f4f9;
}
.thread-invite-popup .thread-invite-popup-row .fa,
.thread-invite-popup .thread-invite-popup-empty .fa { color: #888; font-size: 18px; flex: 0 0 22px; text-align: center; }
.thread-invite-popup .thread-invite-popup-empty {
	color: #A0A0A0; cursor: default;
}
body.appbuilder-dark .thread-invite-popup {
	background: #2a2a2a; color: #ddd; border-color: #444;
	box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
body.appbuilder-dark .thread-invite-popup .thread-invite-popup-row:hover { background: #3a3a3a; }
body.appbuilder-dark .thread-invite-popup .thread-invite-popup-row .fa,
body.appbuilder-dark .thread-invite-popup .thread-invite-popup-empty .fa { color: #888; }

/* Round avatars in the thread header. Maestro is standalone on
   the left; user/agent avatars stack with negative margin so
   they overlap (Slack-style). The stack is clickable and opens
   the full member dialog. */
.thread-avatar {
	display: inline-flex; align-items: center; justify-content: center;
	width: 28px; height: 28px; border-radius: 50%;
	background-color: #eef2f7; color: #2c3e50;
	font-size: 12px; font-weight: 500;
	border: 2px solid #FAF8F5;     /* matches header bg → white halo */
	box-sizing: border-box;
	overflow: hidden; flex: 0 0 28px;
	user-select: none;
}
.thread-avatar i.fa { font-size: 13px; }

.thread-avatar-maestro {
	position: relative;
	background-color: #d6e4f5; color: #1d4e89;
}
.thread-avatar-maestro.muted { opacity: 0.85; }

/* Maestro group — same overlap-stack vocabulary as the user
   avatars stack. Two circles (mic state on the left, magic
   icon on the right); the whole group is one clickable mute
   toggle. Hover affordance mirrors `.thread-members-stack`
   so the chrome reads as a sibling pill. */
.thread-maestro-group {
	display: inline-flex; align-items: center;
	cursor: pointer;
	padding: 2px 6px; border-radius: 16px;
	margin-right: 4px;
	transition: background-color 120ms ease;
}
.thread-maestro-group .thread-avatar { margin-left: -8px; }
.thread-maestro-group .thread-avatar:first-child { margin-left: 0; }
.thread-maestro-group:hover { background-color: #ececec; }
body.appbuilder-dark .thread-maestro-group:hover { background-color: #3A3A3A; }

/* Mic-state circle. Background + border are inherited from
   `.thread-avatar-maestro` (we add that class on the element)
   so the mic circle matches the Maestro circle exactly in
   both modes. Only the glyph colour overrides — green when
   active, red when muted. Pastel in light, flashy in dark. */
.thread-avatar-mic-circle.on   { color: #2e7d32 !important; } /* pastel green */
.thread-avatar-mic-circle.off  { color: #c0392b !important; } /* pastel red   */
body.appbuilder-dark .thread-avatar-mic-circle.on   { color: #1f8a1f !important; } /* flashy green */
body.appbuilder-dark .thread-avatar-mic-circle.off  { color: #d22f2f !important; } /* flashy red   */

.thread-avatar-user  { background-color: #d6e4f5; color: #1d4e89; }
.thread-avatar-agent { background-color: #efe7ff; color: #5b3da5; }

.thread-members-stack {
	display: inline-flex; align-items: center;
	cursor: pointer;
	padding: 2px 6px; border-radius: 16px;
	transition: background-color 120ms ease;
}
.thread-members-stack .thread-avatar { margin-left: -8px; }
.thread-members-stack .thread-avatar:first-child { margin-left: 0; }
.thread-members-stack:hover { background-color: #ececec; }
body.appbuilder-dark .thread-members-stack:hover { background-color: #3A3A3A; }

body.appbuilder-dark .thread-avatar         { background-color: #333a44; color: #d8e1eb; border-color: #1A1A1A; }
/* In dark mode, user avatars typically render their generated
   default logo (a fixed light-blue PNG) which doesn't darken
   with the theme. To keep Maestro visually flush with that
   surrounding row of user circles, paint it the SAME light
   blue rather than the dark-panel tone. */
body.appbuilder-dark .thread-avatar-maestro { background-color: #D9EAFF; color: #1d4e89; }
body.appbuilder-dark .thread-avatar-user    { background-color: #2a3b52; color: #b9d4f5; }
body.appbuilder-dark .thread-avatar-agent   { background-color: #3a2f55; color: #cfb8ff; }
body.appbuilder-dark .thread-avatar-more    { background-color: #3a4452; color: #d8e1eb; }
body.appbuilder-dark .thread-avatar-badge   { border-color: #1A1A1A; }

/* Members dialog (clicking the stack). Simple list rows with
   avatar + name + role chip + optional remove button. */
.thread-members-dialog { padding: 4px 0; }
.thread-members-dialog-row {
	display: flex; align-items: center; gap: 10px;
	padding: 8px 12px;
	font-family: OpenSans; font-size: 13px;
	border-bottom: 1px solid #eee;
}
.thread-members-dialog-row:last-child { border-bottom: 0; }
.thread-members-dialog-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-members-dialog-role {
	font-size: 11px; color: #888; text-transform: uppercase;
	background: #f0f0f0; padding: 2px 6px; border-radius: 8px;
}
.thread-members-dialog-remove {
	background: transparent; border: none; color: #c0392b; cursor: pointer; font-size: 14px; padding: 4px 8px;
}
.thread-members-dialog-remove:hover { color: #e74c3c; }
.thread-members-dialog-self {
	display: inline-flex; align-items: center; justify-content: center;
	color: #aaa; font-size: 14px; padding: 4px 8px; cursor: not-allowed;
}
.thread-members-dialog-empty {
	padding: 20px; color: #A0A0A0; text-align: center;
}
body.appbuilder-dark .thread-members-dialog-row  { border-bottom-color: #2a2a2a; }
body.appbuilder-dark .thread-members-dialog-role { background: #2a2a2a; color: #aaa; }

/* Unread badge on a thread list row. Anchors to the right edge
   so it sits on the leftbar / history list without disturbing
   the existing layout. Same dot vocabulary as .thread-active-dot
   but solid and amber so the two states aren't confused. */
.thread-unread-badge {
	display: inline-block; width: 8px; height: 8px;
	margin-left: 6px; vertical-align: middle;
	border-radius: 50%; background-color: #f5a623;
}
body.appbuilder-dark .thread-unread-badge { background-color: #f7b955; }

/* Fixed-width slot for the leading marker on a thread list row.
   Holds EITHER the chat / sitemap icon OR the unread badge so the
   name's left edge stays aligned regardless of read state. The badge
   gets no left margin in this context (the slot already provides the
   gap) so it visually sits where the icon would. */
.thread-list-icon-slot {
	display: inline-block;
	width: 1.1em;
	text-align: center;
	vertical-align: middle;
}
.thread-list-icon-slot .thread-unread-badge,
.thread-list-icon-slot .thread-active-dot {
	/* Drop the outer margin both dots carry for their standalone
	   (sibling-of-name) usage — the slot already provides the
	   gap. */
	margin-left: 0;
	margin-right: 0;
	/* Nudge the dots up so their centers match the FontAwesome
	   glyph they replace — `vertical-align:middle` aligns to the
	   text baseline, which sits ~2px below the icon's optical
	   center on the row's line-height. */
	position: relative;
	top: -2px;
}

.builder-allthreads > div,
.builder-alldashboards > div {
	max-width:800px;
	width:100%;
	margin: auto;
}

.builder-allthreads-element,
.builder-alldashboards-element {
	width: 100%;
	position: relative;
	font-family: OpenSans;
	margin-left: 8px;
	margin-right: 8px;
	margin-top: 8px;
	margin-bottom: 16px;
	border-bottom: 1px solid #E2E2E2;
	padding-bottom: 4px;
	cursor: pointer;
}

.builder-allthreads-element > div[name],
.builder-alldashboards-element > div[name] {
	width: 100%;
	font-family: OpenSans;
	font-size: 16px;
	line-height: 30px;
}

.builder-allthreads-element > div[name]:hover,
.builder-alldashboards-element > div[name]:hover {
	color: rgb(1, 117, 255);
}

.builder-allthreads-element > div[description],
.builder-alldashboards-element > div[description] {
	width: 100%;
	font-family: OpenSans;
	font-size: 14px;
	line-height: 20px;
	color: rgb(115, 116, 133);
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;   /* max 2 lines */
	overflow: hidden;
	text-overflow: ellipsis;
}

.builder-allthreads-element > div[date],
.builder-alldashboards-element > div[date] {
	font-family: OpenSans;
	font-size: 11px;
	line-height: 20px;
	color: rgb(115, 116, 133);
}


.builder-thread-body-container {
	position: relative;
	top: 0px;
	width: 100%;
	/* Flex child of the OpenThread outer wrapper. `flex:1 1 auto` +
	   `min-height:0` lets the container shrink to fit alongside the
	   header (and the absolutely-positioned prompt textarea), and
	   keeps the inner overflow:auto working — without min-height:0
	   the flex child refuses to shrink below its content height. */
	flex: 1 1 auto;
	min-height: 0;
	height: auto;
	overflow:hidden;
	overflow-y:auto;
	overflow-x:auto;
	box-sizing: border-box;
}
/* Header is the other flex child — natural height, never shrinks. */
.builder-thread-header { flex: 0 0 auto; }

.builder-thread-body-container >div {
	position: relative;
	left:50%;
	transform: translate(-50%,0%);
	width: 650px;
	max-width: 90%;
	padding-bottom:200px;
	box-sizing: border-box;
}


.builder-thread-body-answer {
	font-family: OpenSans;
	font-size: 14px;
	line-height: 24px;
	color: #27251E;
	margin-bottom:16px;
	box-sizing: border-box;
}

/* Markdown headers inside chat bubbles. Without scoped rules the
   browser default kicks in (h1 = 2em, h2 = 1.5em ≈ 21px on our 14px
   body) which produces a jarring shout when an answer uses ##
   headings as section dividers — exactly what the Claude grounded
   path tends to emit for "Sources / Notes" callouts. Keep the visual
   hierarchy but in much gentler steps relative to the body. */
.builder-thread-body-answer h1,
.builder-thread-body-answer h2,
.builder-thread-body-answer h3,
.builder-thread-body-answer h4,
.builder-thread-body-answer h5,
.builder-thread-body-answer h6 {
	font-family: OpenSans;
	font-weight: 600;
	line-height: 1.35;
	margin: 12px 0 6px;
	color: inherit;
}
.builder-thread-body-answer h1 { font-size: 17px; }
.builder-thread-body-answer h2 { font-size: 16px; }
.builder-thread-body-answer h3 { font-size: 15px; }
.builder-thread-body-answer h4,
.builder-thread-body-answer h5,
.builder-thread-body-answer h6 { font-size: 14px; }
/* First header in a bubble: tighten top margin so it doesn't add an
   extra gap right after the avatar/byline. */
.builder-thread-body-answer > h1:first-child,
.builder-thread-body-answer > h2:first-child,
.builder-thread-body-answer > h3:first-child,
.builder-thread-body-answer > h4:first-child,
.builder-thread-body-answer > h5:first-child,
.builder-thread-body-answer > h6:first-child {
	margin-top: 0;
}

/* Links + autolinked emails inside chat bubbles. The default browser
   blue (#0000ee) clashes hard with both the warm-gray light theme and
   the muted dark theme. Use the same w2ui-style blue we use on the
   user's prompt bubble for consistency, with a slightly lighter dark-
   mode variant so it stays legible on the dark background. Underline
   on hover only — keeps bubbles uncluttered while making the affordance
   obvious on interaction. */
.builder-thread-body-answer a,
.builder-thread-body-prompt a {
	color: #1F84C6;
	text-decoration: none;
}
.builder-thread-body-answer a:hover,
.builder-thread-body-prompt a:hover {
	color: #1466a0;
	text-decoration: underline;
}
body.appbuilder-dark .builder-thread-body-answer a,
body.appbuilder-dark .builder-thread-body-prompt a {
	color: #4a90e2;
}
body.appbuilder-dark .builder-thread-body-answer a:hover,
body.appbuilder-dark .builder-thread-body-prompt a:hover {
	color: #6cb1f5;
}

/* GFM tables emitted by the LLM (Showdown 'github' flavor renders pipe
   tables to real <table>/<thead>/<tbody>). Without scoped rules the
   browser default lays them out with no borders, no padding and columns
   sized to raw content — which reads as "misaligned key/value pairs"
   rather than a table. Match the visual system used by
   .ont_query_rows_table / .llm_cost_table elsewhere in this file:
   single-line row separators, subtle header background, dark-mode
   parallel. Cells wrap (chat bubbles are narrow) but long tokens
   (URLs, hashes) break with overflow-wrap. */
.builder-thread-body-answer table {
	width: 100%;
	max-width: 100%;
	border-collapse: collapse;
	margin: 12px 0;
	font-size: 13px;
	line-height: 1.5;
	table-layout: auto;
}
.builder-thread-body-answer thead th {
	background: #fafafa;
	font-weight: 600;
	color: #555;
	text-align: left;
	padding: 8px 12px;
	border-bottom: 1px solid #e0e0e2;
	vertical-align: top;
}
.builder-thread-body-answer tbody td {
	padding: 8px 12px;
	border-bottom: 1px solid #ececec;
	vertical-align: top;
	overflow-wrap: anywhere;
}
.builder-thread-body-answer tbody tr:last-child td {
	border-bottom: none;
}
.builder-thread-body-answer tbody tr:hover {
	background: #fafafa;
}
/* Numeric columns read cleanest when digits align. Showdown emits
   <th align="right">/<td align="right"> when the GFM header is
   |---:| — the model gets alignment control for free. */
.builder-thread-body-answer th[align="right"],
.builder-thread-body-answer td[align="right"]  { text-align: right; font-variant-numeric: tabular-nums; }
.builder-thread-body-answer th[align="center"],
.builder-thread-body-answer td[align="center"] { text-align: center; }

body.appbuilder-dark .builder-thread-body-answer thead th {
	background: #2c2d31;
	color: #cfcfd3;
	border-bottom-color: #3a3b40;
}
body.appbuilder-dark .builder-thread-body-answer tbody td {
	border-bottom-color: #3a3b40;
	color: #e0e0e2;
}
body.appbuilder-dark .builder-thread-body-answer tbody tr:hover {
	background: rgba(255, 255, 255, 0.03);
}

/* Chat error message — red title + collapsible details, emitted by
   BuilderApplicationStep.FormatExceptionForChat. The wrapper styles
   the headline; <details>/<summary> gets a subtle muted border so
   it's visually distinct from the rest of the assistant message. */
.builder-thread-body-answer .builder-chat-error {
	color: #c62828;
	font-weight: 600;
	margin: 4px 0 8px 0;
	font-size: 14px;
}
body.appbuilder-dark .builder-thread-body-answer .builder-chat-error {
	color: #ef9a9a;
}
.builder-thread-body-answer .builder-chat-error-details {
	margin-top: 6px;
	border: 1px solid rgba(198, 40, 40, 0.25);
	border-radius: 4px;
	padding: 6px 10px;
	background: rgba(198, 40, 40, 0.04);
	font-size: 12px;
}
.builder-thread-body-answer .builder-chat-error-details > summary {
	cursor: pointer;
	color: #c62828;
	font-weight: 500;
	user-select: none;
}
.builder-thread-body-answer .builder-chat-error-details > summary:hover {
	text-decoration: underline;
}
.builder-thread-body-answer .builder-chat-error-details pre {
	white-space: pre-wrap;
	word-break: break-word;
	max-height: 320px;
	overflow-y: auto;
	margin: 6px 0 0 0;
	padding: 8px;
	background: rgba(0, 0, 0, 0.04);
	border-radius: 3px;
	font-family: Consolas, Menlo, monospace;
	font-size: 11px;
	line-height: 1.45;
}
body.appbuilder-dark .builder-thread-body-answer .builder-chat-error-details {
	border-color: rgba(239, 154, 154, 0.35);
	background: rgba(239, 154, 154, 0.06);
}
body.appbuilder-dark .builder-thread-body-answer .builder-chat-error-details > summary {
	color: #ef9a9a;
}
body.appbuilder-dark .builder-thread-body-answer .builder-chat-error-details pre {
	background: rgba(255, 255, 255, 0.06);
	color: var(--fg);
}

/* Inline system message — feedback for slash commands.
   Italic, muted, no card chrome — reads as a CLI echo,
   not as a chat reply. Multi-line content (e.g. /help)
   keeps its line breaks. */
.builder-thread-body-system .builder-thread-system-msg {
	font-style: italic;
	color: #888;
	font-size: 12px;
	line-height: 18px;
	padding: 4px 0;
}
body.appbuilder-dark .builder-thread-body-system .builder-thread-system-msg {
	color: var(--fg-muted, #a0a0a0);
}

/* Slash-command hint popup (anchored to the prompt textarea
   when the input starts with "/"). The host w2tooltip's overlay
   body has a dark gray background (#69717a) in BOTH light and
   dark modes, so the popup uses light text in either case —
   dark text on the dark gray backdrop is unreadable, which is
   why earlier versions looked "invisible" in light mode. */
.w2ui-overlay .slash-help-popup {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	line-height: 18px;
	color: #f4f4f4 !important;
	min-width: 220px;
	padding: 4px 2px;
}
.w2ui-overlay .slash-help-title {
	font-weight: 600;
	margin-bottom: 4px;
	color: #ffffff !important;
}
.w2ui-overlay .slash-help-row {
	display: flex;
	gap: 6px;
	align-items: baseline;
	padding: 1px 0;
}
.w2ui-overlay .slash-help-name {
	font: 11px Consolas, monospace;
	color: #E6D6FF !important;
	background-color: rgba(255, 255, 255, 0.18);
	padding: 1px 5px;
	border-radius: 3px;
	flex: 0 0 auto;
}
.w2ui-overlay .slash-help-desc {
	color: #d6d6d6 !important;
}

/* Brief tooltip-style feedback shown after a slash command
   when no chat container is available (home page). Same
   color scheme rationale — light text on dark tooltip bg. */
.w2ui-overlay .slash-feedback-popup {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	line-height: 18px;
	color: #f4f4f4 !important;
	padding: 2px 2px;
	max-width: 320px;
}

/* /trace:hide — toggled on the wrapper by _ApplyTraceVisibility.
   Hides every diagnostic / error trace card; the green
   workflow_completed card stays visible because it's a
   completion banner, not a trace. */
.builder-hide-traces .wf-trace-card:not(.wf-trace-card-success) {
	display: none !important;
}

/* Elapsed-time counter displayed next to the writing-loading.gif while
   a chat message is in its "working" state.  Muted + monospace digits
   so the number doesn't wiggle as seconds tick up. */
.builder-chat-timer {
	margin-left: 8px;
	font-size: 12px;
	color: #808080;
	font-variant-numeric: tabular-nums;
	user-select: none;
}
body.appbuilder-dark .builder-chat-timer {
	color: var(--fg-muted);
}


.builder-thread-body-answer div[form] {
	position: relative;
	width: 200px;
	min-height: 50px;
	border-radius: 8px;
	background-color: #F2F0EC;
	margin-top: 8px;
	color: #27251EA6;
	cursor: pointer;
}


.builder-thread-body-answer div[form] > div[icon] {
	position: absolute;
	border-radius: 4px;
	background-color: white;
	left: 8px;
	top: 8px;
	width: 32px;
	height: calc(100% - 16px);
	display: flex;
	justify-content: center;
	align-items: center;
}


.builder-thread-body-answer div[form] > div[description] {
	margin-left: 40px;
	padding: 8px;
	font-size: 12px;
	line-height: 16px;
}

.builder-thread-body-answer div[form] > div[description] > span {
	color: #27251E;
}

.builder-thread-body-answer span[sourceid] {
	color: #27251E; /* white; */
	font-family: OpenSans;
	font-size: 8px;
	font-weight: bold;
	border-radius: 4px;
	background-color: #EAE8E4; /* #269DF0; */
	cursor: pointer;
	padding: 4px;
	margin-left:3px;
	vertical-align: top;
}

.builder-thread-body-answer span[sourceid]:hover {
	background-color: #F2F0EC; /*white; */
}



.builder-thread-body-prompt {
	/* CURRENT-USER bubble: soft blue tint with brand-blue text,
	   right-aligned. Reads as "the user's voice" against the
	   warm-gray assistant bubbles. */
	background-color: rgba(38, 157, 240, 0.12);
	border-radius: 8px;
	font-family: OpenSans;
	font-size: 14px;
	line-height: 24px;
	color: #1F84C6;
	margin-left: 100px;
	margin-top: 16px;
	margin-bottom:16px;
	padding:12px;
	box-sizing: border-box;
}

/* PEER-USER bubble — another human in the thread. The element
   carries BOTH `builder-thread-body-prompt` and
   `builder-thread-body-peer` classes; we use the compound
   selector here so the peer rules outrank the dark-mode
   `.builder-thread-body-prompt` override that lives further
   down the file (same-specificity, source-order would otherwise
   win against us in dark mode). Mirrors the "Ask follow-up..."
   container: white panel + gray border in light mode; dark
   panel + gray border in dark mode. Left-aligned, no action row. */
.builder-thread-body-prompt.builder-thread-body-peer {
	position: relative;
	background-color: #F2F0EC !important;  /* warm off-white panel */
	color: #333 !important;
	border: 0 !important;                  /* borderless in light mode */
	margin-left: 50px !important;        /* room for the floating avatar */
	margin-right: 100px !important;
}
body.appbuilder-dark .builder-thread-body-prompt.builder-thread-body-peer {
	background-color: var(--bg-panel) !important;
	color: var(--fg) !important;
	border: 1px solid var(--border) !important;
}

/* Floating avatar to the left of the bubble — anchored on the
   bubble's `position: relative`. 32px circle, slight overlap so
   it visually "owns" the bubble. Falls back to a fa-user glyph
   when no logo is available. */
.builder-thread-body-peer-avatar {
	position: absolute;
	left: -42px; top: 10px;
	width: 32px; height: 32px;
	border-radius: 50%;
	background-color: #d6e4f5; color: #1d4e89;
	display: flex; align-items: center; justify-content: center;
	overflow: hidden;
	border: 2px solid #fff;
	box-sizing: border-box;
	font-size: 14px;
}
body.appbuilder-dark .builder-thread-body-peer-avatar {
	background-color: #2a3b52; color: #b9d4f5;
	border-color: var(--bg);
}
.builder-thread-body-peer-text { white-space: pre-wrap; }

/* Directed prompt — a current-user bubble addressed to a specific
   synthetic agent via the "Synthetic Users" widget. The addressee is
   a small rectangular chip (square violet avatar + name) rendered
   INLINE at the start of the bubble, flowing into the typed text on
   the same line. Sized to sit cleanly on the bubble's 24px line. */
.builder-thread-body-prompt-text { white-space: pre-wrap; }

.builder-thread-directed-chip {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	vertical-align: middle;
	margin: 0 6px 1px 0;
	padding: 1px 6px 1px 1px;
	background: rgba(138, 108, 177, 0.15);
	border: 1px solid rgba(138, 108, 177, 0.45);
	border-radius: 5px;
	line-height: 1;
}
.builder-thread-directed-chip-avatar {
	width: 16px; height: 16px; flex: 0 0 16px;
	border-radius: 3px;            /* rounded square — a badge, not a face */
	background: #8a6cb1;
	color: #fff;
	font-family: OpenSans;
	font-size: 8px;
	font-weight: 600;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
}
.builder-thread-directed-chip-name {
	font-family: OpenSans;
	font-size: 11px;
	font-weight: 600;
	color: #6a4e95;
}
body.appbuilder-dark .builder-thread-directed-chip {
	background: rgba(138, 108, 177, 0.22);
	border-color: rgba(138, 108, 177, 0.5);
}
body.appbuilder-dark .builder-thread-directed-chip-avatar { background: #5b4a85; }
body.appbuilder-dark .builder-thread-directed-chip-name   { color: #c3aee0; }

/* Tempo agent cards (ACTIVITY_LIST / ACTIVITY_CARD / SLOTS).
   Same visual family as the dashboard card — rounded panel, brand-blue
   accent on the title icon, dimmed meta line. Renders identically in
   live and replay paths. */
.builder-thread-tempo-card {
	border: 1px solid #e2e2e2;
	border-radius: 8px;
	padding: 10px 12px;
	background-color: #fafafa;
	margin: 4px 0;
}
.builder-thread-tempo-card-title {
	font-weight: 600;
	font-size: 13px;
	margin-bottom: 4px;
	display: flex;
	align-items: center;
	gap: 6px;
}
.builder-thread-tempo-card-title .fa { color: #1F84C6; }
.builder-thread-tempo-card-meta {
	font-size: 12px;
	color: #888;
	margin-top: 2px;
	display: flex;
	align-items: center;
	gap: 4px;
}
.builder-thread-tempo-card-desc {
	font-size: 12px;
	color: #555;
	margin-top: 6px;
	line-height: 1.4;
}
.builder-thread-tempo-empty {
	font-size: 12px;
	color: #888;
	margin-top: 4px;
	font-style: italic;
}
.builder-thread-tempo-list {
	list-style: none;
	margin: 6px 0 0 0;
	padding: 0;
}
.builder-thread-tempo-list li {
	display: flex;
	gap: 8px;
	font-size: 12px;
	padding: 4px 0;
	border-top: 1px solid #f0eee9;
	align-items: baseline;
}
.builder-thread-tempo-list li:first-child { border-top: 0; }
.builder-thread-tempo-list li strong { font-weight: 600; flex: 1; }
.builder-thread-tempo-list li span   { color: #888; font-size: 11px; }
.builder-thread-tempo-list li.tempo-more { color: #888; font-style: italic; }
.builder-thread-tempo-list li.tempo-list-done strong { text-decoration: line-through; color: #888; }
.builder-thread-tempo-list li.tempo-list-done .fa { color: #4a90e2; }
.builder-thread-tempo-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 6px;
}
.builder-thread-tempo-pill {
	display: inline-block;
	padding: 4px 10px;
	border-radius: 14px;
	font-size: 12px;
	background-color: #e6f0fb;
	color: #1F84C6;
	cursor: pointer;
	border: 1px solid transparent;
	transition: background-color 0.15s ease;
}
.builder-thread-tempo-pill:hover {
	background-color: #d4e7f7;
	border-color: #1F84C6;
}
body.appbuilder-dark .builder-thread-tempo-card {
	background-color: #232323;
	border-color: #3a3a3a;
}
body.appbuilder-dark .builder-thread-tempo-card-title { color: #e6e6e6; }
body.appbuilder-dark .builder-thread-tempo-card-meta,
body.appbuilder-dark .builder-thread-tempo-empty,
body.appbuilder-dark .builder-thread-tempo-list li span,
body.appbuilder-dark .builder-thread-tempo-list li.tempo-more { color: #aaa; }
body.appbuilder-dark .builder-thread-tempo-card-desc { color: #ccc; }
body.appbuilder-dark .builder-thread-tempo-list li { border-top-color: #3a3a3a; }
body.appbuilder-dark .builder-thread-tempo-pill {
	background-color: rgba(74, 144, 226, 0.18);
	color: #6cb1f5;
}
body.appbuilder-dark .builder-thread-tempo-pill:hover {
	background-color: rgba(74, 144, 226, 0.28);
	border-color: #4a90e2;
}

/* Dashboard chat — journal entries (synthetic notes for manual edits).
   Distinct from real chat: smaller, italic, dimmed, with a pencil-square
   icon. They sit centered in the column so they read as a timeline marker
   between user / assistant bubbles, not as a participant in the
   conversation. Both light and dark variants. */
.builder-thread-body-journal {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	font-family: OpenSans;
	font-size: 12px;
	font-style: italic;
	line-height: 18px;
	color: #888;
	margin: 8px 24px;
	padding: 4px 8px;
	border-left: 2px solid #d6d3cd;
	background-color: rgba(0, 0, 0, 0.02);
	border-radius: 0 4px 4px 0;
}
.builder-thread-body-journal .fa { color: #b0a99a; margin-top: 2px; }
.builder-thread-body-journal-text { flex: 1; word-break: break-word; }
body.appbuilder-dark .builder-thread-body-journal {
	color: #9a9a9a;
	border-left-color: #3a3a3a;
	background-color: rgba(255, 255, 255, 0.03);
}
body.appbuilder-dark .builder-thread-body-journal .fa { color: #6e6e6e; }

/* Live-chat journal toggle (mirrors the History tab "▸ Details" affordance).
   The dashboard journal layout is `display: flex; align-items: flex-start`
   with `<i>` + `<span>` direct children — icon-next-to-text. The workflow
   variant ships a row sub-wrapper plus an optional details <pre>, so we
   flip the bubble to column layout WHEN the `.wf-journal` opt-in marker
   is present. Without the marker, dashboards stay exactly as before. */
.builder-thread-body-journal.wf-journal {
	display: block !important;
}
.builder-thread-body-journal.wf-journal .builder-thread-body-journal-row {
	display: flex;
	align-items: flex-start;
	gap: 8px;
}
.builder-thread-body-journal-row {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	width: 100%;
}
.builder-thread-body-journal-row .builder-thread-body-journal-text { flex: 1 1 auto; }
.builder-thread-body-journal-toggle {
	flex: 0 0 auto;
	font-size: 11px;
	color: #888;
	cursor: pointer;
	user-select: none;
	padding: 2px 6px;
	border-radius: 3px;
	outline: none;
	font-style: normal;
}
.builder-thread-body-journal-toggle:hover { background: rgba(0, 0, 0, 0.04); color: #333; }
.builder-thread-body-journal-toggle:focus { background: rgba(0, 0, 0, 0.06); }
.builder-thread-body-journal-toggle .fa { font-size: 10px; margin-right: 4px; color: inherit; }
.builder-thread-body-journal-details {
	margin: 4px 24px 6px 38px;
	padding: 8px 10px;
	background: rgba(0, 0, 0, 0.03);
	border-left: 2px solid #d0d0d0;
	border-radius: 0 3px 3px 0;
	font-family: Consolas, "Courier New", monospace;
	font-size: 11px;
	color: #444;
	white-space: pre-wrap;
	word-break: break-word;
	font-style: normal;
	max-height: 280px;
	overflow: auto;
}
body.appbuilder-dark .builder-thread-body-journal-toggle { color: #999; }
body.appbuilder-dark .builder-thread-body-journal-toggle:hover { background: rgba(255, 255, 255, 0.06); color: #e0e0e0; }
body.appbuilder-dark .builder-thread-body-journal-toggle:focus { background: rgba(255, 255, 255, 0.10); }
body.appbuilder-dark .builder-thread-body-journal-details {
	background: rgba(255, 255, 255, 0.04);
	border-left-color: #3a3a3a;
	color: #c8c8c8;
}

/* Warning row — same compact layout as a journal entry but tinted
   amber. Used for per-op apply failures from Orchestro design mode
   so they don't masquerade as successful actions. */
.builder-thread-body-warning {
	color: #8a6d3b;
	border-left-color: #f0c674;
	background-color: rgba(240, 198, 116, 0.10);
}
.builder-thread-body-warning .fa { color: #d4a050; }
body.appbuilder-dark .builder-thread-body-warning {
	color: #f0c674;
	border-left-color: #8a6d3b;
	background-color: rgba(240, 198, 116, 0.08);
}
body.appbuilder-dark .builder-thread-body-warning .fa { color: #f0c674; }

.builder-new-thread-container {
  position: absolute;
  top: 40%;
  left: 50%;
  width:60%;
  max-width: 650px;
  min-width: 400px;
  transform: translate(-50%, -50%);
}

/* "Workflows" button — top-right corner of the threads main
   panel (sibling of the centered prompt container). Click →
   swaps the main panel to a gallery of published workflows. */
.builder-newthread-workflow-btn-wrap {
	position: absolute;
	top: 16px;
	right: 16px;
	z-index: 10;
}
.builder-newthread-workflow-btn {
	border: 1px solid #d9d6d0;
	background-color: #ffffff;
	color: #555;
	padding: 6px 14px;
	border-radius: 6px;
	font: 12px OpenSans, sans-serif;
	cursor: pointer;
	transition: border-color 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}
.builder-newthread-workflow-btn:hover {
	border-color: #4a90e2;
	color: #4a90e2;
	background-color: rgba(74, 144, 226, 0.06);
}
body.appbuilder-dark .builder-newthread-workflow-btn {
	background-color: var(--bg-strong, #242424);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg, #c8c8c8);
}

/* Engine-emitted WORKFLOW chat entries — sober gray rectangle
   with white icon disc, mirroring the existing FORM banner
   pattern (no loud violet/green tints). Screen variants get the
   `wf_screen` attribute and a clickable hover. */
.builder-thread-body-answer .wf-msg {
	position: relative;
	width: 240px;
	min-height: 50px;
	border-radius: 8px;
	background-color: #F2F0EC;
	margin-top: 8px;
	color: #27251EA6;
	cursor: default;
}
.builder-thread-body-answer .wf-msg[wf_screen] { cursor: pointer; }
.builder-thread-body-answer .wf-msg[wf_screen]:hover {
	background-color: #ECE9E2;
}
.builder-thread-body-answer .wf-msg [icon] {
	position: absolute;
	border-radius: 4px;
	background-color: #ffffff;
	left: 8px;
	top: 8px;
	width: 32px;
	height: calc(100% - 16px);
	display: flex;
	justify-content: center;
	align-items: center;
	color: #555;
}
.builder-thread-body-answer .wf-msg [description] {
	margin-left: 40px;
	padding: 8px;
	font-size: 12px;
	line-height: 16px;
	color: #27251E;
}
.builder-thread-body-answer .wf-msg [description] > span {
	color: #888;
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.4px;
	font-weight: 700;
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg {
	background-color: var(--bg-alt, #242424);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg[wf_screen]:hover {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg [icon] {
	background-color: var(--bg, #1a1a1a);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg [description] {
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg [description] > span {
	color: var(--fg-muted, #a0a0a0);
}
/* Right chevron on Screen cards (they open a side-view form) — matches
   the table card's open affordance. */
.builder-thread-body-answer .wf-msg[wf_screen] [description] { padding-right: 24px; }
.builder-thread-body-answer .wf-msg-open {
	position: absolute;
	right: 10px;
	top: 50%;
	transform: translateY(-50%);
	color: rgb(160,160,170);
	font-size: 12px;
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg-open { color: var(--fg-muted, #a0a0a0); }

/* Workflow-completion expandable summary. Sits directly below
   the wf-msg card, picks up the same width so it reads as one
   block. The chevron toggle is inline with the "Show details"
   label; the body is whitespace-preserved (the server emits a
   bullet list with newlines). */
.builder-thread-body-answer .wf-msg-summary {
	/* Stretch to the conversation column width (the answer
	   bubble's box) instead of inheriting the 240px card width.
	   The summary body wraps inside, so a long captured-data
	   JSON stays contained instead of bleeding into the layout. */
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	margin-top: 6px;
	font-family: OpenSans;
	font-size: 12px;
	color: rgb(115, 116, 133);
}
.builder-thread-body-answer .wf-msg-summary-toggle {
	cursor: pointer;
	user-select: none;
	padding: 4px 6px;
	border-radius: 6px;
}
.builder-thread-body-answer .wf-msg-summary-toggle:hover {
	background-color: #F1F1F1;
}
.builder-thread-body-answer .wf-msg-summary-toggle i.fa {
	width: 12px;
	margin-right: 4px;
}
.builder-thread-body-answer .wf-msg-summary-body {
	padding: 6px 8px;
	white-space: pre-wrap;
	/* Long unbroken tokens (JSON values, URLs) must wrap
	   inside the box, not push the column wider. */
	word-break: break-word;
	overflow-wrap: anywhere;
	max-width: 100%;
	box-sizing: border-box;
	background-color: #F1F1F1;
	border-radius: 6px;
	margin-top: 4px;
	color: #27251E;
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg-summary {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg-summary-toggle:hover {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .builder-thread-body-answer .wf-msg-summary-body {
	background-color: var(--bg-elev, #242424);
	color: var(--fg, #c8c8c8);
}

/* ==============================================================
 * Inline confirmation card — used by the CONFIRM message type.
 * Same conversation-column width as a regular answer bubble, soft
 * elevated panel, icon + prompt + optional detail + action buttons.
 * After resolution the buttons are replaced by a "✓ Selected: …"
 * badge so the audit trail is preserved in the conversation.
 * ============================================================== */
.builder-thread-body-answer .confirm-msg {
	display: flex;
	gap: 12px;
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	padding: 12px 14px;
	margin-top: 8px;
	background-color: #F2F0EC;
	border: 1px solid #E6E3DC;
	border-radius: 10px;
	font-family: OpenSans;
	color: #27251E;
}
.builder-thread-body-answer .confirm-msg-icon {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	background-color: rgb(38, 157, 240);
	color: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 18px;
	line-height: 1;
}
.builder-thread-body-answer .confirm-msg-body {
	flex: 1 1 auto;
	min-width: 0;
}
.builder-thread-body-answer .confirm-msg-prompt {
	font-size: 14px;
	font-weight: 600;
	line-height: 20px;
}
.builder-thread-body-answer .confirm-msg-detail {
	margin-top: 4px;
	font-size: 12px;
	color: rgb(115, 116, 133);
	line-height: 18px;
}
.builder-thread-body-answer .confirm-msg-actions {
	margin-top: 12px;
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
}
/* Inline input widgets (template selector etc.) — sit between the
   details panel and the action buttons; stack vertically so each
   widget gets its label above its control. */
.builder-thread-body-answer .confirm-msg-inputs {
	margin-top: 10px;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.builder-thread-body-answer .confirm-msg-input {
	display: flex;
	flex-direction: column;
	gap: 4px;
}
.builder-thread-body-answer .confirm-msg-input-label {
	font-family: OpenSans;
	font-size: 12px;
	font-weight: 600;
	color: rgb(80, 81, 96);
}
.builder-thread-body-answer .confirm-msg-input-select {
	font-family: OpenSans;
	font-size: 13px;
	padding: 6px 8px;
	border-radius: 6px;
	border: 1px solid rgba(0, 0, 0, 0.15);
	background: #fff;
	color: #222;
	max-width: 320px;
}
.builder-thread-body-answer .confirm-msg-input-resolved {
	font-family: OpenSans;
	font-size: 12px;
	color: rgb(80, 81, 96);
}
.builder-thread-body-answer .confirm-msg-input-resolved .confirm-msg-input-value {
	font-weight: 600;
	color: #222;
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-input-label,
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-input-resolved {
	color: rgb(200, 202, 215);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-input-select {
	background: #2b2b30;
	color: #e8e8ea;
	border-color: rgba(255, 255, 255, 0.15);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-input-resolved .confirm-msg-input-value {
	color: #f1f1f4;
}

/* -----------------------------------------------------------------
   Phase 3 — per-LLM-request progress bubbles. Compact card with a
   status icon on the left (spinner while pending, check on success,
   red exclamation on error) and a "Show details" toggle revealing
   the question + result. Always visible — independent of /trace:on.
   ----------------------------------------------------------------- */
.builder-thread-body-answer .skill-progress {
	display: flex;
	gap: 10px;
	align-items: flex-start;
	padding: 8px 12px;
	border-radius: 10px;
	background: rgba(74, 144, 226, 0.06);
	border: 1px solid rgba(74, 144, 226, 0.15);
	font-family: OpenSans;
}
.builder-thread-body-answer .skill-progress-icon {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	margin-top: 2px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 16px;
}
.builder-thread-body-answer .skill-progress-pending .skill-progress-icon { color: #4a90e2; }
.builder-thread-body-answer .skill-progress-ok      .skill-progress-icon { color: #2c8c4a; }
.builder-thread-body-answer .skill-progress-error   .skill-progress-icon { color: #c0392b; }
.builder-thread-body-answer .skill-progress-body {
	flex: 1 1 auto;
	min-width: 0;
}
.builder-thread-body-answer .skill-progress-title {
	font-size: 13px;
	font-weight: 600;
	color: rgb(40, 41, 56);
}
.builder-thread-body-answer .skill-progress-snippet {
	margin-top: 2px;
	font-size: 12px;
	color: rgb(110, 112, 130);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-thread-body-answer .skill-progress-error-msg {
	margin-top: 2px;
	font-size: 12px;
	color: #c0392b;
}
.builder-thread-body-answer .skill-progress-toggle {
	margin-top: 6px;
	font-size: 12px;
	color: #4a90e2;
	cursor: pointer;
	user-select: none;
	display: inline-flex;
	align-items: center;
	gap: 4px;
}
.builder-thread-body-answer .skill-progress-toggle:hover { color: #2c6cb0; }
.builder-thread-body-answer .skill-progress-details {
	margin-top: 6px;
	border-top: 1px solid rgba(74, 144, 226, 0.18);
	padding-top: 6px;
}
.builder-thread-body-answer .skill-progress-section-label {
	font-size: 11px;
	font-weight: 600;
	color: rgb(110, 112, 130);
	text-transform: uppercase;
	letter-spacing: 0.3px;
	margin-top: 6px;
}
.builder-thread-body-answer .skill-progress-agent {
	font-family: OpenSans;
	font-size: 13px;
	font-weight: 600;
	color: rgb(40, 41, 56);
	margin: 4px 0 2px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.builder-thread-body-answer .skill-progress-agent::before {
	content: "";
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: #4a90e2;
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-agent {
	color: rgb(225, 227, 235);
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-agent::before {
	background: #7AB1F0;
}
.builder-thread-body-answer .skill-progress-prov {
	margin-top: 4px;
	border: 1px solid rgba(0, 0, 0, 0.07);
	border-radius: 6px;
	overflow: hidden;
	background: #fff;
}
.builder-thread-body-answer .skill-progress-prov-row {
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 5px 10px;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 11px;
	line-height: 1.45;
	border-top: 1px solid rgba(0, 0, 0, 0.05);
}
.builder-thread-body-answer .skill-progress-prov-row:first-child { border-top: 0; }
.builder-thread-body-answer .skill-progress-prov-path {
	flex: 0 1 auto;
	min-width: 0;
	color: rgb(40, 41, 56);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.builder-thread-body-answer .skill-progress-prov-arrow {
	flex: 0 0 auto;
	color: rgb(110, 112, 130);
}
.builder-thread-body-answer .skill-progress-prov-src {
	flex: 1 1 auto;
	min-width: 0;
	font-family: OpenSans;
	font-size: 11px;
	color: #4a90e2;
	font-weight: 600;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.builder-thread-body-answer .skill-progress-prov-count {
	color: rgb(110, 112, 130);
	font-weight: normal;
	font-size: 10px;
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov {
	background: rgba(255, 255, 255, 0.04);
	border-color: rgba(255, 255, 255, 0.08);
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov-row {
	border-top-color: rgba(255, 255, 255, 0.06);
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov-path { color: rgb(225, 227, 235); }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov-arrow,
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov-count { color: rgb(165, 168, 185); }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-prov-src { color: #7AB1F0; }
.builder-thread-body-answer .skill-progress-pre {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 11px;
	line-height: 1.45;
	background: rgba(0, 0, 0, 0.04);
	border-radius: 6px;
	padding: 8px 10px;
	margin: 4px 0 0;
	max-height: 280px;
	overflow: auto;
	white-space: pre-wrap;
	word-break: break-word;
	color: rgb(40, 41, 56);
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress {
	background: rgba(122, 177, 240, 0.07);
	border-color: rgba(122, 177, 240, 0.20);
}
body.appbuilder-dark .builder-thread-body-answer .skill-progress-title { color: rgb(225, 227, 235); }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-snippet,
body.appbuilder-dark .builder-thread-body-answer .skill-progress-section-label { color: rgb(165, 168, 185); }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-pending .skill-progress-icon { color: #7AB1F0; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-ok      .skill-progress-icon { color: #58c884; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-error   .skill-progress-icon { color: #ef6e5e; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-error-msg { color: #ef6e5e; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-toggle { color: #7AB1F0; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-toggle:hover { color: #a8caf6; }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-details { border-color: rgba(122, 177, 240, 0.22); }
body.appbuilder-dark .builder-thread-body-answer .skill-progress-pre {
	background: rgba(255, 255, 255, 0.05);
	color: rgb(225, 227, 235);
}
.builder-thread-body-answer .confirm-msg-btn {
	font-family: OpenSans;
	font-size: 13px;
	line-height: 1;
	padding: 8px 14px;
	border-radius: 6px;
	border: 1px solid transparent;
	cursor: pointer;
	transition: background-color 0.12s ease, border-color 0.12s ease;
}
.builder-thread-body-answer .confirm-msg-btn[disabled] {
	cursor: default;
	opacity: 0.55;
}
.builder-thread-body-answer .confirm-msg-btn-pending {
	opacity: 0.85;
}
.builder-thread-body-answer .confirm-msg-btn-primary {
	background-color: #269DF0;
	color: #ffffff;
}
.builder-thread-body-answer .confirm-msg-btn-primary:hover:not([disabled]) {
	background-color: #1F84C6;
}
.builder-thread-body-answer .confirm-msg-btn-secondary {
	background-color: #ffffff;
	color: #27251E;
	border-color: #C0C0C0;
}
.builder-thread-body-answer .confirm-msg-btn-secondary:hover:not([disabled]) {
	background-color: #F1F1F1;
}
.builder-thread-body-answer .confirm-msg-btn-ghost {
	background-color: transparent;
	color: rgb(115, 116, 133);
}
.builder-thread-body-answer .confirm-msg-btn-ghost:hover:not([disabled]) {
	background-color: #F1F1F1;
	color: #27251E;
}
.builder-thread-body-answer .confirm-msg-resolved {
	margin-top: 12px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 10px;
	font-size: 13px;
	background-color: rgba(38, 157, 240, 0.12);
	color: #1F84C6;
	border-radius: 6px;
}
.builder-thread-body-answer .confirm-msg-resolved i.fa {
	font-size: 12px;
}

/* Dark-mode confirmation card */
body.appbuilder-dark .builder-thread-body-answer .confirm-msg {
	background-color: var(--bg-elev, #242424);
	border-color: var(--border, #333);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-icon {
	background-color: rgb(96, 165, 250);
	color: #ffffff;
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-detail {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-btn-secondary {
	background-color: transparent;
	color: var(--fg, #c8c8c8);
	border-color: var(--border, #333);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-btn-secondary:hover:not([disabled]) {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-btn-ghost {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-btn-ghost:hover:not([disabled]) {
	background-color: var(--bg-hover, #2a2a2a);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-resolved {
	background-color: rgba(96, 165, 250, 0.18);
	color: rgb(96, 165, 250);
}

/* Confirmation card "> Show details" panel — reuses the
   wf-msg-summary-toggle chevron styles already wired in the
   click delegation. The body holds a key/value table of
   parameters Maestro extracted, plus a "Still needed" footer
   listing required-but-missing fields. */
.builder-thread-body-answer .confirm-msg-details {
	margin-top: 8px;
	font-family: OpenSans;
	font-size: 12px;
	color: rgb(115, 116, 133);
}
.builder-thread-body-answer .confirm-msg-details-body {
	padding: 6px 8px;
	background-color: #F1F1F1;
	border-radius: 6px;
	margin-top: 4px;
	color: #27251E;
	max-width: 100%;
	box-sizing: border-box;
	overflow-wrap: anywhere;
}
.builder-thread-body-answer .confirm-msg-kv {
	width: 100%;
	border-collapse: collapse;
	font-size: 13px;
}
.builder-thread-body-answer .confirm-msg-kv td {
	padding: 4px 8px;
	vertical-align: top;
	border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}
.builder-thread-body-answer .confirm-msg-kv tr:last-child td { border-bottom: 0; }
.builder-thread-body-answer .confirm-msg-kv-key {
	font-weight: 600;
	color: rgb(115, 116, 133);
	white-space: nowrap;
	width: 1px;     /* shrink-to-fit; long values get the rest */
}
.builder-thread-body-answer .confirm-msg-kv-val {
	color: #27251E;
	word-break: break-word;
}
.builder-thread-body-answer .confirm-msg-missing {
	margin-top: 6px;
	padding-top: 6px;
	border-top: 1px solid rgba(0, 0, 0, 0.06);
	font-size: 12px;
	color: #C0392B;
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-details {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-details-body {
	background-color: var(--bg-elev, #242424);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-kv td {
	border-bottom-color: rgba(255, 255, 255, 0.06);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-kv-key {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-kv-val {
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .builder-thread-body-answer .confirm-msg-missing {
	color: #ff8a7e;
	border-top-color: rgba(255, 255, 255, 0.08);
}

/* ==============================================================
 * Inline error card — used by the ERROR message type. Same shape
 * as the confirm card (icon + body) but red-tinted with a
 * pronounced border so it reads unmistakably as a failure.
 * ============================================================== */
.builder-thread-body-answer .error-msg {
	display: flex;
	gap: 12px;
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	padding: 12px 14px;
	margin-top: 8px;
	background-color: rgba(192, 57, 43, 0.10);
	border: 1px solid rgba(192, 57, 43, 0.45);
	border-radius: 10px;
	font-family: OpenSans;
	color: #5a1a14;
}
.builder-thread-body-answer .error-msg-icon {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	background-color: #C0392B;
	color: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 16px;
	line-height: 1;
}
.builder-thread-body-answer .error-msg-body {
	flex: 1 1 auto;
	min-width: 0;
}
.builder-thread-body-answer .error-msg-title {
	font-size: 13px;
	font-weight: 700;
	color: #C0392B;
	letter-spacing: 0.2px;
}
.builder-thread-body-answer .error-msg-message {
	margin-top: 2px;
	font-size: 14px;
	line-height: 20px;
	color: #5a1a14;
	word-break: break-word;
	overflow-wrap: anywhere;
}
.builder-thread-body-answer .error-msg-detail {
	margin-top: 8px;
	padding: 6px 8px;
	font-size: 12px;
	background-color: rgba(192, 57, 43, 0.08);
	border-radius: 6px;
	color: #5a1a14;
	white-space: pre-wrap;
	word-break: break-word;
	overflow-wrap: anywhere;
}

/* Dark-mode error card — keep the red as the signal but soften
   the surface and lift the text so it's readable on the dark
   conversation background. */
body.appbuilder-dark .builder-thread-body-answer .error-msg {
	background-color: rgba(231, 76, 60, 0.14);
	border-color: rgba(231, 76, 60, 0.55);
	color: #f8d7d2;
}
body.appbuilder-dark .builder-thread-body-answer .error-msg-icon {
	background-color: #E74C3C;
	color: #ffffff;
}
body.appbuilder-dark .builder-thread-body-answer .error-msg-title {
	color: #ff8a7e;
}
body.appbuilder-dark .builder-thread-body-answer .error-msg-message {
	color: #f8d7d2;
}
body.appbuilder-dark .builder-thread-body-answer .error-msg-detail {
	background-color: rgba(231, 76, 60, 0.10);
	color: #f8d7d2;
}

/* The right-panel screen form is rendered inside a bg-page /
   bg-block shell hosting a w2form. We rely on w2form's native
   field rendering + dark-mode support — the only extra rule we
   need is making the form host transparent so the bg-block tone
   shows through. */
.wf-screen-form-host .w2ui-form,
.wf-screen-form-host .w2ui-form .w2ui-page {
	background-color: transparent !important;
}

/* The picker's inner .wf_subblock has a 12 px top margin (set
   for its standalone use in the field-edit dialog). When it's
   nested inside the variable / property edit forms, that
   margin pushes the form's total content past the page's
   allocated height by a few pixels and triggers w2form's
   auto-scroll. Zero it out here so the picker hugs the row
   tightly and the form fits. */
#WfVarEditExtras .wf_subblock,
#WfTypePropExtras .wf_subblock {
	margin-top: 0 !important;
}

/* Banner shown above the form when revisiting a screen that
   has already been submitted. Tone matches the user-prompt
   bubble: a darker gray over the bg-block in light mode, a
   blue-with-alpha tint in dark mode. */
.wf-screen-submitted-banner {
	margin-bottom: 8px;
	padding: 8px 12px;
	background-color: #E2DED5;
	border-radius: 8px;
	color: #27251E;
	font: 12px OpenSans, sans-serif;
}
.wf-screen-submitted-banner .fa { margin-right: 6px; }
.wf-screen-submitted-banner b   { color: #27251E; }
.wf-screen-submitted-banner-meta {
	margin-top: 4px;
	font-size: 11px;
	color: #6a6660;
}
.wf-screen-submitted-banner-meta .fa {
	margin-right: 4px;
	font-size: 10px;
}

body.appbuilder-dark .wf-screen-submitted-banner {
	background-color: rgba(38, 157, 240, 0.12);
	border: 1px solid rgba(38, 157, 240, 0.25);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .wf-screen-submitted-banner b    { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .wf-screen-submitted-banner-meta { color: var(--fg-muted, #a0a0a0); }

/* Quick-launch tag row below the textarea. Blue rounded pills,
   one per published workflow. */
.builder-newthread-workflow-tags {
	margin-top: 12px;
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}
.builder-newthread-workflow-tag {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 5px 12px;
	background-color: rgba(74, 144, 226, 0.1);
	color: #4a90e2;
	border: 1px solid rgba(74, 144, 226, 0.3);
	border-radius: 999px;
	font: 600 12px OpenSans, sans-serif;
	cursor: pointer;
	transition: background-color 0.12s ease, border-color 0.12s ease;
}
.builder-newthread-workflow-tag:hover {
	background-color: #4a90e2;
	color: #ffffff;
	border-color: #4a90e2;
}
.builder-newthread-workflow-tag .fa { font-size: 11px; }
body.appbuilder-dark .builder-newthread-workflow-tag {
	background-color: rgba(74, 144, 226, 0.18);
	border-color: rgba(74, 144, 226, 0.45);
}

/* Published-workflows gallery panel (rendered into the threads
   layout's main panel when the user clicks the "Workflows"
   button). Card grid + Run button per card. */
.builder-published-panel {
	width: 100%;
	height: 100%;
	overflow-y: auto;
	padding: 24px 28px;
	box-sizing: border-box;
	font-family: OpenSans, sans-serif;
}
.builder-published-header {
	margin-bottom: 20px;
}
.builder-published-header-title {
	font-size: 18px;
	font-weight: 700;
	color: #27251e;
}
.builder-published-header-title .fa {
	color: #4a90e2;
	margin-right: 8px;
}
.builder-published-header-sub {
	margin-top: 4px;
	font-size: 12px;
	color: #888;
}
/* Match the .applications_element layout used by Admin/Workflows
   so the two card surfaces feel identical: 300×158, light gray
   border, neutral hover background. The Run button is anchored
   in the top-right corner so it sits on the title line, not
   centered vertically. */
.builder-published-grid {
	display: flex;
	flex-wrap: wrap;
}
.builder-published-card {
	width: 300px;
	height: 158px;
	border: 1px solid #EEECEA;
	background-color: #ffffff;
	border-radius: 12px;
	margin-right: 12px;
	margin-bottom: 12px;
	padding: 6px;
	position: relative;
	display: inline-block;
	cursor: pointer;
	transition: background-color 0.15s ease-out;
}
.builder-published-card:hover { background-color: #f4f4f4; }
.builder-published-card-icon {
	position: absolute;
	left: 10px;
	top: 10px;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: linear-gradient(135deg, #4a90e2, #7AB6F5);
	color: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 20px;
}
.builder-published-card-text {
	position: absolute;
	left: 56px;
	top: 10px;
	right: 10px;
	height: 148px;
	color: #808080;
	user-select: none;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	overflow: hidden;
	box-sizing: border-box;
}
/* Title only — reserves room on the right for the absolutely
   positioned Run button. Description and meta lines below use
   the full available width. */
.builder-published-card-text > span {
	display: block;
	padding-right: 70px;
	font-weight: bold;
	user-select: none;
	line-height: 20px;
	color: #27251e;
}
.builder-published-card-desc {
	margin: 4px 0 0 0;
	color: #777;
	overflow: hidden;
	text-overflow: ellipsis;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
}
.builder-published-card-meta {
	margin: 6px 0 0 0;
	font-size: 11px;
	color: #999;
}
.builder-published-card-meta .fa {
	margin-right: 3px;
	font-size: 10px;
}
/* Run button — anchored top-right of the card, on the same
   line as the workflow name. Matches the height + pill style
   of the .workflow_published_tag in Admin/Workflows so the
   two buttons feel consistent. */
.builder-published-card-run {
	position: absolute;
	top: 14px;
	right: 12px;
	padding: 3px 10px;
	background-color: #3FAE5A;
	color: #ffffff;
	border: none;
	border-radius: 10px;
	font: 600 10px OpenSans, sans-serif;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	transition: background-color 0.12s ease;
}
.builder-published-card-run:hover { background-color: #34964c; }
.builder-published-card-run .fa { font-size: 11px; }

.builder-published-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	height: 100%;
	min-height: 240px;
	padding: 40px 24px;
	box-sizing: border-box;
	text-align: center;
	color: #888;
	font-family: OpenSans, sans-serif;
}
.builder-published-empty-icon {
	font-size: 48px;
	opacity: 0.4;
	margin-bottom: 16px;
}
.builder-published-empty-text {
	font-size: 14px;
	color: #555;
}
.builder-published-empty-sub {
	margin-top: 6px;
	font-size: 12px;
	color: #999;
	max-width: 360px;
}

body.appbuilder-dark .builder-published-card {
	background-color: var(--bg-strong, #242424);
	border-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .builder-published-card:hover {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .builder-published-card-text > span { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .builder-published-card-desc { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .builder-published-card-meta { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .builder-published-header-title { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .builder-published-empty-text { color: var(--fg-strong, #e6e6e6); }

.builder-new-thread-logo-container {
	width: 100%;
	height: 140px;
	position: relative;
}

.builder-new-thread-logo {
	top: 50%;
	left: 50%;
	width: 120px;
	height: 120px;
	transform: translate(-50%, -50%);
	position: absolute;
	border: 0px;
	padding:2px;
	cursor:pointer;
}

.builder-new-thread-logo:hover {
	border: 2px dotted #C0C0C0;
	padding:0px;
}


.builder-new-thread-logo img {
	object-fit: contain;
	width: 100%;
	height:100%;
}

.builder-new-thread-label {
	width: 100%;
	text-align:center;
	padding:16px;
	font-family: OpenSans;
	font-size: 28px;
}

.builder-new-thread-prompt {
	position:relative;
	width: calc(100% - 32px);
	/* height: 80px; */
	background-color: white; /*#FAFAFA;*/
	border:1px solid #C0C0C0;
	border-radius: 16px;
	padding-left: 16px;
	padding-right: 16px;
	padding-top: 16px;
	padding-bottom: 40px;
	/* box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3); */
}

.builder-new-thread-prompt textarea {
	box-sizing: border-box;
	width: 100%;
	min-height: 60px;
	max-height: 350px;      /* max height */
	overflow-y: auto;       /* scrollbar after max height */
	resize: none;       
	border: 0px;
	background: transparent;
	font-family: OpenSans;
	font-size: 14px;
	outline: 0 !important;
}


.builder-thread-scrollto {
	position: absolute;
	left:50%;
	transform: translate(-50%,0%);
	z-index: 10000;
	width: 20px;
	height: 20px;
	padding: 8px;
	border-radius: 50%;
	background-color: #FAF8F5;
	border: 1px solid #C0C0C0;
	cursor: pointer;
	color: rgb(115, 116, 133);
	text-align: center;
}


.builder-thread-scrollto:hover {
	background-color: #F1F1F1;
}

.builder-thread-scrollto il {
	font-size: 20px;
}

body.appbuilder-dark .builder-thread-scrollto {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg-muted) !important;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4) !important;
}
body.appbuilder-dark .builder-thread-scrollto:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}



.builder-chatbot-moreinfo-agent {
	height:54px;
	position:relative;
}


.builder-chatbot-moreinfo-agent div[icon] {
	position: absolute;
	top:0px;
	left: 0px;
	width: 40px;
	height: 40px;
	/* Round the avatar — applies to both agent cards (the
	   agent's image may itself be square) and the user cards
	   (default initials avatar is a square base64 PNG). The
	   img inside is also rounded via inheritance so it clips
	   cleanly to the circle. */
	border-radius: 50%;
	overflow: hidden;
}
.builder-chatbot-moreinfo-agent div[icon] > img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.builder-chatbot-moreinfo-agent div[props] {
	position: absolute;
	top:4px;
	left: 46px;
	width: 100px;
	font-family: OpenSans;
	vertical-align: middle;
}

.builder-chatbot-moreinfo-agent div[name] {
	color: #27251E;
	font-size: 12px;
	width:100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow:hidden;
}

.builder-chatbot-moreinfo-agent div[position] {
	color: rgb(115, 116, 133);
	font-size: 12px;
	width:100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow:hidden;
}




.builder-chatbot-moreinfo-file {
	height:54px;
	position:relative;
}


.builder-chatbot-moreinfo-file div[icon] {
	position: absolute;
	top:0px;
	left: 0px;
	width: 40px;
	height: 40px;
	background-color:#E2E2E2;
	border-radius: 50%;
	text-align: center;
}


.builder-chatbot-moreinfo-file div[icon] >il {
	font-size: 20px;
	color: #27251e;
	padding:8px;
}

.builder-chatbot-moreinfo-file div[props] {
	position: absolute;
	top:4px;
	left: 46px;
	width: 200px;
	font-family: OpenSans;
	vertical-align: middle;
}

.builder-chatbot-moreinfo-file div[name] {
	color: #27251E;
	font-size: 12px;
	width:100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow:hidden;
}

/* Dark-mode override — the default #27251E is near-black and barely
   visible on the dark composer background when a file chip is
   attached to the prompt. Promote to the var-driven light text used
   elsewhere in the dark theme. */
body.appbuilder-dark .builder-chatbot-moreinfo-file div[name] {
	color: var(--w2-fg, #e8e8e8);
}

.builder-chatbot-moreinfo-file div[size] {
	color: rgb(115, 116, 133);
	font-size: 12px;
	width:100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow:hidden;
}

/* The default size grey rgb(115,116,133) reads OK on both backgrounds
   but tighten it slightly in dark mode for parity with the filename
   above. */
body.appbuilder-dark .builder-chatbot-moreinfo-file div[size] {
	color: rgb(160, 162, 178);
}




.builder-chatbot-moreinfo {
	min-height:0px;
	max-height: 300px;
	overflow:hidden;
	overflow-y:auto;
	box-sizing: border-box;
}



.builder-chatbot-moreinfo > div
{
	height:50px;
	display:inline-block;
	margin-right:4px;
	margin-bottom:4px;
	border-radius:8px;
	background-color:#F5F3F1;
	position: relative;
	padding:4px;
	box-sizing: border-box;
	overflow:hidden;
}


.builder-chatbot-moreinfo > div[agent],
.builder-chatbot-moreinfo > div[user],
.builder-chatbot-moreinfo > div[syntheticagent],
.builder-chatbot-moreinfo > div[skillattached],
.builder-chatbot-moreinfo > div[dataroomattached]
{
	width: 180px;
}

.builder-chatbot-moreinfo > div[file]
{
	width: 280px;
}

.builder-chatbot-moreinfo div[close]
{
	position: absolute;
	right: 8px;
	top: 12px;
	width: 24px;
	height:24px;
	color: #27251e;
	font-size: 10px;
	border-radius: 50%;
	cursor: pointer;
	box-sizing: border-box;
	text-align: center;
	padding:4px;
}

.builder-thread-prompt {
	position: absolute;
	bottom:16px;
	left:calc(50% - 4px); /* some space (4px) to align with body taking into account elevator */
	transform: translate(-50%,0%);
	width: 652px; 
	max-width: 90%;
	background-color: white; /*#FAFAFA;*/
	border:1px solid #C0C0C0;
	border-radius: 16px;
	padding-left: 16px;
	padding-right: 16px;
	padding-top: 16px;
	padding-bottom: 40px;
	box-sizing: border-box;
/* box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3); */
}

.builder-thread-prompt textarea {
	box-sizing: border-box;
	width: 100%;
	min-height: 60px;
	max-height: 350px;      /* max height */
	overflow-y: auto;       /* scrollbar after max height */
	resize: none;       
	border: 0px;
	background: transparent;
	font-family: OpenSans;
	font-size: 14px;
	outline: 0 !important;
}




.builder-threads-home,
.builder-dashboards-home {
	padding:2px;
}

.builder-threads-home div,
.builder-dashboards-home div {
	line-height: 24px;
	font-family: OpenSans;
	font-size: 14px;
	color: #27251E;
	padding: 4px;
	margin: 2px;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow : hidden;
	user-select: none;
}


.builder-threads-home div[selected],
.builder-dashboards-home div[selected] {
	background-color: #EAE8E4;
	border-radius:4px;
}

.builder-threads-home div[command]:hover,
.builder-dashboards-home div[command]:hover {
	background-color: #EAE8E4;
	cursor: pointer;
	border-radius:4px;
}

.builder-threads-home-lastthreads,
.builder-dashboards-home-lastdashboards {
	margin-left:10px !important;
	border-left:1px solid #E2E2E2;
	padding:0px !important;
	margin-right:0px !important;
	margin-top:0px !important;
	margin-bottom:0px !important;
}

.builder-threads-home-lastthreads > div,
.builder-dashboards-home-lastdashboards > div {
	font-size:14px;
}


.builder-leftbar-home {
	padding:2px;
}

/* Fixed-width icon slot inside every leftbar row.
   Without this the FA glyphs render at their natural widths (fa-bolt
   narrow, fa-sitemap wide, fa-database medium…) so the `&nbsp;Label`
   text after each one lands at a different x-position and the column
   of labels looks ragged. A 16px centered slot normalises the gutter
   so all labels start at the same offset. Applies to every leftbar
   that uses .builder-leftbar-home (Admin, Directory, Tower Control). */
.builder-leftbar-home div > i.fa {
	display: inline-block;
	width: 16px;
	text-align: center;
}

/* Strip the text-shadow / box-shadow on the shared `data-tooltip`
   overlay only (w2ui's other overlays — dropdowns, menus, errors —
   keep their default styling). Scoped via the `name` attribute
   w2tooltip stamps on the overlay root.
   The `body.appbuilder-dark` variant is needed to outscore w2ui's
   own dark-mode overlay rule at w2ui.css:4737, which sets a
   `0 4px 12px rgba(0,0,0,0.6) !important` shadow with specificity
   (0,3,1) — beating a plain `!important` from a class-only selector. */
.w2ui-overlay[name="data-tooltip-shared"],
.w2ui-overlay[name="data-tooltip-shared"] .w2ui-overlay-body,
body.appbuilder-dark .w2ui-overlay[name="data-tooltip-shared"],
body.appbuilder-dark .w2ui-overlay[name="data-tooltip-shared"] > div,
body.appbuilder-dark .w2ui-overlay[name="data-tooltip-shared"] .w2ui-overlay-body {
	text-shadow: none !important;
	box-shadow: none !important;
}

/* The outer .w2ui-overlay carries its own background in dark mode
   (w2ui.css:4737 sets it on outer + body). The body's own bg covers
   the tooltip surface, but the outer's bg leaks as a dark strip
   under the body. Force ONLY the outer transparent — the body keeps
   its w2ui-defined bg so the tooltip stays themed. (The body IS the
   overlay's first-child div, so we must NOT target `> div` here.) */
.w2ui-overlay[name="data-tooltip-shared"],
body.appbuilder-dark .w2ui-overlay[name="data-tooltip-shared"] {
	background: transparent !important;
}

/* Overdue task row — color set on TD so it beats w2ui's dark-mode TD
   `color: var(--w2-fg) !important` (w2ui.css:4592), which otherwise
   overrides the inline TR style with its higher TD-level specificity.
   Brighter red in dark mode for contrast against the panel background. */
.w2ui-grid .w2ui-grid-records table tr.task-overdue td,
.w2ui-grid .w2ui-grid-frecords table tr.task-overdue td {
	color: rgb(200, 38, 39) !important;
	font-weight: bold !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td {
	color: #d98a8a !important;
}
/* w2ui's dark mode applies `color: var(--w2-fg)` to every descendant
   of `.w2ui-reset` (w2ui.css:4457, `.w2ui-reset *` selector) — that
   direct-on-element rule beats inheritance from our TD `!important`,
   so the actual text inside spans stays grey unless we recolor them
   explicitly. The descendant selector below targets every child node
   inside the overdue row's cells. */
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td *,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td * {
	color: #d98a8a !important;
}
/* Re-pin elements that carry their own (non-text) backgrounds, so
   the `*` selector above doesn't repaint their text to a value that
   matches their bg (e.g. the "X day" overdue badge inside the task
   name cell — red bg, was white text; the `*` rule turned it red-on-red).
   Same trick covers any chip/badge that may appear in these cells. */
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td .plan_task_name > div,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td .plan_task_name > div {
	color: #ffffff !important;
}

/* Status-pill action chips MUST stay white regardless of row state.
   Two distinct overrides cover both failure modes:
   (a) Light mode — the overdue TR sets `color: red !important` on td
       which CASCADES via inheritance to chips that lack an own color
       (.task-chip-close had none). Force white on every chip class.
   (b) Dark mode — the `tr.task-overdue td *` rule above wins on
       specificity over a plain .task-chip-* selector. Use the same
       prefix to lift specificity high enough to win back.
   Both rules also apply to the chips' inner glyphs (::before pseudo
   on close/run/thread, real <i> on pause/resume) so the icon color
   matches the chip color. */
.task-chip-close,
.task-chip-close::before,
.task-chip-run,
.task-chip-thread,
.task-chip-pause,
.task-chip-resume,
.task-chip-pause > i,
.task-chip-resume > i {
	color: #ffffff !important;
}
/* Nuclear override: use the same selector chain length as the
   problematic `*` rule above to GUARANTEE win on specificity. The
   :is() wrapper lets us cover every chip class + glyph in one
   selector, doubled with `body.appbuilder-dark` to also catch the
   dark-mode `*` rule, and again for `.w2ui-grid-frecords` (frozen
   left columns — w2grid splits the table into records / frecords;
   chips in a frozen column live in the second table). */
html body .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread, .task-chip-pause, .task-chip-resume),
html body .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread)::before,
html body .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-pause, .task-chip-resume) > i,
html body .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread, .task-chip-pause, .task-chip-resume),
html body .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread)::before,
html body .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-pause, .task-chip-resume) > i,
html body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread, .task-chip-pause, .task-chip-resume),
html body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread)::before,
html body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.task-overdue td :is(.task-chip-pause, .task-chip-resume) > i,
html body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread, .task-chip-pause, .task-chip-resume),
html body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-close, .task-chip-run, .task-chip-thread)::before,
html body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.task-overdue td :is(.task-chip-pause, .task-chip-resume) > i {
	color: #ffffff !important;
}

/* Task scheduler — × close button inside the status pill. Clones the
   `.w2ui-tab-close` affordance used by closeable tabs (Contacts × in
   the topbar): muted at rest, solid red-on-pink with bold weight on
   hover, deeper red on active. Has a dark-mode variant matching the
   same tab-close rule for visual consistency. */
.task-chip-close {
	display: inline-block;
	width: 18px;
	height: 18px;
	margin-left: 4px;
	padding: 1px 4px;
	border-radius: 3px;
	font-size: 12px;
	line-height: 14px;
	opacity: 0.6;
	cursor: pointer;
	text-align: center;
	user-select: none;
	box-sizing: border-box;
}
.task-chip-close::before {
	content: 'x';
	position: relative;
	display: inline-block;
	line-height: 1;
}
/* Only the at-rest fade is local; the hover tint is the shared close
   pattern at the end of this file. */
.task-chip-close:hover { opacity: 1; }

/* Task scheduler — action icons (Run-now, Open-thread) embedded inside
   the status pill. Same height as the chip text so they don't push the
   pill taller; muted-white at rest, brighter on hover. Click area stays
   tight to avoid hiding the chip background underneath. */
/* Task scheduler — run-now / open-thread chips embedded in the status
   pill. Clones .task-chip-close's box model byte-for-byte (same width,
   height, padding, line-height) so the three affordances line up
   pixel-perfectly. The FontAwesome glyph is injected via ::before on a
   plain <span> (NOT an <i class="fa">) so FA's global
   `font: normal normal normal 14px/1 FontAwesome` shorthand can't
   reset our line-height and shove the glyph to the upper-left. */
.task-chip-run,
.task-chip-thread,
.task-chip-pause,
.task-chip-resume {
	display: inline-block;
	width: 18px;
	height: 18px;
	margin-left: 4px;
	padding: 1px 4px;
	border-radius: 3px;
	font-size: 11px;
	line-height: 14px;
	text-align: center;
	color: #ffffff !important;
	opacity: 0.85;
	cursor: pointer;
	user-select: none;
	box-sizing: border-box;
}
.task-chip-run::before,
.task-chip-thread::before {
	font-family: FontAwesome;
	font-weight: normal;
	font-style: normal;
	font-size: 11px;
	line-height: 1;
	position: relative;
	display: inline-block;
}
.task-chip-run::before    { content: '\f04b'; } /* fa-play */
.task-chip-thread::before { content: '\f0e6'; } /* fa-comments-o is f0e6; fa-comments is f086 */
.task-chip-run:hover,
.task-chip-thread:hover,
.task-chip-pause:hover,
.task-chip-resume:hover {
	background-color: rgba(255, 255, 255, 0.22);
	opacity: 1;
}
.task-chip-run:active,
.task-chip-thread:active,
.task-chip-pause:active,
.task-chip-resume:active {
	background-color: rgba(255, 255, 255, 0.35);
}
/* Pause/Resume use real <i class="fa fa-…"> children (rather than the
   ::before-injected glyph the run/thread chips use), because the
   fa-pause / fa-play unicode codepoints align differently in the
   shared chip box. The wrapping rule below re-anchors them so the
   glyph sits in the centre of the 18×18 button — same visual weight
   as the other chips. */
.task-chip-pause > i,
.task-chip-resume > i {
	font-size: 10px;
	line-height: 1;
	color: #ffffff;
}

/* Task scheduler audit bubbles — compact, full-width, no banner /
   thumbs / copy / download chrome. Distinguished from real speech by
   a muted gray text colour and a faint left border so they read as
   meta-events. The action glyph (created / modified / completed / …)
   is colourised inline by _RenderAuditEnvelope. */
.builder-thread-body-answer.builder-thread-body-audit {
	background: transparent !important;
	box-shadow: none !important;
	padding: 4px 8px !important;
	margin: 4px 0 !important;
	max-width: none !important;
	border-left: 3px solid #e2e2e2;
	border-radius: 2px;
}
.builder-thread-body-audit .builder-thread-audit-row {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 12px;
	color: #666;
	font-family: OpenSans, Arial, sans-serif;
	line-height: 1.4;
}
.builder-thread-body-audit .builder-thread-audit-icon { font-size: 14px; flex-shrink: 0; color: #888; }
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-icon { color: #aaa; }
.builder-thread-body-audit .builder-thread-audit-text strong { color: #333; font-weight: 600; }
.builder-thread-body-audit .builder-thread-audit-text em     { color: #555; font-style: italic; }

body.appbuilder-dark .builder-thread-body-audit { border-left-color: #444; }
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-row { color: #aaa; }
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-text strong { color: #ddd; }
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-text em     { color: #ccc; }

/* Audit chip — "Show result" toggle + collapsible body. The body is
   styled like an inset quote so it reads as a sub-bubble and stays
   visually anchored to its parent chip even when the user is mid-
   conversation. */
.builder-thread-body-audit .builder-thread-audit-toggle {
	margin-left: 12px;
	font-size: 11px;
	color: #3a82f6;
	cursor: pointer;
	user-select: none;
	white-space: nowrap;
}
.builder-thread-body-audit .builder-thread-audit-time {
	margin-left: auto;
	padding-left: 12px;
	font-size: 11px;
	color: #999;
	white-space: nowrap;
}
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-time { color: #888; }
.builder-thread-body-audit .builder-thread-audit-toggle:hover { text-decoration: underline; }
.builder-thread-body-audit .builder-thread-audit-result {
	margin: 6px 0 0 26px;
	padding: 8px 12px;
	background: rgba(0, 0, 0, 0.03);
	border-left: 3px solid #b9c7d6;
	border-radius: 2px;
	font-size: 13px;
	color: #333;
}
.builder-thread-body-audit .builder-thread-audit-result-body {
	white-space: pre-wrap;
	word-break: break-word;
	font-family: OpenSans, Arial, sans-serif;
	line-height: 1.5;
}
/* `pre-wrap` above preserves newlines so plain-text replies keep their
   line breaks. But when markdownConverter has produced block-level
   HTML (<p>, <ul>, …), the literal newlines BETWEEN those tags
   (`</p>\n<p>`) render as visible blank lines stacked ON TOP OF the
   <p> margins below, blowing up paragraph spacing. Detect the
   markdown case via :has() and switch to normal whitespace; block
   margins are then the only spacing source. */
.builder-thread-body-audit .builder-thread-audit-result-body:has(p, ul, ol, h1, h2, h3, h4, h5, h6, blockquote, pre, table) {
	white-space: normal;
}
/* When the body holds markdown-rendered HTML (markdownConverter
   output: <p>, <ul>, <ol>, <h*>, etc.), the browser default margins
   add a full line of blank above AND below every <p> — combined with
   line-height 1.5 that reads as two empty lines between paragraphs.
   Tighten the block-level spacing so the agent's reply renders as a
   compact card, not an essay. First/last child margins zeroed so the
   block doesn't push against the card's own padding. */
.builder-thread-body-audit .builder-thread-audit-result-body p,
.builder-thread-body-audit .builder-thread-audit-result-body ul,
.builder-thread-body-audit .builder-thread-audit-result-body ol,
.builder-thread-body-audit .builder-thread-audit-result-body blockquote,
.builder-thread-body-audit .builder-thread-audit-result-body pre {
	margin: 0 0 6px 0;
}
.builder-thread-body-audit .builder-thread-audit-result-body h1,
.builder-thread-body-audit .builder-thread-audit-result-body h2,
.builder-thread-body-audit .builder-thread-audit-result-body h3,
.builder-thread-body-audit .builder-thread-audit-result-body h4,
.builder-thread-body-audit .builder-thread-audit-result-body h5,
.builder-thread-body-audit .builder-thread-audit-result-body h6 {
	margin: 8px 0 4px 0;
	font-weight: 600;
}
.builder-thread-body-audit .builder-thread-audit-result-body > *:first-child { margin-top: 0; }
.builder-thread-body-audit .builder-thread-audit-result-body > *:last-child  { margin-bottom: 0; }
.builder-thread-body-audit .builder-thread-audit-result-body ul,
.builder-thread-body-audit .builder-thread-audit-result-body ol {
	padding-left: 24px;
}
.builder-thread-body-audit .builder-thread-audit-result-body li {
	margin: 2px 0;
}
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-toggle { color: #60a5fa; }
body.appbuilder-dark .builder-thread-body-audit .builder-thread-audit-result {
	background: rgba(255, 255, 255, 0.04);
	border-left-color: #4a5568;
	color: #ddd;
}

/* Task dialog — Schedule group's "Next firings" preview card. Reserves
   a stable footprint (min-height fits the 5-line content: header + 3
   occurrences + 1 cron line) so the layout doesn't jump while the
   /builder/previewcron round-trip is in flight. Bordered card with
   left accent so it reads as an inline info panel rather than free
   text glued to the field row. */
.plan_cron_preview {
	min-height: 92px;
	padding: 8px 12px;
	margin: 4px 0 0 0;
	background: rgba(0, 0, 0, 0.03);
	border-left: 3px solid #b9c7d6;
	border-radius: 3px;
	font-size: 12px;
	line-height: 1.6;
	color: #444;
	font-family: OpenSans, Arial, sans-serif;
}
.plan_cron_preview b { color: #1a1a1a; font-weight: 600; }
.plan_cron_preview code {
	background: rgba(0, 0, 0, 0.05);
	padding: 1px 6px;
	border-radius: 3px;
	font-family: Consolas, "Courier New", monospace;
	font-size: 11px;
}
body.appbuilder-dark .plan_cron_preview {
	background: rgba(255, 255, 255, 0.04);
	border-left-color: #4a5568;
	color: #ccc;
}
body.appbuilder-dark .plan_cron_preview b    { color: #f1f5f9; }
body.appbuilder-dark .plan_cron_preview code { background: rgba(255, 255, 255, 0.08); }
/* The preview is a read-only info card; w2ui's form-field focus ring
   ends up drawn around our left-accent border and reads as a doubled
   outline. Suppress border / outline / box-shadow on the field AND
   every descendant in both resting and any-focus state. Critically we
   zero out border-WIDTH and outline-WIDTH (not just color) — w2ui
   draws the focus border with non-zero width, and a transparent
   border still reserves its pixels, shifting the card right on
   focus. The bordered "card" look comes from .plan_cron_preview's
   own border-left, untouched here. */
html body .w2ui-field:has(.plan_cron_preview),
html body .w2ui-field:has(.plan_cron_preview) *,
html body .w2ui-field:has(.plan_cron_preview):focus,
html body .w2ui-field:has(.plan_cron_preview):focus-within,
html body .w2ui-field:has(.plan_cron_preview):focus-visible,
html body .w2ui-field:has(.plan_cron_preview) *:focus,
html body .w2ui-field:has(.plan_cron_preview) *:focus-within,
html body .w2ui-field:has(.plan_cron_preview) *:focus-visible {
	border-width: 0 !important;
	outline-width: 0 !important;
	box-shadow: none !important;
}
/* …but RE-allow the preview card's own left-accent border that the
   blanket "border-width: 0" rule above just nuked. */
html body .w2ui-field .plan_cron_preview {
	border-left: 3px solid #b9c7d6 !important;
}
body.appbuilder-dark .w2ui-field .plan_cron_preview {
	border-left-color: #4a5568 !important;
}


/* Thread header — Chat / Tasks view toggle. Segmented-pill style:
   one rounded outer container with a subtle background, two inner
   segments sharing the same border-radius footprint. Selected
   segment is filled blue with white text; unselected stays muted and
   only changes background on hover. Sits in
   builder-thread-header-actions to the left of the "Search user" input. */
.builder-thread-view-toggle {
	display: inline-flex;
	align-items: stretch;
	background-color: rgba(0, 0, 0, 0.05);
	border-radius: 6px;
	padding: 2px;
	margin-right: 8px;
	gap: 2px;
}
.builder-thread-view-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 12px;
	border-radius: 4px;
	/* Inherit OpenSans (the rest of the app's UI font) — without an
	   explicit family the segment falls back to the page default for
	   <div>, which on some browsers is the serif Times stack. */
	font-family: OpenSans, Arial, sans-serif;
	font-size: 12px;
	font-weight: 500;
	color: #555;
	cursor: pointer;
	user-select: none;
	transition: background-color 0.12s ease, color 0.12s ease;
}
.builder-thread-view-btn i { font-size: 13px; }
.builder-thread-view-btn:hover { background-color: rgba(0, 0, 0, 0.06); color: #222; }
.builder-thread-view-btn.selected {
	/* Match the Thread Submit affordance (.builder-chatbot-button-icon-alt)
	   so the primary-action blue is consistent across the thread UI. */
	background-color: #269DF0;
	color: #ffffff;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10);
}
.builder-thread-view-btn.selected:hover { background-color: #1F84C6; }

body.appbuilder-dark .builder-thread-view-toggle { background-color: rgba(255, 255, 255, 0.06); }
body.appbuilder-dark .builder-thread-view-btn { color: #bbb; }
body.appbuilder-dark .builder-thread-view-btn:hover { background-color: rgba(255, 255, 255, 0.08); color: #eee; }
body.appbuilder-dark .builder-thread-view-btn.selected { background-color: #269DF0; color: #ffffff; }
body.appbuilder-dark .builder-thread-view-btn.selected:hover { background-color: #1F84C6; }

/* Task grid — completed-column visual feedback. The toggle variant
   shows a pointer cursor; the locked variant (synthetic-owned terminal
   runs) shows the default arrow so users see it's not interactive. */
.task-completed-toggle { cursor: pointer; }
.task-completed-locked { cursor: default; }

/* Directory panel — fallback logos (initials for users, sitemap / users
   icons for groups) shown on cards when no LOGO is stored. */
.directory_initials,
.directory_group_icon,
.directory_workflow_icon,
.directory_ontology_icon,
.directory_tradescript_icon,
.directory_backtest_icon,
.directory_portfolio_icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	font-family: OpenSans, sans-serif;
	font-weight: 600;
	color: #ffffff;
	background: #6b7fb3;
	border-radius: 4px;
	font-size: 18px;
	letter-spacing: 0.5px;
}
.directory_group_icon { background: #7a9f7a; font-size: 22px; }
/* Org Units get a distinct warm orange so they don't read as Groups. */
.directory_orgunit_icon { background: #c98654; }
/* Synthetic users get a distinct violet so a glance at the directory
   immediately tells you bot vs. person. */
.directory_initials_synth { background: #8a6cb1; }
/* Workflow cards: violet sitemap badge — matches the Workflows
   sidebar entry color in the Admin tabulation. */
.directory_workflow_icon { background: linear-gradient(135deg, #4a90e2, #7AB6F5); font-size: 20px; }
/* Ontology cards: teal share-alt badge — distinct hue from Workflows
   so the two Admin panels stay visually separable at a glance. */
.directory_ontology_icon { background: linear-gradient(135deg, #2fa2a0, #6bcac9); font-size: 20px; }
/* Trade Script cards: warm amber chart-line badge — signals finance,
   distinct from workflows (blue) and ontologies (teal) at a glance. */
.directory_tradescript_icon { background: linear-gradient(135deg, #d97706, #f5c76b); font-size: 20px; }
/* Backtest cards: violet flask badge — a backtest is an experiment ON a
   script, so it reads as related to the amber script badge without being
   mistaken for one. */
.directory_backtest_icon { background: linear-gradient(135deg, #7c4dbe, #b190e3); font-size: 20px; }
/* Portfolio cards: teal-green briefcase badge — a portfolio is what strategies
   graduate INTO, so it reads as the end of the chain rather than another
   experiment (violet) or an authoring surface (amber). */
.directory_portfolio_icon { background: linear-gradient(135deg, #0f9d76, #63d6b0); font-size: 20px; }

/* Green "Published" tag — anchored to the top-right corner of
   the workflow card. Sits as a sibling of the logo + text divs
   inside the card (which is position:relative via .applications_element).
   Ontology cards use the same chip shape via the twin selector. */
.workflow_published_tag,
.ontology_published_tag {
	position: absolute;
	top: 10px;
	right: 10px;
	/* Lift the chip above the card's title / description text,
	   which can otherwise paint on top of it when the title wraps. */
	z-index: 2;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 3px 8px;
	background-color: #3FAE5A;
	color: #ffffff;
	font: 600 10px OpenSans, sans-serif;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	border-radius: 10px;
}
.workflow_published_tag .fa,
.ontology_published_tag .fa { font-size: 11px; }

/* -----------------------------------------------------------------
   Ontology designer — Ship 2 GoJS graph editor.
   Layout mirrors the workflow designer's palette / canvas / props
   three-column pattern so the two panels feel cohesive.
   ----------------------------------------------------------------- */
.ontology_designer_layout {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	background-color: #FAF8F5;
	overflow: hidden;
	font-family: OpenSans, sans-serif;
}
.ontology_designer_top {
	flex: 0 0 40px;
	min-height: 40px;
	max-height: 40px;
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 12px;
	padding: 0 12px;
	border-bottom: 1px solid #e2e2e2;
	background-color: #fafafa;
}
.ontology_designer_top_actions {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: 6px;
}

/* Save indicator — same idle/dirty/saving/saved/error pattern as
   the workflow designer. Empty (no text) when idle. */
.ontology_designer_save_status {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font: 11px OpenSans, sans-serif;
	padding: 4px 8px;
	border-radius: 4px;
	color: #888;
	transition: opacity 0.2s ease, color 0.2s ease;
}
.ontology_designer_save_status.dirty  { color: #b58900; }
.ontology_designer_save_status.saving { color: #268bd2; }
.ontology_designer_save_status.saved  { color: #3fae5a; }
.ontology_designer_save_status.error  { color: #dc322f; }

/* Main three-column area */
.ontology_designer_main {
	flex: 1 1 auto;
	display: flex;
	flex-direction: row;
	min-height: 0;
}

/* Palette — 220px column with drag sources + link-legend. */
.ontology_designer_palette {
	flex: 0 0 220px;
	max-width: 220px;
	background: #f6f4ef;
	border-right: 1px solid #e2e2e2;
	padding: 10px 10px;
	overflow-y: auto;
	font: 12px OpenSans, sans-serif;
}
/* Datamodel-group cards — force a green accent (same family as
   workflow DATA activities) regardless of what the ONT_Table.png
   pixel sample would produce. */
.ontology_palette_datamodel_card {
	border-color: #3FAE5A !important;
	background-color: rgba(63, 174, 90, 0.10) !important;
}
.ontology_palette_datamodel_card:hover {
	box-shadow: 0 2px 6px rgba(63, 174, 90, 0.20) !important;
	border-color: #34964c !important;
}
body.appbuilder-dark .ontology_palette_datamodel_card {
	border-color: #4bbf72 !important;
	background-color: rgba(75, 191, 114, 0.14) !important;
}

.ontology_palette_empty {
	padding: 12px 16px;
	color: #999;
	font: italic 12px OpenSans, sans-serif;
	text-align: center;
}
body.appbuilder-dark .ontology_palette_empty { color: #8b8b90; }

/* Canvas */
.ontology_designer_canvas_wrap {
	flex: 1 1 auto;
	position: relative;
	min-width: 0;
	background: #ffffff;
}
.ontology_designer_canvas {
	position: absolute;
	inset: 0;
	outline: none;
}
/* Suppress the browser focus ring that appears around the GoJS
   <canvas> when the diagram receives keyboard focus (Delete / etc.).
   Same trick used by .workflow_designer_canvas canvas. */
.ontology_designer_canvas canvas {
	outline: none;
	-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}

/* Right property panel — default HIDDEN, revealed by adding
   `.visible` (workflow parity). Toggled via the top-bar button
   or a double-click on the canvas. Width driven by inline
   `flex-basis` set in JS (default 400 px) and adjusted by
   the splitter drag — same idiom as the workflow designer. */
.ontology_designer_props {
	flex: 0 0 400px;
	height: 100%;
	background: #F2F0EC;
	border-left: 1px solid #e2e2e2;
	overflow: hidden;
	display: none;
	min-width: 0;
	flex-direction: column;
}
.ontology_designer_props.visible { display: flex; }
.ontology_designer_props_header {
	padding: 12px 14px 10px 14px;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: #555;
	border-bottom: 1px solid #e2e2e2;
}
.ontology_designer_props_body {
	padding: 0;
}
.ontology_designer_props_empty {
	color: #888;
	font: 12px OpenSans, sans-serif;
	padding: 20px 14px;
	text-align: center;
	line-height: 1.5;
}
/* Preserve the workflow-style clip on section bodies so any
   overflow inside can't propagate to the outer panel. */
.ontology_designer_props .workflow_props_section_body {
	overflow-x: hidden;
}

/* ---- Query tab (Ship 3.1) ---- */
.ont_query_editor {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 12px 14px;
	font: 12px OpenSans, sans-serif;
}
.ont_query_hint {
	color: #888;
	font-size: 11px;
	line-height: 1.4;
}
.ont_query_input {
	width: 100%;
	box-sizing: border-box;
	min-height: 96px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	padding: 8px 10px;
	border: 1px solid #d5d5d5;
	border-radius: 4px;
	resize: vertical;
	background: #ffffff;
	color: #222;
}
.ont_query_input:focus {
	outline: none;
	border-color: #218AD1;
	box-shadow: 0 0 0 1px #218AD1 inset;
}
.ont_query_actions { display: flex; gap: 6px; align-items: center; }
.ont_query_messages { display: flex; flex-direction: column; gap: 4px; }
.ont_query_error {
	background: #fdecea;
	border-left: 3px solid #dc322f;
	color: #7a1e1c;
	padding: 6px 10px;
	border-radius: 3px;
	font: 12px OpenSans, sans-serif;
}
.ont_query_warning {
	background: #fef7e0;
	border-left: 3px solid #d6a300;
	color: #6b5203;
	padding: 6px 10px;
	border-radius: 3px;
	font: 12px OpenSans, sans-serif;
}
.ont_query_pending { color: #999; font-style: italic; }
.ont_query_empty   { color: #999; font-style: italic; }
.ont_query_ir_header {
	font: 600 11px OpenSans, sans-serif;
	text-transform: uppercase;
	color: #666;
	letter-spacing: 0.3px;
	margin-top: 8px;
	margin-bottom: 4px;
}
.ont_query_ir,
.ont_query_plan_tree { font: 12px "Fira Code", Menlo, Consolas, monospace; }
/* Ship 3.2: physical-plan chips visually distinct from IR (green) so
   the two trees don't blur when both are open. */
.ont_query_plan_tree .ont_ir_kind { background: #2a9d8f; }
.ont_ir_node {
	padding-left: 12px;
	border-left: 1px dashed #ccc;
	margin: 2px 0;
}
.ont_ir_head { display: flex; align-items: center; gap: 8px; }
.ont_ir_kind {
	background: #218AD1;
	color: #fff;
	padding: 1px 6px;
	border-radius: 3px;
	font: 600 11px OpenSans, sans-serif;
}
.ont_ir_summary { color: #333; }
.ont_ir_children { margin-top: 2px; }

body.appbuilder-dark .ont_query_hint,
body.appbuilder-dark .ont_query_empty,
body.appbuilder-dark .ont_query_pending { color: #8b8b90; }
body.appbuilder-dark .ont_query_input {
	background: #2c2d31; border-color: #45464b; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_input:focus { border-color: #6bcac9; box-shadow: 0 0 0 1px #6bcac9 inset; }
body.appbuilder-dark .ont_query_error {
	background: #3a1f1f; border-left-color: #ff8a7e; color: #f0c8c4;
}
body.appbuilder-dark .ont_query_warning {
	background: #3a341a; border-left-color: #ffd166; color: #ecd5a5;
}
body.appbuilder-dark .ont_ir_node { border-left-color: #45464b; }
body.appbuilder-dark .ont_ir_summary { color: #cfcfd3; }
body.appbuilder-dark .ont_query_plan_tree .ont_ir_kind { background: #38b09f; color: #10231f; }

/* Ship 3.7 — cardinality chip + stats-age pill */
.ont_ir_estrows {
	background: #eef4ff;
	color: #2c5aa0;
	padding: 1px 6px;
	border-radius: 3px;
	font: 600 10px "Fira Code", Menlo, Consolas, monospace;
	margin-left: 6px;
}
.ont_query_plan_tree .ont_ir_estrows {
	background: #e4f4f2; color: #1f6d63;
}
.ont_query_stats_age {
	font: 11px OpenSans, sans-serif;
	color: #666;
	margin-left: 8px;
	align-self: center;
}
.ont_query_stats_age_fresh { color: #226622; }
.ont_query_stats_age_stale { color: #b58900; }

body.appbuilder-dark .ont_ir_estrows { background: #2a3552; color: #a9c4ff; }
body.appbuilder-dark .ont_query_plan_tree .ont_ir_estrows {
	background: #1f3936; color: #6bcac9;
}
body.appbuilder-dark .ont_query_stats_age { color: #a8a8ac; }
body.appbuilder-dark .ont_query_stats_age_fresh { color: #7fc47f; }
body.appbuilder-dark .ont_query_stats_age_stale { color: #ffd166; }

/* Ship 3.8.3 — Translate button "N learned" badge.
   The button itself becomes an inline-flex row so the label and the
   chip share the same cross-axis center. `vertical-align: middle` on
   the chip isn't reliable — with two different font metrics inside a
   line-box it aligns to x-height, not visual center. */
.ont_query_translate {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.ont_query_kb_badge {
	display: inline-flex;
	align-items: center;
	line-height: 1;
	background: #eef4ff; color: #2c5aa0;
	padding: 2px 6px; border-radius: 3px; margin-left: 0;
	font: 600 10px OpenSans, sans-serif;
}
body.appbuilder-dark .ont_query_kb_badge { background: #2a3552; color: #a9c4ff; }

/* Ship 3.8.1 — KB manager modal */
.ont_kb_mgr { font: 12px OpenSans, sans-serif; }
.ont_kb_mgr_summary { color: #666; margin-bottom: 10px; }
.ont_kb_mgr_stale_count, .nlpe-mgr-stale-count { color: #b58900; font-weight: 600; margin-left: 6px; }
.ont_kb_mgr_hash, .nlpe-mgr-hash { color: #999; font: 11px "Fira Code", Menlo, Consolas, monospace; margin-left: 6px; }
.ont_kb_mgr_empty { color: #999; font-style: italic; padding: 20px; text-align: center; }
.ont_kb_mgr_err   { color: #a03030; padding: 20px; }
.ont_kb_mgr_row {
	border: 1px solid #e0e0e0; border-radius: 4px;
	padding: 8px 10px; margin-bottom: 8px; background: #fdfdfd;
}
.ont_kb_mgr_row_head { display: flex; align-items: center; gap: 8px; }
.ont_kb_mgr_kind {
	padding: 1px 6px; border-radius: 3px; font: 600 10px OpenSans, sans-serif;
	text-transform: uppercase; letter-spacing: 0.3px;
}
.ont_kb_mgr_kind_up  { background: #dff5dd; color: #226622; }
.ont_kb_mgr_kind_fix { background: #fff2c9; color: #8a6b00; }
.ont_kb_mgr_nl { flex: 1; font-weight: 600; color: #333; }
.ont_kb_mgr_stale, .nlpe-mgr-stale {
	background: #fbe6b8; color: #8a6b00;
	padding: 1px 6px; border-radius: 3px; font: 600 10px OpenSans, sans-serif;
}
.ont_kb_mgr_row_actions { display: flex; gap: 4px; }
.ont_kb_mgr_cypher {
	background: #fafafa; border: 1px solid #ececec; border-radius: 3px;
	padding: 6px 8px; margin: 6px 0 0;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	white-space: pre-wrap; word-break: break-word; color: #222;
}
.ont_kb_mgr_edit_ta {
	width: 100%; box-sizing: border-box; min-height: 80px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	background: #fdfaf3; border: 1px solid #e5d9b6; border-radius: 3px;
	padding: 6px 8px; margin-top: 6px;
}
.ont_kb_mgr_edit_actions { display: flex; gap: 6px; margin-top: 6px; }
body.appbuilder-dark .ont_kb_mgr                    { color: #cfcfd3; }
body.appbuilder-dark .ont_kb_mgr_summary            { color: #a8a8ac; }
body.appbuilder-dark .ont_kb_mgr_hash, body.appbuilder-dark .nlpe-mgr-hash { color: #7a7a80; }
body.appbuilder-dark .ont_kb_mgr_row                { background: #2a2b2f; border-color: #3a3b40; }
body.appbuilder-dark .ont_kb_mgr_nl                 { color: #e0e0e2; }
body.appbuilder-dark .ont_kb_mgr_cypher             { background: #24262b; border-color: #3a3b40; color: #e0e0e2; }
body.appbuilder-dark .ont_kb_mgr_edit_ta            { background: #2a2822; border-color: #46402c; color: #e6e6e8; }
body.appbuilder-dark .ont_kb_mgr_kind_up            { background: #1f3a1f; color: #7fc47f; }
body.appbuilder-dark .ont_kb_mgr_kind_fix           { background: #3a2f10; color: #ffd166; }
body.appbuilder-dark .ont_kb_mgr_stale, body.appbuilder-dark .nlpe-mgr-stale { background: #3a2f10; color: #ffd166; }

/* Ship 3.8 — 👍/👎 vote controls (row-inline, always visible).
   Reuses the thread UI's `dbcons-prompt-vote` icon styling for
   consistency. Only override `position` — the parent there is
   absolute-positioned over messages; here we sit in a flex row. */
.ont_query_vote_group_row.dbcons-prompt-vote {
	position: static; right: auto; top: auto;
	margin-left: 8px;
	height: auto; line-height: 1.4;
}
.ont_query_vote_status {
	margin-left: 8px; font: 11px OpenSans, sans-serif; color: #888;
	text-transform: none; letter-spacing: 0;
}
.ont_query_vote_status.ok  { color: #226622; }
.ont_query_vote_status.err { color: #a03030; }
.ont_query_vote_fix { margin: 4px 0 10px; }
.ont_query_vote_fix_input {
	width: 100%; box-sizing: border-box; min-height: 100px; max-height: 30vh;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	background: #fdfaf3; color: #222;
	border: 1px solid #e5d9b6; border-radius: 3px;
	padding: 8px 10px; resize: vertical; white-space: pre;
}
.ont_query_vote_fix_input:focus { border-color: #b58900; outline: none; box-shadow: 0 0 0 1px #b58900 inset; }
.ont_query_vote_fix_actions { display: flex; gap: 6px; margin-top: 6px; }
body.appbuilder-dark .ont_query_vote_btn:hover:not(:disabled) { background: #2c2d31; border-color: #45464b; }
body.appbuilder-dark .ont_query_vote_status                    { color: #a8a8ac; }
body.appbuilder-dark .ont_query_vote_status.ok                 { color: #7fc47f; }
body.appbuilder-dark .ont_query_vote_status.err                { color: #ff8a7e; }
body.appbuilder-dark .ont_query_vote_fix_input {
	background: #2a2822; border-color: #46402c; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_vote_fix_input:focus { border-color: #ffd166; box-shadow: 0 0 0 1px #ffd166 inset; }

/* Ship 3.6: NL → Cypher input + generated cypher chip */
.ont_query_nl_input {
	width: 100%;
	box-sizing: border-box;
	min-height: 44px;
	max-height: 120px;
	font: 12px OpenSans, sans-serif;
	color: #222;
	background: #fbf7ee;
	border: 1px solid #e5d9b6;
	border-radius: 3px;
	padding: 6px 8px;
	resize: vertical;
	margin-bottom: 4px;
}
.ont_query_nl_input:focus {
	border-color: #b58900;
	outline: none;
	box-shadow: 0 0 0 1px #b58900 inset;
}
.ont_query_hint_cypher { margin-top: 12px; }
.ont_query_generated_cypher {
	background: #fbf7ee;
	border: 1px solid #e5d9b6;
	border-radius: 3px;
	padding: 8px 10px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	color: #222;
	white-space: pre-wrap;
	word-break: break-word;
	margin: 4px 0 8px;
}
.ont_query_nl_attempts {
	background: #b58900;
	color: #fff;
	padding: 1px 6px;
	border-radius: 3px;
	font: 600 11px OpenSans, sans-serif;
	margin-left: 6px;
}
body.appbuilder-dark .ont_query_nl_input {
	background: #2a2822; border-color: #46402c; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_nl_input:focus { border-color: #ffd166; box-shadow: 0 0 0 1px #ffd166 inset; }
body.appbuilder-dark .ont_query_generated_cypher {
	background: #2a2822; border-color: #46402c; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_nl_attempts { background: #ffd166; color: #10231f; }

/* Ship 3.4: plan JSON editor */
.ont_query_plan_actions { margin: 6px 0; }
.ont_query_plan_editor { margin: 4px 0 10px; }
.ont_query_plan_input {
	width: 100%;
	box-sizing: border-box;
	min-height: 180px;
	max-height: 40vh;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	background: #fafafa;
	color: #222;
	border: 1px solid #d5d5d5;
	border-radius: 3px;
	padding: 8px 10px;
	resize: vertical;
	white-space: pre;
}
.ont_query_plan_input:focus { border-color: #218AD1; outline: none; box-shadow: 0 0 0 1px #218AD1 inset; }
.ont_query_plan_editor_actions { display: flex; gap: 6px; margin-top: 6px; }
body.appbuilder-dark .ont_query_plan_input {
	background: #24262b; border-color: #3a3b40; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_plan_input:focus { border-color: #6bcac9; box-shadow: 0 0 0 1px #6bcac9 inset; }

/* Ship 3.12 — DB > Query "Manage examples" modal. Same look as the
   Ontology KB manager (Ship 3.8.1) so the two curation surfaces feel
   like siblings. Scoped to `.dbcons-mgr` to avoid clashing with the
   ontology namespace. */
.dbcons-mgr, .nlpe-mgr { font: 12px OpenSans, sans-serif; }
.dbcons-mgr-summary, .nlpe-mgr-summary { color: #666; margin-bottom: 10px; }
.dbcons-mgr-empty, .nlpe-mgr-empty { color: #999; font-style: italic; padding: 20px; text-align: center; }
.dbcons-mgr-row, .nlpe-mgr-row {
	border: 1px solid #e0e0e0; border-radius: 4px;
	padding: 8px 10px; margin-bottom: 8px; background: #fdfdfd;
}
.dbcons-mgr-row-head, .nlpe-mgr-row-head { display: flex; align-items: center; gap: 8px; }
.dbcons-mgr-kind, .nlpe-mgr-kind {
	padding: 1px 6px; border-radius: 3px; font: 600 10px OpenSans, sans-serif;
	text-transform: uppercase; letter-spacing: 0.3px;
}
.dbcons-mgr-kind_up, .nlpe-mgr-kind_up   { background: #dff5dd; color: #226622; }
.dbcons-mgr-kind_fix, .nlpe-mgr-kind_fix { background: #fff2c9; color: #8a6b00; }
.dbcons-mgr-nl, .nlpe-mgr-nl { flex: 1; font-weight: 600; color: #333; }
.dbcons-mgr-row-actions, .nlpe-mgr-row-actions { display: flex; gap: 4px; }
.dbcons-mgr-comment, .nlpe-mgr-comment {
	color: #8a6b00; font-style: italic; margin: 4px 0 0; font-size: 11px;
}
.dbcons-mgr-shape, .nlpe-mgr-shape {
	background: #eef4ff; color: #2c5aa0;
	padding: 1px 6px; border-radius: 3px;
	font: 600 10px OpenSans, sans-serif;
	text-transform: lowercase;
}
.dbcons-mgr-desc, .nlpe-mgr-desc { color: #666; font-style: italic; margin: 4px 0 0; }
body.appbuilder-dark .dbcons-mgr-shape, body.appbuilder-dark .nlpe-mgr-shape { background: #2a3552; color: #a9c4ff; }
body.appbuilder-dark .dbcons-mgr-desc,  body.appbuilder-dark .nlpe-mgr-desc  { color: #a8a8ac; }
/* `.dbcons-mgr-sql` is the SQL-flavoured content block; `.nlpe-mgr-content`
   is the generic sibling used by Pine/Chart/Ontology. Same visual, only
   the classname differs — new code should use nlpe. */
.dbcons-mgr-sql, .nlpe-mgr-content {
	background: #fafafa; border: 1px solid #ececec; border-radius: 3px;
	padding: 6px 8px; margin: 6px 0 0;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	white-space: pre-wrap; word-break: break-word; color: #222;
}
/* Collapse long content blocks (Pine scripts can run to 100+ lines);
   ~5 line window, then a gradient fade + "Show more" button. */
.nlpe-mgr-content.is-collapsed {
	max-height: 96px;
	overflow: hidden;
	position: relative;
}
.nlpe-mgr-content.is-collapsed::after {
	content: "";
	position: absolute;
	left: 0; right: 0; bottom: 0; height: 32px;
	background: linear-gradient(to bottom, rgba(250,250,250,0), #fafafa 90%);
	pointer-events: none;
}
.nlpe-mgr-actions-row {
	display: flex;
	gap: 12px;
	margin: 6px 0 0 8px;   /* 6px gap above the pre, 8px left offset to line up with pre's inner padding */
}
.nlpe-mgr-more {
	display: inline-block;
	margin: 0;
	padding: 0;
	background: none;
	border: 0;
	color: #2F9EEE;
	font: 11px OpenSans, sans-serif;
	cursor: pointer;
	line-height: 1.4;
}
.nlpe-mgr-more:hover { text-decoration: underline; }
.nlpe-mgr-more .fa   { margin-right: 2px; }
body.appbuilder-dark .nlpe-mgr-content.is-collapsed::after {
	background: linear-gradient(to bottom, rgba(36,38,43,0), #24262b 90%);
}
body.appbuilder-dark .nlpe-mgr-more { color: #7ec8ff; }
.dbcons-mgr-edit-ta, .nlpe-mgr-edit-ta {
	width: 100%; box-sizing: border-box; min-height: 80px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	background: #fdfaf3; border: 1px solid #e5d9b6; border-radius: 3px;
	padding: 6px 8px; margin-top: 6px;
}
.dbcons-mgr-edit-actions, .nlpe-mgr-edit-actions { display: flex; gap: 6px; margin-top: 6px; }
body.appbuilder-dark .dbcons-mgr, body.appbuilder-dark .nlpe-mgr                { color: #cfcfd3; }
body.appbuilder-dark .dbcons-mgr-summary, body.appbuilder-dark .nlpe-mgr-summary { color: #a8a8ac; }
body.appbuilder-dark .dbcons-mgr-row, body.appbuilder-dark .nlpe-mgr-row        { background: #2a2b2f; border-color: #3a3b40; }
body.appbuilder-dark .dbcons-mgr-nl, body.appbuilder-dark .nlpe-mgr-nl          { color: #e0e0e2; }
body.appbuilder-dark .dbcons-mgr-sql, body.appbuilder-dark .nlpe-mgr-content    { background: #24262b; border-color: #3a3b40; color: #e0e0e2; }
body.appbuilder-dark .dbcons-mgr-edit-ta, body.appbuilder-dark .nlpe-mgr-edit-ta { background: #2a2822; border-color: #46402c; color: #e6e6e8; }
body.appbuilder-dark .dbcons-mgr-kind_up, body.appbuilder-dark .nlpe-mgr-kind_up   { background: #1f3a1f; color: #7fc47f; }
body.appbuilder-dark .dbcons-mgr-kind_fix, body.appbuilder-dark .nlpe-mgr-kind_fix { background: #3a2f10; color: #ffd166; }
body.appbuilder-dark .dbcons-mgr-comment, body.appbuilder-dark .nlpe-mgr-comment   { color: #ffd166; }

/* Ship 3.10-A — SQL parameters table */
.ont_query_params {
	border-collapse: collapse; margin: 4px 0 8px;
	background: #fafafa; border: 1px solid #ececec; border-radius: 3px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
}
.ont_query_params td { padding: 3px 8px; border-bottom: 1px solid #ececec; vertical-align: top; }
.ont_query_params tr:last-child td { border-bottom: 0; }
.ont_query_param_name { color: #218AD1; font-weight: 600; white-space: nowrap; }
.ont_query_param_val  { color: #226622; word-break: break-word; }
body.appbuilder-dark .ont_query_params {
	background: #24262b; border-color: #3a3b40;
}
body.appbuilder-dark .ont_query_params td       { border-color: #3a3b40; }
body.appbuilder-dark .ont_query_param_name      { color: #6bcac9; }
body.appbuilder-dark .ont_query_param_val       { color: #7fc47f; }

/* Ship 3.3: SQL preview + rows grid */
.ont_query_sql {
	background: #f5f5f5;
	border: 1px solid #e0e0e0;
	border-radius: 3px;
	padding: 8px 10px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	color: #222;
	white-space: pre-wrap;
	word-break: break-word;
	margin: 4px 0 8px;
	max-height: 200px;
	overflow: auto;
}
.ont_query_rowcount {
	background: #218AD1;
	color: #fff;
	padding: 1px 6px;
	border-radius: 3px;
	font: 600 11px OpenSans, sans-serif;
	margin-left: 6px;
}
.ont_query_trunc { color: #b58900; font: italic 11px OpenSans, sans-serif; }
.ont_query_rows { max-height: 320px; overflow: auto; border: 1px solid #e0e0e0; border-radius: 3px; }
.ont_query_rows_table {
	width: 100%;
	border-collapse: collapse;
	font: 12px OpenSans, sans-serif;
}
.ont_query_rows_table th,
.ont_query_rows_table td {
	padding: 4px 8px;
	border-bottom: 1px solid #ececec;
	text-align: left;
	vertical-align: top;
	white-space: nowrap;
	max-width: 400px;
	overflow: hidden;
	text-overflow: ellipsis;
}
.ont_query_rows_table th {
	background: #fafafa;
	font-weight: 600;
	color: #555;
	position: sticky;
	top: 0;
}
.ont_query_rows_empty td { color: #999; font-style: italic; text-align: center; padding: 12px; }

body.appbuilder-dark .ont_query_sql {
	background: #24262b; border-color: #3a3b40; color: #e6e6e8;
}
body.appbuilder-dark .ont_query_rowcount { background: #6bcac9; color: #10231f; }
body.appbuilder-dark .ont_query_trunc    { color: #ffd166; }
body.appbuilder-dark .ont_query_rows { border-color: #3a3b40; }
body.appbuilder-dark .ont_query_rows_table th {
	background: #2c2d31; color: #cfcfd3; border-color: #3a3b40;
}
body.appbuilder-dark .ont_query_rows_table td { border-color: #3a3b40; color: #e0e0e2; }
body.appbuilder-dark .ont_query_rows_empty td { color: #888; }

.ontology_props_field { margin-bottom: 14px; }
.ontology_props_field > label {
	display: block;
	font: 600 11px OpenSans, sans-serif;
	color: #666;
	margin-bottom: 4px;
	letter-spacing: 0.3px;
	text-transform: uppercase;
}
.ontology_props_field input[type=text],
.ontology_props_field textarea {
	width: 100%;
	box-sizing: border-box;
	font: 12px OpenSans, sans-serif;
	color: #222;
	background: #ffffff;
	border: 1px solid #d5d5d5;
	border-radius: 3px;
	padding: 6px 8px;
	resize: vertical;
}
.ontology_props_field input[type=text]:focus,
.ontology_props_field textarea:focus {
	outline: none;
	border-color: #2fa2a0;
	box-shadow: 0 0 0 1px #2fa2a0 inset;
}
.ontology_props_hint {
	font: 12px OpenSans, sans-serif;
	color: #888;
	background: #fdfbf5;
	border-left: 3px solid #d5d5d5;
	padding: 8px 10px;
	line-height: 1.4;
}

.ontology_props_endpoints > div {
	font: 12px OpenSans, sans-serif;
	color: #444;
	padding: 3px 0;
}
.ontology_endpoint_label {
	display: inline-block;
	min-width: 46px;
	font: 600 11px OpenSans, sans-serif;
	color: #888;
	text-transform: uppercase;
	letter-spacing: 0.3px;
}

/* Kind + Cardinality toggles */
.ontology_kind_toggle,
.ontology_card_toggle {
	display: flex;
	gap: 0;
	border: 1px solid #d5d5d5;
	border-radius: 4px;
	overflow: hidden;
}
.ontology_kind_btn,
.ontology_card_btn {
	flex: 1 1 auto;
	background: #ffffff;
	border: none;
	color: #444;
	font: 12px OpenSans, sans-serif;
	padding: 6px 8px;
	cursor: pointer;
	border-left: 1px solid #e5e5e5;
}
.ontology_kind_btn:first-child,
.ontology_card_btn:first-child { border-left: none; }
.ontology_kind_btn:hover,
.ontology_card_btn:hover  { background: #f4f4f4; }
.ontology_kind_btn.active,
.ontology_card_btn.active {
	background: #218AD1;
	color: #ffffff;
}

/* Attribute grid */
.ontology_attr_list {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-bottom: 6px;
}
.ontology_attr_row {
	display: flex;
	gap: 6px;
	align-items: center;
}
.ontology_attr_row input.ontology_attr_name { flex: 1 1 50%; }
.ontology_attr_row input.ontology_attr_type { flex: 1 1 50%; }
.ontology_attr_del {
	background: transparent;
	border: 1px solid transparent;
	color: #999;
	padding: 4px 6px;
	border-radius: 3px;
	cursor: pointer;
}
.ontology_attr_del:hover { background: #fde0dc; color: #c0392b; border-color: #f0c0b8; }
.ontology_attr_add {
	background: #ffffff;
	border: 1px dashed #b8d5d3;
	color: #2fa2a0;
	font: 12px OpenSans, sans-serif;
	padding: 6px 10px;
	border-radius: 3px;
	cursor: pointer;
	width: 100%;
}
.ontology_attr_add:hover { background: #ecf7f6; }

/* Read-only overlay for published ontologies. Mirrors the
   workflow_designer_readonly treatment (grayscale + disabled
   inputs). Canvas remains navigable; the Stop button in the
   header (rendered via .workflow_designer_publish_btn) stays
   clickable via the escape rule below. */
.ontology_designer_readonly .ontology_designer_palette,
.ontology_designer_readonly .ontology_designer_props,
.ontology_designer_readonly .workflow_designer_autolayout_btn {
	opacity: 0.55;
	filter: grayscale(30%);
	pointer-events: none;
}
.ontology_designer_readonly .workflow_designer_publish_btn { pointer-events: auto; }

/* -------- Dark theme -------- */
body.appbuilder-dark .ontology_designer_layout     { background-color: #1e1f22; }
body.appbuilder-dark .ontology_designer_top        { background-color: #26272b; border-bottom-color: #3a3b40; }

body.appbuilder-dark .ontology_designer_palette    { background: #232428; border-right-color: #3a3b40; }
body.appbuilder-dark .ontology_palette_group_header { color: #8b8b90; }
body.appbuilder-dark .ontology_designer_canvas_wrap { background: #1a1a1a; }

body.appbuilder-dark .ontology_designer_props        { background: #232428; border-left-color: #3a3b40; }
body.appbuilder-dark .ontology_designer_props_header { background: #26272b; border-bottom-color: #3a3b40; color: #cfcfd3; }
body.appbuilder-dark .ontology_designer_props_empty  { color: #8b8b90; }
body.appbuilder-dark .ontology_props_field > label   { color: #a0a0a6; }
body.appbuilder-dark .ontology_props_field input[type=text],
body.appbuilder-dark .ontology_props_field textarea {
	background: #2c2d31;
	border-color: #45464b;
	color: #e6e6e8;
}
body.appbuilder-dark .ontology_props_hint            { background: #2c2d31; color: #9a9aa2; border-left-color: #45464b; }
body.appbuilder-dark .ontology_props_endpoints > div { color: #cfcfd3; }
body.appbuilder-dark .ontology_endpoint_label        { color: #8b8b90; }

body.appbuilder-dark .ontology_kind_toggle,
body.appbuilder-dark .ontology_card_toggle { border-color: #45464b; }
body.appbuilder-dark .ontology_kind_btn,
body.appbuilder-dark .ontology_card_btn {
	background: #2c2d31;
	color: #cfcfd3;
	border-left-color: #45464b;
}
body.appbuilder-dark .ontology_kind_btn:hover,
body.appbuilder-dark .ontology_card_btn:hover  { background: #34353a; }
body.appbuilder-dark .ontology_kind_btn.active,
body.appbuilder-dark .ontology_card_btn.active { background: #218AD1; color: #ffffff; }

body.appbuilder-dark .ontology_attr_add { background: #2c2d31; border-color: #45464b; color: #6bcac9; }
body.appbuilder-dark .ontology_attr_add:hover { background: #34353a; }
body.appbuilder-dark .ontology_attr_del:hover { background: #4d2222; color: #f0b0a8; border-color: #6a3030; }

/* Workflow designer — replaces the workflow cards list when a
   workflow is opened. Top bar shows the workflow name; hovering
   reveals a back arrow (same UX as the global app-title control). */
.workflow_designer_layout {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	background-color: #FAF8F5;
	/* Prevent any inner overflow from triggering scrollbars on
	   the outer designer surface. */
	overflow: hidden;
}
.workflow_designer_top {
	flex: 0 0 40px;
	min-height: 40px;
	max-height: 40px;
	display: flex;
	flex-direction: row;
	align-items: center;
	padding: 0 12px;
	border-bottom: 1px solid #e2e2e2;
	background-color: #fafafa;
}
/* Force vertical centering for both children of the top bar —
   defensive against any descendant rule that might override
   `align-items: center`. */
.workflow_designer_top > * {
	align-self: center;
}
.workflow_designer_top_actions {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: 6px;
}

/* Inline save indicator — sits to the LEFT of the Publish /
   Properties buttons. Empty (no width) when idle so it doesn't
   waste space; states drive the color and icon. The "saved"
   state fades out after 2s (handled in JS). */
.workflow_designer_save_status {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font: 11px OpenSans, sans-serif;
	padding: 4px 8px;
	border-radius: 4px;
	color: #888;
	transition: opacity 0.2s ease, color 0.2s ease;
	min-height: 18px;
}
.workflow_designer_save_status:empty {
	padding: 0;
	min-height: 0;
}
.workflow_designer_save_status.is-pending { color: #888; }
.workflow_designer_save_status.is-saving  { color: #555; }
.workflow_designer_save_status.is-saved   { color: #2E7D32; }
.workflow_designer_save_status.is-error   { color: #C0392B; background-color: rgba(192, 57, 43, 0.10); }
.workflow_designer_save_status .fa { font-size: 10px; }
body.appbuilder-dark .workflow_designer_save_status.is-pending { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .workflow_designer_save_status.is-saving  { color: var(--fg, #c8c8c8); }
body.appbuilder-dark .workflow_designer_save_status.is-saved   { color: #4caf50; }
body.appbuilder-dark .workflow_designer_save_status.is-error   { color: #ff8a7e; background-color: rgba(231, 76, 60, 0.14); }
.workflow_designer_props_toggle,
.ontology_designer_props_toggle,
.tradescript_chat_toggle {
	cursor: pointer;
	color: #555;
	padding: 6px 10px;
	border-radius: 4px;
	font-size: 14px;
	transition: background-color 0.12s ease, color 0.12s ease;
}
.workflow_designer_props_toggle:hover,
.ontology_designer_props_toggle:hover,
.tradescript_chat_toggle:hover { background-color: #ECE9E2; }
.workflow_designer_props_toggle.active,
.ontology_designer_props_toggle.active,
.tradescript_chat_toggle.active {
	color: #ffffff;
	background-color: #5a6268;
}

/* Publish / Stop button — sits to the LEFT of the properties
   toggle. Green when not yet published; red when published. */
.workflow_designer_publish_btn {
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 12px;
	border-radius: 4px;
	font: 600 12px OpenSans, sans-serif;
	color: #ffffff;
	background-color: #3FAE5A;
	transition: background-color 0.12s ease;
	user-select: none;
}
.workflow_designer_publish_btn:hover     { background-color: #34964c; }
.workflow_designer_publish_btn.workflow_designer_published {
	background-color: #D9534F;
}
.workflow_designer_publish_btn.workflow_designer_published:hover {
	background-color: #b9433f;
}
body.appbuilder-dark .workflow_designer_props_toggle,
body.appbuilder-dark .ontology_designer_props_toggle,
body.appbuilder-dark .tradescript_chat_toggle {
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .workflow_designer_props_toggle:hover,
body.appbuilder-dark .ontology_designer_props_toggle:hover,
body.appbuilder-dark .tradescript_chat_toggle:hover {
	background-color: var(--bg-hover, #2a2a2a);
}

/* Phase J — Auto-arrange button. Same chrome as the properties
   toggle (neutral icon-only chip) so it doesn't compete with the
   colored Publish button. Mirrors light + dark. */
.workflow_designer_autolayout_btn {
	cursor: pointer;
	color: #555;
	padding: 6px 10px;
	border-radius: 4px;
	font-size: 14px;
	transition: background-color 0.12s ease, color 0.12s ease;
}
.workflow_designer_autolayout_btn:hover { background-color: #ECE9E2; }
body.appbuilder-dark .workflow_designer_autolayout_btn {
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .workflow_designer_autolayout_btn:hover {
	background-color: var(--bg-hover, #2a2a2a);
}
.workflow_designer_title {
	font-family: OpenSans, sans-serif;
	font-size: 14px;
	font-weight: 600;
	color: #27251e;
	padding: 4px 10px;
}
.workflow_designer_main {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: flex;
	flex-direction: row;
	/* Clip a too-wide right panel so a designer who drags the
	   splitter past the viewport doesn't trigger a horizontal
	   scrollbar on the whole workflow surface. The splitter
	   handler also clamps live, but this is a safety net. */
	overflow: hidden;
}
/* Palette column: fixed width, lighter background to read as a
   tool tray separate from the canvas. */
.workflow_designer_palette {
	flex: 0 0 200px;
	height: 100%;
	border-right: 1px solid #e2e2e2;
	background-color: #F2F0EC;
	overflow: hidden;
	overflow-y: auto;
	padding: 4px 0;
}

/* Collapsible group inside the workflow palette. Header is a
   row with chevron + title; clicking the header toggles the
   `collapsed` class which slides the body away. */
.workflow_palette_group {
	border-bottom: 1px solid #e2e2e2;
}
.workflow_palette_group_header {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 12px;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: #555;
	cursor: pointer;
	user-select: none;
	background-color: #ECE9E2;
}
.workflow_palette_group_header:hover {
	background-color: #E4E0D7;
}
.workflow_palette_chevron {
	font-size: 11px;
	width: 12px;
	color: #888;
	transition: transform 0.15s ease;
}
.workflow_palette_group.collapsed .workflow_palette_chevron {
	transform: rotate(-90deg);
}
.workflow_palette_group_body {
	max-height: 1200px;
	overflow: hidden;
	transition: max-height 0.2s ease;
}
.workflow_palette_group.collapsed .workflow_palette_group_body {
	max-height: 0;
}

body.appbuilder-dark .workflow_palette_group {
	border-bottom-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_palette_group_header {
	background-color: var(--bg, #1a1a1a);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .workflow_palette_group_header:hover {
	background-color: var(--bg-hover, #2a2a2a);
}

/* Palette draggable card — hand-rolled HTML (no GoJS Palette) so
   we can stack richer content (icon + title + description) and
   later add tabs / filters / search without fighting the GoJS
   layout. Same pattern as ChapsV_AppAI.js .agent_step. */
.workflow_palette_step {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	color: rgba(101, 97, 100, 0.9);
	background-color: #ffffff;
	border: 1px solid #d9d6d0;
	border-radius: 8px;
	margin: 8px;
	padding: 8px 8px 8px 48px;
	min-height: 48px;
	position: relative;
	cursor: grab;
	user-select: none;
	transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}
.workflow_palette_step:hover {
	border-color: #4a90e2;
	box-shadow: 0 2px 6px rgba(74, 144, 226, 0.15);
}
.workflow_palette_step:active {
	cursor: grabbing;
	transform: scale(0.98);
}
.workflow_palette_icon {
	position: absolute;
	/* Top-aligned so it sits next to the title, not centered
	   relative to title + description below. */
	top: 8px;
	left: 10px;
	transform: none;
	width: 32px;
	height: 32px;
	/* Clip the square PNG into a disc — the image carries its own
	   colored background, so the visible disc reads as that color
	   automatically. The card border + fill are sampled from the
	   same pixel at OpenDesigner time. */
	border-radius: 50%;
	background: transparent;
	border: none;
	padding: 0;
	box-sizing: border-box;
	object-fit: cover;
	pointer-events: none;
}
.workflow_palette_title {
	font-size: 13px;
	font-weight: 600;
	color: #27251e;
}
.workflow_palette_desc {
	margin-top: 2px;
	color: #808080;
	line-height: 1.3;
}

body.appbuilder-dark .workflow_palette_step {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .workflow_palette_step:hover {
	border-color: #7AB1F0;
	box-shadow: 0 2px 6px rgba(122, 177, 240, 0.25);
}
body.appbuilder-dark .workflow_palette_title {
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .workflow_palette_desc {
	color: var(--fg-muted, #a0a0a0);
}
.workflow_designer_canvas_wrap {
	flex: 1 1 auto;
	height: 100%;
	min-width: 0;
	position: relative;
	overflow: hidden;        /* defensive — the GoJS canvas inside
	                            manages its own scrolling and shouldn't
	                            ever leak to a wrap-level scrollbar */
}
.workflow_designer_canvas {
	width: 100%;
	height: 100%;
	background-color: #FAF8F5;
}
/* Suppress the browser focus ring that appears around the GoJS
   <canvas> when the diagram receives keyboard focus (Delete / etc.).
   Same trick used by .diagram_container canvas in ChapsV_AppSFA.css. */
.workflow_designer_canvas canvas {
	outline: none;
	-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}

/* Locked / published workflow — palette and properties panel
   are disabled so the user can't author changes. The diagram
   itself is locked via go.Diagram.isReadOnly (still allows pan,
   zoom, and selection). The Stop button in the top bar stays
   live so the user can unlock at any time. */
.workflow_designer_readonly .workflow_designer_palette {
	pointer-events: none;
	opacity: 0.45;
	filter: grayscale(0.5);
}
.workflow_designer_readonly .workflow_designer_props_body input,
.workflow_designer_readonly .workflow_designer_props_body textarea,
.workflow_designer_readonly .workflow_designer_props_body select,
.workflow_designer_readonly .workflow_designer_props_body button,
.workflow_designer_readonly .workflow_designer_props_body .wf_handle,
.workflow_designer_readonly .workflow_designer_props_body .wf_edit,
.workflow_designer_readonly .workflow_designer_props_body .wf_delete,
.workflow_designer_readonly .workflow_designer_props_body .wf_list_add,
.workflow_designer_readonly .workflow_designer_props_body .wf_row {
	pointer-events: none;
}
.workflow_designer_readonly .workflow_designer_props_body input,
.workflow_designer_readonly .workflow_designer_props_body textarea,
.workflow_designer_readonly .workflow_designer_props_body select {
	background-color: #ECE9E2;
	color: #888;
}
body.appbuilder-dark .workflow_designer_readonly .workflow_designer_props_body input,
body.appbuilder-dark .workflow_designer_readonly .workflow_designer_props_body textarea,
body.appbuilder-dark .workflow_designer_readonly .workflow_designer_props_body select {
	background-color: var(--bg-strong, #242424);
	color: var(--fg-muted, #a0a0a0);
}
.workflow_designer_readonly .wf_list_add,
.workflow_designer_readonly .wf_edit,
.workflow_designer_readonly .wf_delete,
.workflow_designer_readonly .wf_handle {
	opacity: 0.5;
}

/* Right-side properties panel + drag handle. Hidden by default;
   the toggle in the top bar flips `.visible`. Width persists on
   the instance via _propsWidth (clamped 180-600 in JS). */
/* The splitter is a 1px visible line, but its hit area is widened
   horizontally via a transparent ::before so it stays grabbable
   without looking like a thick bar. */
.workflow_designer_splitter,
.ontology_designer_splitter {
	flex: 0 0 1px;
	height: 100%;
	background-color: #e2e2e2;
	cursor: ew-resize;   /* match w2ui's resize cursor */
	user-select: none;
	display: none;
	position: relative;
	transition: background-color 0.12s ease;
}
.workflow_designer_splitter::before,
.ontology_designer_splitter::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: -3px;
	right: -3px;
}
.workflow_designer_splitter:hover,
.ontology_designer_splitter:hover { background-color: #4a90e2; }
.workflow_designer_splitter.visible,
.ontology_designer_splitter.visible { display: block; }

.workflow_designer_props {
	flex: 0 0 500px;
	height: 100%;
	background-color: #F2F0EC;
	overflow: hidden;
	display: none;
	min-width: 0;
	flex-direction: column;
}
/* Prevent any w2field('list') helper inside the props panel
   from pushing horizontal overflow up the layout chain. The
   helper carries an inline `width: NNNpx` set at init time
   based on the input's then-measured width. When the panel
   later reflows (textarea resize, internal scrollbar
   appearing/disappearing) that inline width can exceed the
   shrunken container — `max-width: 100%` keeps it bounded.
   Same defensive treatment for the visible w2field input
   that w2ui sets to width:100% but whose padding/border can
   still spill if no max-width is set. */
.workflow_designer_props .w2ui-field-helper {
	max-width: 100% !important;
	box-sizing: border-box !important;
}
.workflow_designer_props .workflow_designer_props_field input.w2ui-input,
.workflow_designer_props .workflow_designer_props_field input.w2ui-select {
	max-width: 100%;
	box-sizing: border-box;
}
/* Defensive horizontal clip on each section body so any
   stray overflow inside one section can never propagate to
   the panel's outer scroll context. */
.workflow_designer_props .workflow_props_section_body {
	overflow-x: hidden;
}
.workflow_designer_props.visible { display: flex; }

.workflow_designer_props_header {
	padding: 12px 14px 10px 14px;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: #555;
	border-bottom: 1px solid #e2e2e2;
}
.workflow_designer_props_body {
	padding: 0;
}

/* Phase 0 — right-panel tab strip (Properties / Chat / History).
   The strip itself is a w2tabs widget so it inherits the same look
   and dark-mode treatment as the top navigation tabs. We only need
   the host sizing rules + the per-tab body layout here.
   Ontology tabs share the same rules via twin selectors. */
.workflow_designer_props_tabbar,
.ontology_designer_props_tabbar {
	flex: 0 0 auto;
	border-bottom: 1px solid #e2e2e2;
	font-family: OpenSans, sans-serif;
}
.workflow_designer_props_tabbody,
.ontology_designer_props_tabbody {
	flex: 1 1 auto;
	overflow-y: auto;
	overflow-x: hidden;
	min-height: 0;
}
/* Chat tab body wraps a Builder_Editor.GetChatHTML() container —
   that container is already a flex column (textarea pinned, scroll
   list above), so the wrapper just needs to fill available height. */
.workflow_designer_props_tabbody_chat,
.workflow_designer_props_tabbody_history {
	display: flex;
	flex-direction: column;
}
.workflow_designer_props_tabbody_chat > div {
	flex: 1 1 auto;
	min-height: 0;
}
.workflow_history_list {
	padding: 8px 12px;
	display: flex;
	flex-direction: column;
	gap: 4px;
	font-family: OpenSans, sans-serif;
}
.workflow_history_entry {
	font-size: 12px;
	color: #555;
	padding: 4px 6px;
	border-left: 2px solid #d0d0d0;
}
.workflow_history_row {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: OpenSans, sans-serif;
}
.workflow_history_text {
	flex: 1 1 auto;
}
.workflow_history_toggle {
	flex: 0 0 auto;
	font-size: 11px;
	color: #888;
	cursor: pointer;
	user-select: none;
	padding: 2px 6px;
	border-radius: 3px;
	outline: none;
}
.workflow_history_toggle:hover { background: rgba(0, 0, 0, 0.04); color: #333; }
.workflow_history_toggle:focus { background: rgba(0, 0, 0, 0.06); }
.workflow_history_toggle .fa { font-size: 10px; margin-right: 4px; }
.workflow_history_details {
	margin: 4px 0 6px 14px;
	padding: 8px 10px;
	background: rgba(0, 0, 0, 0.03);
	border-left: 2px solid #d0d0d0;
	border-radius: 0 3px 3px 0;
	font-family: Consolas, "Courier New", monospace;
	font-size: 11px;
	color: #444;
	white-space: pre-wrap;
	word-break: break-word;
	max-height: 280px;
	overflow: auto;
}
body.appbuilder-dark .workflow_history_toggle { color: #999; }
body.appbuilder-dark .workflow_history_toggle:hover { background: rgba(255, 255, 255, 0.06); color: #e0e0e0; }
body.appbuilder-dark .workflow_history_toggle:focus { background: rgba(255, 255, 255, 0.10); }
body.appbuilder-dark .workflow_history_details {
	background: rgba(255, 255, 255, 0.04);
	border-left-color: #3a3a3a;
	color: #c8c8c8;
}
.workflow_history_warning {
	color: #8a6d3b;
	border-left-color: #f0c674;
	background-color: rgba(240, 198, 116, 0.10);
}
body.appbuilder-dark .workflow_history_warning {
	color: #f0c674;
	border-left-color: #8a6d3b;
	background-color: rgba(240, 198, 116, 0.06);
}
.workflow_history_empty {
	padding: 16px;
	color: #888;
	font-size: 12px;
	font-style: italic;
	font-family: OpenSans, sans-serif;
}
.workflow_chat_loading {
	padding: 16px;
	color: #888;
	font-size: 12px;
	font-style: italic;
	font-family: OpenSans, sans-serif;
}
body.appbuilder-dark .workflow_chat_loading { color: #888; }
body.appbuilder-dark .workflow_designer_props_tabbar,
body.appbuilder-dark .ontology_designer_props_tabbar {
	border-bottom-color: #2a2a2a;
}
body.appbuilder-dark .workflow_history_entry {
	color: #c0c0c0;
	border-left-color: #444;
}
body.appbuilder-dark .workflow_history_empty {
	color: #888;
}

/* Phase C — Orchestro proposal card (rendered inside the Chat tab
   when the agent emits a structural edit set that needs explicit
   user approval). Sits between chat bubbles, so it inherits the
   chat body's font + spacing. Apply/Discard use w2ui-btn so they
   pick up the project's button skin in both light and dark mode. */
.wf-proposal-card {
	border: 1px solid #d6d6d6;
	border-radius: 8px;
	padding: 10px 12px;
	margin: 6px 0;
	background: #f8f9fc;
	font-family: OpenSans, sans-serif;
	font-size: 13px;
}
.wf-proposal-card-title {
	font-weight: 600;
	margin-bottom: 6px;
	color: #1f6feb;
}
.wf-proposal-card-title .fa { margin-right: 6px; }
.wf-proposal-card-lines {
	margin: 4px 0 10px 18px;
	padding: 0;
	color: #333;
}
.wf-proposal-card-lines li { margin: 2px 0; }
.wf-proposal-card-actions { display: flex; gap: 8px; }
.wf-proposal-card-busy { opacity: 0.6; pointer-events: none; }
body.appbuilder-dark .wf-proposal-card {
	border-color: #3a3a3a;
	background: #232323;
}
body.appbuilder-dark .wf-proposal-card-title { color: #7AB1F0; }
body.appbuilder-dark .wf-proposal-card-lines { color: #d8d8d8; }

/* Collapsible section inside the properties panel. Mirrors the
   palette group pattern — header + body, chevron rotates and
   max-height collapses on `.collapsed`. Section ids are stable
   per kind so collapse state survives selection changes. */
.workflow_props_section {
	border-bottom: 1px solid #e2e2e2;
}
.workflow_props_section_header {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 14px;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: #555;
	cursor: pointer;
	user-select: none;
	background-color: #ECE9E2;
}
.workflow_props_section_header:hover { background-color: #E4E0D7; }
.workflow_props_section_title { flex: 1 1 auto; }
.workflow_props_section_count {
	min-width: 20px;
	padding: 1px 7px;
	background-color: #d6d2c6;
	color: #555;
	font: 700 11px OpenSans, sans-serif;
	letter-spacing: 0;
	border-radius: 10px;
	text-align: center;
}
body.appbuilder-dark .workflow_props_section_count {
	background-color: var(--bg-strong, #242424);
	color: var(--fg-muted, #a0a0a0);
}
.workflow_props_chevron {
	font-size: 11px;
	width: 12px;
	color: #888;
	transition: transform 0.15s ease;
}
.workflow_props_section.collapsed .workflow_props_chevron {
	transform: rotate(-90deg);
}
.workflow_props_section_body {
	max-height: 2000px;
	overflow: hidden;
	padding: 12px 14px;
	transition: max-height 0.2s ease, padding 0.2s ease;
}
.workflow_props_section.collapsed .workflow_props_section_body {
	max-height: 0;
	padding-top: 0;
	padding-bottom: 0;
}

body.appbuilder-dark .workflow_props_section {
	border-bottom-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_props_section_header {
	background-color: var(--bg, #1a1a1a);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .workflow_props_section_header:hover {
	background-color: var(--bg-hover, #2a2a2a);
}

/* ============================================================
 * Generic list editor used inside properties sections
 * (Screen → Fields, Actions; reusable for future activity types).
 * Each row: drag handle + name + meta + edit/delete icons.
 * ============================================================ */
/* Type-edit dialog: the "Properties" slot is rendered inside
   the form via a w2form `type: "html"` field, so its layout
   sits naturally under Description and above the popup's
   Cancel/Ok footer. Fixed height; the inner list scrolls. */
.wf-type-properties-host {
	/* Lock width to fill the form-row content area and never
	   let it shrink due to a flex parent or content overflow.
	   Without this, maximizing the popup leaves the host at
	   its initial render width (≈ small), creating a wide
	   gutter on the right + a horizontal scrollbar. */
	width: 100%;
	max-width: 100%;
	min-width: 0;
	height: 320px;
	display: flex;
	flex-direction: column;
	border: 1px solid #d9d6d0;
	border-radius: 6px;
	padding: 10px;
	box-sizing: border-box;
	/* Match the input/textarea fill used on other w2form fields
	   in light mode so the Properties container reads as another
	   field surface. */
	background-color: #F8FAFA;
}
/* Suppress focus indicators on the Properties row by:
   1. Always pinning outline-color to transparent on every
      element in the row (whatever the browser/w2form reserved
      as outline width/style still gets drawn — just invisible).
   2. Pinning box-shadow to "none" on focus states for
      descendants OTHER than the host (host keeps its own
      shadow-less default; we don't touch its border).
   3. Pinning border-color to transparent on focus for
      descendants OTHER than the host (kills any border-color
      flip to blue on a focused .wf_row / button / etc.).
   Geometry is preserved on every layer so click doesn't
   trigger a 1 px shift. */
html body div.wf-no-focus,
html body div.wf-no-focus *,
html body .w2ui-field:has(#WfTypePropsHost),
html body .w2ui-field:has(#WfTypePropsHost) *,
html body .w2ui-field:has(#OntologyAttrBindingsSlot),
html body .w2ui-field:has(#OntologyAttrBindingsSlot) * {
	outline-color: transparent !important;
}
html body div.wf-no-focus *:not(.wf-type-properties-host):focus,
html body div.wf-no-focus *:not(.wf-type-properties-host):focus-within,
html body div.wf-no-focus *:not(.wf-type-properties-host):focus-visible,
html body .w2ui-field:has(#WfTypePropsHost) *:not(.wf-type-properties-host):focus,
html body .w2ui-field:has(#WfTypePropsHost) *:not(.wf-type-properties-host):focus-within,
html body .w2ui-field:has(#WfTypePropsHost) *:not(.wf-type-properties-host):focus-visible,
html body .w2ui-field:has(#OntologyAttrBindingsSlot) *:not(.wf-type-properties-host):focus,
html body .w2ui-field:has(#OntologyAttrBindingsSlot) *:not(.wf-type-properties-host):focus-within,
html body .w2ui-field:has(#OntologyAttrBindingsSlot) *:not(.wf-type-properties-host):focus-visible {
	border-color: transparent !important;
	box-shadow: none !important;
}
/* Lock the host's border color across all states + make any
   focus outline invisible without touching its geometry. */
.wf-type-properties-host,
.wf-type-properties-host:focus,
.wf-type-properties-host:focus-visible,
.wf-type-properties-host:focus-within {
	border-color: #d9d6d0 !important;
	outline-color: transparent !important;
}
body.appbuilder-dark .wf-type-properties-host,
body.appbuilder-dark .wf-type-properties-host:focus,
body.appbuilder-dark .wf-type-properties-host:focus-visible,
body.appbuilder-dark .wf-type-properties-host:focus-within {
	border-color: var(--bd, #3a3a3a) !important;
}
/* Empty-state placeholder inside the host — slightly darker
   in dark mode so it reads at the same visual weight as
   "No types yet" in the workflow Properties panel. */
body.appbuilder-dark .wf-type-properties-host .wf_list_empty {
	color: #6e6e6e;
}
.wf-type-properties-host > .wf-section-description {
	flex: 0 0 auto;
	margin-bottom: 8px;
}
.wf-type-properties-host > .wf_list {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	/* Always reserve scrollbar space — prevents the host's
	   content from shifting horizontally by ~1 px when a focus
	   change inside causes the scrollbar to materialize. */
	scrollbar-gutter: stable;
}
.wf-type-properties-host > .wf_list_add {
	flex: 0 0 auto;
	margin-top: 8px;
	align-self: flex-start;
}
body.appbuilder-dark .wf-type-properties-host {
	/* Match the input/textarea fill used on other w2form fields
	   in dark mode so the Properties container reads as another
	   field surface. */
	background-color: #2B2B2B;
	border-color: var(--bd, #3a3a3a);
}
/* Ontology Bindings section — same class as the workflow Type
   dialog's Properties, but 100 px shorter since a concept
   attribute typically carries fewer bindings than a Type has
   properties. */
#OntologyAttrBindingsSlot.wf-type-properties-host { height: 220px; }

/* In-popup sub-view header for the Type-edit dialog and the
   Ontology attribute dialog — shown above the property/binding
   form when the user clicks Add/Edit on a nested row. Same
   Back-button pattern as the Group Members user-picker view. */
.wf-typedit-subhead {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-bottom: 12px;
}
.wf-typedit-subtitle {
	font: 700 13px OpenSans, sans-serif;
	color: #27251e;
}
body.appbuilder-dark .wf-typedit-subtitle { color: var(--fg-strong, #e6e6e6); }

/* Optional helper paragraph rendered at the top of a section
   body — explains the section's purpose to the user. */
.wf-section-description {
	font: 12px OpenSans, sans-serif;
	color: #777;
	line-height: 1.5;
	margin-bottom: 12px;
}
.wf-section-description code {
	font-family: monospace;
	background-color: #ECE9E2;
	padding: 1px 5px;
	border-radius: 3px;
	font-size: 11px;
}
body.appbuilder-dark .wf-section-description { color: var(--fg-muted, #a0a0a0); }

/* ==============================================================
 * Get activity — filter list in the (narrow) properties panel.
 * Each row is a compact, read-only summary:
 *   [logic chip] column-label op "value preview" [edit][×]
 * Editing pops a roomy modal (wf-filter-dialog) so long
 * expressions / long literals don't get cramped.
 * ============================================================== */
.wf-get-filters-list {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin-top: 6px;
	margin-bottom: 8px;
}
.wf-get-empty {
	font: italic 12px OpenSans, sans-serif;
	color: #999;
	padding: 8px 6px;
}
.wf-get-summary-row {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 6px;
	background-color: #FAFAFA;
	border: 1px solid #ECECEC;
	border-radius: 4px;
	min-width: 0;
}
.wf-get-summary-body {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 6px;
	font: 12px OpenSans, sans-serif;
	color: #27251E;
}
.wf-get-summary-col {
	font-weight: 600;
	color: #2c2c2c;
}
.wf-get-summary-op {
	color: #777;
	font-size: 11px;
	background-color: #ECECEC;
	padding: 1px 6px;
	border-radius: 3px;
}
.wf-get-summary-literal {
	color: #444;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf-get-summary-expr {
	/* Green — matches the Get activity widget color so the
	   designer's row pills echo the diagram node's accent. */
	color: #2E7D32;
	background-color: rgba(46, 125, 50, 0.10);
	padding: 1px 6px;
	border-radius: 3px;
	font: 11px Consolas, monospace;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf-get-summary-novalue { color: #999; font-style: italic; }
.wf-get-summary-edit,
.wf-get-summary-del {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	padding: 0;
	border: 1px solid transparent;
	background-color: transparent;
	border-radius: 3px;
	cursor: pointer;
	color: #777;
}
.wf-get-summary-edit:hover { color: #2c2c2c; background-color: #ECECEC; }
.wf-get-summary-del:hover  { color: #C0392B; background-color: rgba(192, 57, 43, 0.08); }

.wf-get-row-logic,
.wf-get-row-logic-spacer {
	/* Green to match the Get activity widget color (same as
	   .wf-get-summary-expr) — the AND/OR connector belongs to
	   the Get row, so it should pick up the same accent. */
	flex: 0 0 36px;
	font: 600 10px OpenSans, sans-serif;
	color: #2E7D32;
	background-color: rgba(46, 125, 50, 0.10);
	padding: 2px 6px;
	border-radius: 3px;
	text-align: center;
	letter-spacing: 0.4px;
}
.wf-get-row-logic-spacer { background-color: transparent; visibility: hidden; }

.wf-get-add-row {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 5px 12px;
	background-color: #FFFFFF;
	border: 1px dashed #B7B5AE;
	border-radius: 4px;
	cursor: pointer;
	font: 12px OpenSans, sans-serif;
	color: #555;
}
.wf-get-add-row:hover { background-color: #F1F1F1; border-color: #888; }

/* Dark mode for the side-panel summary list */
body.appbuilder-dark .wf-get-summary-row {
	background-color: var(--bg-alt, #242424);
	border-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .wf-get-summary-body  { color: var(--fg, #c8c8c8); }
body.appbuilder-dark .wf-get-summary-col   { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .wf-get-summary-op    { color: var(--fg-muted, #a0a0a0); background-color: var(--bg, #1a1a1a); }
body.appbuilder-dark .wf-get-summary-literal { color: var(--fg, #c8c8c8); }
body.appbuilder-dark .wf-get-summary-expr  { color: #A5D6A7; background-color: rgba(76, 175, 80, 0.20); }
body.appbuilder-dark .wf-get-summary-edit:hover { color: var(--fg-strong, #e6e6e6); background-color: var(--bg, #1a1a1a); }
body.appbuilder-dark .wf-get-row-logic     { color: #A5D6A7; background-color: rgba(76, 175, 80, 0.20); }
body.appbuilder-dark .wf-get-add-row {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .wf-get-add-row:hover { background-color: var(--bg-hover, #2a2a2a); }

/* Filter editor modal — uses a standard w2form, so no
   bespoke CSS is needed. The form picks up the project's
   default form/input styling for both light and dark modes. */

/* Native-button picklist used by the Select activity's
   Appearance > Mode field. Looks like a w2field('list') input
   (text + caret) but anchors its dropdown via w2menu.show with
   an explicit `anchor: e.currentTarget`, which sidesteps the
   stale-anchor bug that plagues w2field('list') inside a
   scrollable container. */
.wf-pickbtn {
	width: 100%;
	box-sizing: border-box;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 6px;
	padding: 6px 8px;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	font: 12px OpenSans, sans-serif;
	background-color: #ffffff;
	color: #27251e;
	cursor: pointer;
	text-align: left;
}
.wf-pickbtn:focus,
.wf-pickbtn:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
}
.wf-pickbtn-text {
	flex: 1 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf-pickbtn-caret {
	flex: 0 0 auto;
	color: #888;
	font-size: 12px;
}
body.appbuilder-dark .wf-pickbtn {
	/* --bg-input matches the dark-gray background applied to
	   <input>/<textarea> via the catch-all dark-mode rule
	   (`html body.appbuilder-dark input:not(...) { ... }`).
	   Without this the button would inherit the near-black --bg
	   and stand out against the surrounding inputs.
	   #505050 matches the same catch-all's `border:1px solid
	   var(--border-strong)` — which resolves to that lighter
	   gray — so the button border reads identically to a real
	   text input next to it. */
	background-color: var(--bg-input, #2b2b2b);
	border-color: var(--border-strong, #505050);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .wf-pickbtn-caret {
	color: var(--fg-muted, #a0a0a0);
}


/* ==============================================================
 * Select activity card — list of pickable entries inside the
 * standard .confirm-msg shell. Rows are stacked (name on top,
 * subtitle muted underneath); selected rows get the project's
 * accent blue tint + a filled checkbox/radio icon.
 *
 * Long lists scroll inside the card via max-height; short
 * lists size to their natural height.
 * ============================================================== */
.wf-select-list {
	margin-top: 8px;
	max-height: 360px;
	overflow-y: auto;
	border: 1px solid #ECECEC;
	border-radius: 6px;
	background-color: #FFFFFF;
}
/* The fa-list-ul glyph is visually heavier than the question /
   exclamation glyphs the other confirm-style cards use, so it
   crowds the 28-px disc. Trim it down a bit for the Select
   card only. */
.builder-thread-body-answer .wf-select-card .confirm-msg-icon {
	font-size: 13px;
}
.wf-select-row {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 8px 10px;
	cursor: pointer;
	border-bottom: 1px solid #ECECEC;
	transition: background-color 0.08s ease;
}
.wf-select-row:last-child { border-bottom: 0; }
.wf-select-row:hover { background-color: #F8F8F8; }
.wf-select-row.wf-select-row-on {
	background-color: rgba(38, 157, 240, 0.08);
}
.wf-select-check {
	flex: 0 0 auto;
	font-size: 14px;
	color: #999;
	margin-top: 2px;
}
.wf-select-row.wf-select-row-on .wf-select-check {
	color: rgb(38, 157, 240);
}
.wf-select-row-text {
	flex: 1 1 auto;
	min-width: 0;
}
.wf-select-row-name {
	font-size: 13px;
	font-weight: 600;
	color: #27251E;
	line-height: 1.3;
}
.wf-select-row-sub {
	font-size: 11px;
	color: #777;
	line-height: 1.4;
	margin-top: 2px;
}
.wf-select-empty {
	font-style: italic;
	color: #999;
	padding: 8px 0;
}
/* Phase H — per-row zoom icon, visible when the Select activity's
   `entity` slot is set. Click opens the entry via the same OpenEntry
   path refTo clicks use. Subtle in default state so it doesn't
   compete with the row name; tints blue on hover for the affordance. */
.wf-select-row-zoom {
	flex: 0 0 auto;
	font-size: 12px;
	color: #B5B5B5;
	margin-top: 3px;
	padding: 2px 4px;
	border-radius: 3px;
	cursor: pointer;
	transition: color 0.08s ease, background-color 0.08s ease;
}
.wf-select-row-zoom:hover {
	color: rgb(38, 157, 240);
	background-color: rgba(38, 157, 240, 0.10);
}
.wf-select-count {
	font-size: 11px;
	opacity: 0.85;
	margin-left: 4px;
}

/* Use --bg-input (#2b2b2b) — slightly LIGHTER than the
   surrounding card (--bg-elev #242424) so the list reads as a
   raised panel sitting on the card, not a near-black hole
   punched into it. Soft semi-transparent row dividers + a
   barely-there hover keep the list visually calm; the
   blue-tinted selection still pops. */
body.appbuilder-dark .wf-select-list {
	background-color: var(--bg-input, #2b2b2b);
	border-color: rgba(255, 255, 255, 0.06);
}
body.appbuilder-dark .wf-select-row { border-bottom-color: rgba(255, 255, 255, 0.05); }
body.appbuilder-dark .wf-select-row:hover { background-color: rgba(255, 255, 255, 0.04); }
body.appbuilder-dark .wf-select-row.wf-select-row-on { background-color: rgba(38, 157, 240, 0.18); }
body.appbuilder-dark .wf-select-row-name { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .wf-select-row-sub  { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .wf-select-empty    { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .wf-select-row.wf-select-row-on .wf-select-check { color: #7AB1F0; }
body.appbuilder-dark .wf-select-row-zoom { color: var(--fg-muted, #707070); }
body.appbuilder-dark .wf-select-row-zoom:hover {
	color: #7AB1F0;
	background-color: rgba(38, 157, 240, 0.18);
}

/* Code activity — label row holds the field title on the left
   and the path-picker / helpers buttons on the right. Buttons
   re-use the .wf_pp_inline_btn pill styling but sit inline
   inside the label rather than over a textarea.
   Specificity bumped via .workflow_designer_props_field so the
   flex layout wins over the generic `label { display:block }`
   rule (otherwise the helpers stack under the label text). */
.workflow_designer_props_field label.wf-code-label {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
}
.wf-code-label-helpers {
	display: inline-flex;
	gap: 4px;
	margin-left: auto;     /* hard-right within the flex row */
}
.wf-code-label-helpers .wf_pp_inline_btn {
	position: static;      /* override the default absolute positioning */
}

/* ==============================================================
 * Code activity — CodeMirror dark-mode styling.
 * The neo theme that CodeMirror loads by default is light-only;
 * scoping these overrides to body.appbuilder-dark gives the
 * editor a real dark surface (matching the rest of the workflow
 * properties panel) plus a blue accent on the line-number
 * gutter so the digits read clearly against the dark gutter.
 * ============================================================== */
body.appbuilder-dark .workflow_props_section_body .CodeMirror {
	background-color: #1a1a1a;
	color: #e6e6e6;
	border: 1px solid #3a3a3a;
}
body.appbuilder-dark .workflow_props_section_body .CodeMirror-gutters {
	background-color: #242424;
	border-right: 1px solid #3a3a3a;
}
body.appbuilder-dark .workflow_props_section_body .CodeMirror-linenumber {
	color: #4a90e2;
}
body.appbuilder-dark .workflow_props_section_body .CodeMirror-cursor {
	border-left-color: #e6e6e6;
}
body.appbuilder-dark .workflow_props_section_body .CodeMirror-selected {
	background-color: rgba(74, 144, 226, 0.30);
}
body.appbuilder-dark .workflow_props_section_body .CodeMirror-matchingbracket {
	color: #81C784 !important;
	font-weight: 600;
}
/* Active-line highlight — subtle so it doesn't fight with
   the cursor caret. */
body.appbuilder-dark .workflow_props_section_body .CodeMirror-activeline-background {
	background-color: rgba(74, 144, 226, 0.06);
}

/* DB console SQL editor + Trade Script editor — same dark
   treatment as the workflow property panel CodeMirror. Scoped
   under #dbcons-root (SQL) and .tradescript_editor_body_inner
   (Pine) so any future code-editor panel picks up the same
   look by joining the selector. fromTextArea() drops the
   textarea's class on the wrapper so we can't scope by that. */
body.appbuilder-dark #dbcons-root .CodeMirror,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror,
body.appbuilder-dark .charts_pine_editor .CodeMirror {
	background-color: #1a1a1a;
	color: #e6e6e6;
	border: 1px solid #3a3a3a;
}
body.appbuilder-dark #dbcons-root .CodeMirror-gutters,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-gutters,
body.appbuilder-dark .charts_pine_editor .CodeMirror-gutters {
	background-color: #242424;
	border-right: 1px solid #3a3a3a;
}
body.appbuilder-dark #dbcons-root .CodeMirror-linenumber,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-linenumber,
body.appbuilder-dark .charts_pine_editor .CodeMirror-linenumber {
	color: #4a90e2;
}
body.appbuilder-dark #dbcons-root .CodeMirror-cursor,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-cursor,
body.appbuilder-dark .charts_pine_editor .CodeMirror-cursor {
	border-left-color: #e6e6e6;
}
body.appbuilder-dark #dbcons-root .CodeMirror-selected,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-selected,
body.appbuilder-dark .charts_pine_editor .CodeMirror-selected {
	background-color: rgba(74, 144, 226, 0.30);
}
body.appbuilder-dark #dbcons-root .CodeMirror-matchingbracket,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-matchingbracket,
body.appbuilder-dark .charts_pine_editor .CodeMirror-matchingbracket {
	color: #81C784 !important;
	font-weight: 600;
}
body.appbuilder-dark #dbcons-root .CodeMirror-activeline-background,
body.appbuilder-dark .tradescript_editor_body_inner .CodeMirror-activeline-background,
body.appbuilder-dark .charts_pine_editor .CodeMirror-activeline-background {
	background-color: rgba(74, 144, 226, 0.06);
}

/* Dashboard widget editor SQL CodeMirror — same dark treatment
   as the DB console editor, scoped under the dialog's form. */
body.appbuilder-dark .dashboard-edit-form .CodeMirror {
	background-color: #1a1a1a;
	color: #e6e6e6;
	border: 1px solid #3a3a3a;
}
body.appbuilder-dark .dashboard-edit-form .CodeMirror-gutters {
	background-color: #242424;
	border-right: 1px solid #3a3a3a;
}
body.appbuilder-dark .dashboard-edit-form .CodeMirror-linenumber       { color: #4a90e2; }
body.appbuilder-dark .dashboard-edit-form .CodeMirror-cursor           { border-left-color: #e6e6e6; }
body.appbuilder-dark .dashboard-edit-form .CodeMirror-selected         { background-color: rgba(74, 144, 226, 0.30); }
body.appbuilder-dark .dashboard-edit-form .CodeMirror-matchingbracket  { color: #81C784 !important; font-weight: 600; }
body.appbuilder-dark .dashboard-edit-form .CodeMirror-activeline-background { background-color: rgba(74, 144, 226, 0.06); }

/* ==============================================================
 * Widget editor — "Describe the widget" card.
 * Sits at the top of the form, visually isolated as the primary
 * entry point (NL → widget). Light/dark variants with a rounded
 * border + subtle tint keeping the same magic-icon accent already
 * used by the prompt bar. */
.dashboard-edit-prompt-card {
	margin: 4px 0 14px 0;
	padding: 10px 12px 12px 12px;
	border: 1px solid #d6d3cd;
	border-radius: 8px;
	background-color: #faf8f3;
}
.dashboard-edit-prompt-card-title {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 12px;
	color: #555;
	margin-bottom: 6px;
	letter-spacing: 0.2px;
}
.dashboard-edit-prompt-card-title .fa { color: #4a90e2; }
.dashboard-edit-prompt-card-hint {
	margin-top: 6px;
	font-size: 11px;
	color: #888;
	line-height: 1.35;
}
body.appbuilder-dark .dashboard-edit-prompt-card {
	border-color: #3a3a3a;
	background-color: #232323;
}
body.appbuilder-dark .dashboard-edit-prompt-card-title      { color: #c8c8c8; }
body.appbuilder-dark .dashboard-edit-prompt-card-title .fa  { color: #4a90e2; }
body.appbuilder-dark .dashboard-edit-prompt-card-hint       { color: #9a9a9a; }

/* ==============================================================
 * Assignment row in the right-panel list — mirrors the Edit
 * Filter row layout (.wf-get-summary-*) so both designer lists
 * read the same way. Each list pill is colored to match its
 * activity widget in the diagram:
 *   Assignment row pill → violet  (rgba(142,91,217,0.10) / #6A3FB0)
 *   Filter (Get) row pill → green (rgba(46,125,50,0.10) / #2E7D32)
 * That way the side-panel chips read as the diagram nodes'
 * accent color at a glance.
 * ============================================================== */
.wf-assign-row .wf-assign-summary-body {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 6px;
	font: 12px OpenSans, sans-serif;
	color: #27251E;
}
.wf-assign-row .wf-assign-summary-target {
	font-weight: 600;
	color: #2c2c2c;
}
.wf-assign-row .wf-assign-summary-op {
	color: #777;
	font-size: 11px;
	background-color: #ECECEC;
	padding: 1px 6px;
	border-radius: 3px;
}
.wf-assign-row .wf-assign-summary-literal {
	color: #444;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf-assign-row .wf-assign-summary-pill {
	/* Violet — matches the Assignment activity widget color
	   in the diagram so the row pills echo the node accent. */
	color: #6A3FB0;
	background-color: rgba(142, 91, 217, 0.10);
	padding: 1px 6px;
	border-radius: 3px;
	font: 11px Consolas, monospace;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Dark-mode parity */
body.appbuilder-dark .wf-assign-row .wf-assign-summary-body    { color: var(--fg, #c8c8c8); }
body.appbuilder-dark .wf-assign-row .wf-assign-summary-target  { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .wf-assign-row .wf-assign-summary-op      { color: var(--fg-muted, #a0a0a0); background-color: var(--bg, #1a1a1a); }
body.appbuilder-dark .wf-assign-row .wf-assign-summary-literal { color: var(--fg, #c8c8c8); }
body.appbuilder-dark .wf-assign-row .wf-assign-summary-pill    { color: #C8B0F0; background-color: rgba(142, 91, 217, 0.22); }

/* ==============================================================
 * Workflow "Long description & routing hints" section — sits in
 * the right-side properties panel when no node is selected.
 * Drives Maestro's intent routing.
 * ============================================================== */
.wf-intent-suggest {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 5px 10px;
	margin: 0 0 10px;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	background-color: #ffffff;
	color: #27251e;
	font: 12px OpenSans, sans-serif;
	cursor: pointer;
}
.wf-intent-suggest:hover { background-color: #F1F1F1; }
.wf-intent-suggest[disabled] { opacity: 0.6; cursor: default; }
.wf-intent-suggest .fa { font-size: 11px; color: rgb(38, 157, 240); }

.wf-intent-field {
	margin-bottom: 12px;
}
.wf-intent-label {
	display: block;
	font: 600 11px OpenSans, sans-serif;
	color: #555;
	text-transform: uppercase;
	letter-spacing: 0.4px;
	margin-bottom: 4px;
}
.wf-intent-longdesc {
	width: 100%;
	box-sizing: border-box;
	resize: vertical;
	min-height: 150px;
	padding: 8px 10px;
	font: 13px OpenSans, sans-serif;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	outline: none;
}
.wf-intent-longdesc:focus,
.wf-intent-longdesc:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	border-color: #C0C0C0 !important;
	box-shadow: none !important;
}

.wf-intent-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 6px;
	min-height: 22px;
	margin-bottom: 6px;
}
.wf-intent-chip {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 3px 8px;
	background-color: rgba(38, 157, 240, 0.12);
	color: #1F84C6;
	border-radius: 12px;
	font: 12px OpenSans, sans-serif;
}
.wf-intent-chip-x {
	cursor: pointer;
	font-size: 10px;
	opacity: 0.6;
}
.wf-intent-chip-x:hover { opacity: 1; color: #C0392B; }

.wf-intent-chip-input { margin-bottom: 6px; }
.wf-intent-chip-add {
	width: 100%;
	box-sizing: border-box;
	padding: 6px 10px;
	font: 12px OpenSans, sans-serif;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	outline: none;
	background-color: #ffffff;
}
.wf-intent-chip-add:focus,
.wf-intent-chip-add:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	border-color: #C0C0C0 !important;
	box-shadow: none !important;
}
/* No focus outline — this is a button (opens a menu), not a
   text-entry field. The 2-px blue outline used elsewhere
   reads as "you can type here" which is misleading for an
   action button. */
.wf-intent-entity-trigger:focus,
.wf-intent-entity-trigger:focus-visible {
	outline: none !important;
	box-shadow: none !important;
}
/* Dark-mode parity — same 2px blue outline regardless of mode.
   Anchor with html body so we beat any deep-cascade w2ui rule. */
html body.appbuilder-dark .wf-intent-longdesc:focus,
html body.appbuilder-dark .wf-intent-longdesc:focus-visible,
html body.appbuilder-dark .wf-intent-chip-add:focus,
html body.appbuilder-dark .wf-intent-chip-add:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
}
html body.appbuilder-dark .wf-intent-entity-trigger:focus,
html body.appbuilder-dark .wf-intent-entity-trigger:focus-visible {
	outline: none !important;
	box-shadow: none !important;
}

/* Entity-hints "pick a table" trigger — a button (action).
   Styling mirrors `.wf-intent-suggest` (the "Suggest with AI"
   button) so the two action affordances in this section read
   as the same family. Right-chevron icon to reinforce
   "click to open / act". */
.wf-intent-entity-trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
	box-sizing: border-box;
	padding: 5px 10px;
	font: 12px OpenSans, sans-serif;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	background-color: #ffffff;
	color: #27251e;
	cursor: pointer;
	text-align: left;
}
.wf-intent-entity-trigger:hover:not([disabled]) { background-color: #F1F1F1; }
.wf-intent-entity-trigger[disabled] { opacity: 0.6; cursor: default; }
.wf-intent-entity-trigger .fa { font-size: 11px; color: rgb(38, 157, 240); }


.wf-intent-suggestions {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 6px;
	margin-top: 4px;
}
.wf-intent-suggestion {
	padding: 2px 8px;
	border-radius: 10px;
	border: 1px dashed #C0C0C0;
	color: #777;
	font: 11px OpenSans, sans-serif;
	cursor: pointer;
	user-select: none;
}
.wf-intent-suggestion:hover {
	border-style: solid;
	border-color: rgb(38, 157, 240);
	color: #1F84C6;
}

body.appbuilder-dark .wf-intent-suggest {
	background-color: var(--bg-elev, #242424);
	border-color: var(--border, #333);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .wf-intent-suggest:hover { background-color: var(--bg-hover, #2a2a2a); }
body.appbuilder-dark .wf-intent-label { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .wf-intent-longdesc,
body.appbuilder-dark .wf-intent-chip-add,
body.appbuilder-dark .wf-intent-entity-trigger {
	background-color: var(--bg-elev, #242424);
	border-color: var(--border, #333);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .wf-intent-entity-trigger:hover:not([disabled]) {
	background-color: var(--bg-hover, #2a2a2a);
}
body.appbuilder-dark .wf-intent-chip {
	background-color: rgba(96, 165, 250, 0.18);
	color: rgb(96, 165, 250);
}
body.appbuilder-dark .wf-intent-suggestion {
	border-color: var(--border, #333);
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .wf-intent-suggestion:hover {
	border-color: rgb(96, 165, 250);
	color: rgb(96, 165, 250);
}

/* "Resolves to table: …" / error hint under the entry-path
   input on Create / Update activities. Inherits the same font
   family as the rest of the workflow editor — without an
   explicit family the bare div fell back to the browser's
   serif default. */
.wf-entry-table-hint {
	font: 11px OpenSans, sans-serif;
	color: #888;
	margin-top: 4px;
}
body.appbuilder-dark .wf-entry-table-hint { color: var(--fg-muted, #a0a0a0); }

/* Workflow Debug toggle in the right-side properties panel —
   single checkbox + label pair; lives in its own section so
   it's always findable. */
.wf-debug-toggle {
	display: flex;
	align-items: center;
	gap: 8px;
	font: 12px OpenSans, sans-serif;
	color: #555;
	cursor: pointer;
}
.wf-debug-toggle input { width: 14px; height: 14px; }
body.appbuilder-dark .wf-debug-toggle { color: var(--fg-muted, #a0a0a0); }

/* Trace step — compact diagnostic card distinct from normal
   workflow steps. Single-line clickable header (title is the
   toggle) + collapsed body holding the variables snapshot.
   Purple/violet accent so traces read clearly as "diagnostic,
   not flow" — designers see the conversation rhythm and the
   trace breadcrumbs without confusing them with real activity
   output.

   The wf_summary_toggle delegation already wired in the chat
   container's click handler flips display on the sibling
   .wf-msg-summary-body, so the toggle "just works" with the
   same machinery used by completion summaries. */
.builder-thread-body-answer .wf-trace-card {
	margin-top: 6px;
	border-left: 3px solid #8E5BD9;
	background-color: rgba(142, 91, 217, 0.06);
	border-radius: 4px;
	font-family: OpenSans, sans-serif;
	max-width: 100%;
	box-sizing: border-box;
}
.builder-thread-body-answer .wf-trace-toggle {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 10px;
	cursor: pointer;
	font-size: 12px;
	color: #6A3FB0;
}
.builder-thread-body-answer .wf-trace-toggle:hover {
	background-color: rgba(142, 91, 217, 0.10);
}
.builder-thread-body-answer .wf-trace-icon {
	font-size: 11px;
	color: #8E5BD9;
}
.builder-thread-body-answer .wf-trace-title {
	flex: 1 1 auto;
	font-weight: 600;
	color: #4A2A82;
}
.builder-thread-body-answer .wf-trace-chev {
	flex: 0 0 auto;
	font-size: 11px;
	color: #888;
}
/* Copy-to-clipboard affordance — sits between the title and
   the chevron. Subtle by default (low opacity), brightens on
   hover. Stops propagation in JS so clicking it does NOT
   toggle the body. */
.builder-thread-body-answer .wf-trace-copy {
	flex: 0 0 auto;
	font-size: 11px;
	padding: 2px 6px;
	margin-right: 2px;
	border-radius: 4px;
	cursor: pointer;
	opacity: 0.55;
	color: inherit;
	transition: opacity 0.12s ease, background-color 0.12s ease;
}
.builder-thread-body-answer .wf-trace-copy:hover {
	opacity: 1;
	background-color: rgba(0, 0, 0, 0.06);
}
body.appbuilder-dark .builder-thread-body-answer .wf-trace-copy:hover {
	background-color: rgba(255, 255, 255, 0.08);
}
.builder-thread-body-answer .wf-trace-card-haserrors {
	border-left-color: #C0392B;
	background-color: rgba(192, 57, 43, 0.07);
}
.builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-toggle  { color: #C0392B; }
.builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-title   { color: #5a1a14; }
.builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-icon    { color: #C0392B; }

/* Success variant — workflow_completed reuses the trace card
   shell with a green accent so the completion message reads as
   success, not diagnostic. */
.builder-thread-body-answer .wf-trace-card-success {
	border-left-color: #2E7D32;
	background-color: rgba(46, 125, 50, 0.06);
}
.builder-thread-body-answer .wf-trace-card-success .wf-trace-toggle  { color: #2E7D32; }
.builder-thread-body-answer .wf-trace-card-success .wf-trace-title   { color: #1B4D1F; }
.builder-thread-body-answer .wf-trace-card-success .wf-trace-icon    { color: #2E7D32; }
/* Green hover tint for the success card — without this, the
   generic .wf-trace-toggle:hover paints a violet rgba over the
   green panel, which reads wrong (especially in light mode). */
.builder-thread-body-answer .wf-trace-card-success .wf-trace-toggle:hover {
	background-color: rgba(46, 125, 50, 0.10);
}
/* Specificity bump (.wf-trace-card.wf-trace-card-success) so the
   generic dark .wf-trace-card rule below doesn't reassert the
   violet background/border on the success variant. */
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card.wf-trace-card-success {
	background-color: rgba(76, 175, 80, 0.14);
	border-left-color: #81C784;
}
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-success .wf-trace-toggle { color: #81C784; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-success .wf-trace-icon   { color: #81C784; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-success .wf-trace-title  { color: #C8E6C9; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-success .wf-trace-toggle:hover {
	background-color: rgba(76, 175, 80, 0.18);
}
.builder-thread-body-answer .wf-trace-body {
	padding: 6px 10px 10px;
	background-color: transparent;
}
/* Keep the body transparent in dark mode too, so the card's
   violet (trace) / green (success) / red (errors) tint shows
   through. Without this, the generic dark
   .wf-msg-summary-body rule paints a solid #242424 over the
   tint and the body reads as a flat black panel. */
body.appbuilder-dark .builder-thread-body-answer .wf-trace-body {
	background-color: transparent;
}

/* Dark-mode variant — keep the violet/red accent but on a
   dark surface. */
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card {
	background-color: rgba(142, 91, 217, 0.12);
	border-left-color: #B388E5;
}
body.appbuilder-dark .builder-thread-body-answer .wf-trace-toggle  { color: #B388E5; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-icon    { color: #B388E5; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-title   { color: #D4BFEA; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-chev    { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-haserrors { border-left-color: #ff8a7e; background-color: rgba(231, 76, 60, 0.14); }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-toggle { color: #ff8a7e; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-title  { color: #f8d7d2; }
body.appbuilder-dark .builder-thread-body-answer .wf-trace-card-haserrors .wf-trace-icon   { color: #ff8a7e; }

/* Trace step body — JSON snapshot of the variable bag rendered
   in a monospace <pre>. Same elevated panel as the completion
   summary; just a different content shape. */
.wf-trace-pre {
	margin: 0;
	font: 11px Consolas, monospace;
	white-space: pre-wrap;
	word-break: break-word;
	overflow-wrap: anywhere;
	max-width: 100%;
	box-sizing: border-box;
	max-height: 320px;
	overflow: auto;
}
/* Per-row errors above the snapshot. Lifted styling from the
   ERROR card so the designer reads them as the same kind of
   signal — red title bar, red-tinted background. Compact list
   so a few rows don't dominate the trace card. */
.wf-trace-errors {
	margin-bottom: 8px;
	padding: 6px 8px;
	background-color: rgba(192, 57, 43, 0.10);
	border: 1px solid rgba(192, 57, 43, 0.45);
	border-radius: 4px;
	color: #5a1a14;
}
.wf-trace-errors-title {
	font-size: 11px;
	font-weight: 700;
	color: #C0392B;
	margin-bottom: 4px;
	display: flex;
	align-items: center;
	gap: 5px;
}
.wf-trace-errors-list {
	margin: 0;
	padding-left: 18px;
	font: 11px Consolas, monospace;
	color: #5a1a14;
	word-break: break-word;
	overflow-wrap: anywhere;
}
.wf-trace-errors-list li { margin: 2px 0; }
body.appbuilder-dark .wf-trace-errors {
	background-color: rgba(231, 76, 60, 0.14);
	border-color: rgba(231, 76, 60, 0.55);
	color: #f8d7d2;
}
body.appbuilder-dark .wf-trace-errors-title { color: #ff8a7e; }
body.appbuilder-dark .wf-trace-errors-list  { color: #f8d7d2; }
/* Subtle pulse on the chevron when the trace has errors so the
   designer's eye lands on it without expanding every step. */
.wf-msg-summary-haserrors .wf-msg-summary-toggle .fa-chevron-right {
	color: #C0392B;
}
body.appbuilder-dark .wf-msg-summary-haserrors .wf-msg-summary-toggle .fa-chevron-right {
	color: #ff8a7e;
}
body.appbuilder-dark .wf-section-description code {
	background-color: var(--bg-strong, #242424);
	color: var(--fg-strong, #e6e6e6);
}

.wf_list {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin-bottom: 8px;
}
.wf_list_empty {
	color: #999;
	font: italic 12px OpenSans, sans-serif;
	padding: 6px 4px;
}
.wf_list_add {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 10px;
	border: 1px dashed #c7c2b8;
	border-radius: 6px;
	background: transparent;
	color: #555;
	font: 12px OpenSans, sans-serif;
	cursor: pointer;
	transition: border-color 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}
.wf_list_add:hover {
	border-color: #4a90e2;
	color: #4a90e2;
	background-color: rgba(74, 144, 226, 0.06);
}
.wf_row {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 8px;
	border: 1px solid #d9d6d0;
	border-radius: 6px;
	background-color: #ffffff;
	font: 12px OpenSans, sans-serif;
	color: #27251e;
	user-select: none;
	cursor: default;
}
.wf_row.wf_dragging   { opacity: 0.4; }
.wf_row.wf_drop_target {
	border-color: #4a90e2;
	box-shadow: inset 0 -2px 0 0 #4a90e2;
}
/* Mirror the .wf_edit / .wf_delete icon sizing exactly so all
   three FA glyphs in the row use the same line-height + padding
   and land on the same vertical center. */
.wf_handle {
	color: #b0aba0;
	cursor: grab;
	padding: 4px;
	flex-shrink: 0;
}
.wf_handle:active { cursor: grabbing; }

.wf_row_name {
	font-weight: 600;
	color: #27251e;
	min-width: 80px;
	max-width: 180px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf_row_label {
	color: #666;
	flex: 1 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.wf_row_type {
	color: #888;
	font-size: 11px;
	background-color: #ECE9E2;
	padding: 1px 6px;
	border-radius: 8px;
	text-transform: lowercase;
}
.wf_row_badges {
	display: flex;
	gap: 4px;
	margin-left: auto;
}
.wf_badge {
	font-size: 10px;
	padding: 1px 6px;
	border-radius: 8px;
	white-space: nowrap;
}
.wf_badge_required {
	background-color: #4a90e2;
	color: #ffffff;
	font-weight: 600;
}
.wf_badge_muted    { background-color: #ECE9E2; color: #888; }
.wf_edit, .wf_delete {
	cursor: pointer;
	color: #999;
	padding: 4px;
	border-radius: 4px;
	transition: color 0.12s ease, background-color 0.12s ease;
}
.wf_edit:hover   { color: #4a90e2; background-color: rgba(74, 144, 226, 0.1); }
.wf_delete:hover { color: #D9534F; background-color: rgba(217, 83, 79, 0.1); }

/* Field-edit dialog: type-specific extras block (list items grid /
   refto table picker). */
.wf_subblock {
	margin-top: 12px;
	padding: 10px 12px;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	background-color: #FAF8F5;
}
.wf_subblock_label {
	font: 700 11px OpenSans, sans-serif;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: #666;
	margin-bottom: 8px;
}
.wf_subitems {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin-bottom: 8px;
}
.wf_subrow {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 6px;
	border: 1px solid #d9d6d0;
	border-radius: 6px;
	background-color: #ffffff;
}
.wf_subrow.wf_dragging   { opacity: 0.4; }
.wf_subrow.wf_drop_target {
	border-color: #4a90e2;
	box-shadow: inset 0 -2px 0 0 #4a90e2;
}
.wf_subinput {
	flex: 1 1 auto;
	min-width: 0;
	padding: 4px 6px;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	font: 12px OpenSans, sans-serif;
}
/* Expression textarea — used by Decision's condition section
   and any future expression-driven activity in a properties
   panel (not in a popup; the assignment dialog uses the
   field-edit's panel-switch picker pattern instead). The
   `.wf_pp_inline_btn` (already styled below) sits at the
   right edge as a search-icon affordance — click opens the
   path picker, picked path inserts at the cursor. */
.wf-expr-pickwrap {
	position: relative;
}
/* Position the inline picker button(s) at the textarea's
   top-right corner. Two buttons can sit side by side — the
   right-most is the primary path picker (search icon), and a
   second helpers button (bolt icon) sits to its left. Static
   positioning (no JS reposition needed since the wrap is the
   textarea's only sibling). */
.wf-expr-pickwrap > .wf_pp_inline_btn {
	top: 4px;
	right: 4px;
}
.wf-expr-pickwrap > .wf_pp_inline_btn.wf-expr-helpers {
	right: 30px;     /* sit to the left of the search icon */
}
/* Reserve a wider right gutter on the textarea when both
   buttons are present, so typed text doesn't slip under them. */
.wf-expr-pickwrap > .wf-expr-input {
	padding-right: 56px;
}
.wf-expr-input {
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	resize: vertical;
	max-height: 360px;                  /* hard cap so a designer dragging
	                                       the resize handle can't push the
	                                       panel past its scroll envelope
	                                       and trigger a stray outer
	                                       scrollbar */
	padding: 6px 28px 6px 8px;          /* room for the inline btn */
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	font: 12px Consolas, monospace;
	color: #27251e;
	background-color: #ffffff;
}
/* Match the constraint on the picker wrapper so the absolute
   button stays anchored even when the textarea hits its cap. */
.wf-expr-pickwrap {
	max-width: 100%;
}
body.appbuilder-dark .wf-expr-input {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg-strong, #e6e6e6);
}

.wf_subinput:focus,
.wf_subinput:focus-visible,
.wf_refto_select:focus,
.wf_refto_select:focus-visible,
.wf_pp_header_path:focus,
.wf_pp_header_path:focus-visible,
.wf-objtype-input:focus,
.wf-objtype-input:focus-visible,
.wf-expr-input:focus,
.wf-expr-input:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
}
/* w2field('list') picker (.wf-objtype-input) parks tabindex=-1
   on its visible input and routes focus to a hidden helper —
   same trick as the Screen Data source. Trigger via
   :focus-within on the w2popup body so the wrapped picker
   gets the same outline. */
.w2ui-popup-body :focus-within > input.w2ui-input.w2ui-select,
.w2ui-popup-body input.w2ui-input.w2ui-select.has-focus {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
}
html body.appbuilder-dark .w2ui-popup-body :focus-within > input.w2ui-input.w2ui-select,
html body.appbuilder-dark .w2ui-popup-body input.w2ui-input.w2ui-select.has-focus {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
	border: 1px solid #505050 !important;
}
.wf_refto_select {
	padding: 6px 8px;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	font: 12px OpenSans, sans-serif;
	background-color: #ffffff;
}

/* Dark-mode counterparts */
body.appbuilder-dark .wf_row {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .wf_row_name { color: var(--fg-strong, #e6e6e6); }
body.appbuilder-dark .wf_row_label { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .wf_row_type {
	background-color: var(--bg-strong, #242424);
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .wf_list_add {
	border-color: var(--bd, #3a3a3a);
	color: var(--fg, #c8c8c8);
}
body.appbuilder-dark .wf_subblock {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .wf_subblock_label { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .wf_subrow {
	background-color: var(--bg-strong, #242424);
	border-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .wf_subinput,
body.appbuilder-dark .wf_refto_select {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg-strong, #e6e6e6);
}
/* Centered empty-state placeholder, modelled after the database
   console "No query opened" message. */
.workflow_designer_props_empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: 200px;
	padding: 40px 24px;
	color: #888;
	font-family: OpenSans, sans-serif;
	font-size: 13px;
	text-align: center;
}
.workflow_designer_props_empty_icon {
	font-size: 48px;
	opacity: 0.4;
	margin-bottom: 16px;
}
.workflow_designer_props_empty_text {
	font-size: 14px;
	line-height: 1.4;
}
.workflow_designer_props_field {
	margin-bottom: 12px;
}
.workflow_designer_props_field label {
	display: block;
	font-family: OpenSans, sans-serif;
	font-size: 11px;
	font-weight: 600;
	color: #666;
	margin-bottom: 4px;
}
.workflow_designer_props_field input,
.workflow_designer_props_field textarea {
	width: 100%;
	box-sizing: border-box;
	padding: 6px 8px;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	font: 12px OpenSans, sans-serif;
	background-color: #ffffff;
	color: #27251e;
}
.workflow_designer_props_field textarea {
	resize: vertical;
	min-height: 60px;
	max-height: 360px;       /* hard cap so a designer dragging the
	                            resize handle can't push the panel
	                            past its scroll envelope and trigger
	                            a stray outer scrollbar */
	max-width: 100%;
}
/* Focus marker — a 2px blue outline, consistent across every
   input/textarea in the workflow-designer props panel,
   light AND dark, including the w2field('list') data-source
   picker (whose visible input is at tabindex=-1, so :focus on
   it never fires; we use :focus-within on the parent instead).
   Outline (not border) avoids two problems at once:
     1. No layout shift — outline doesn't take space.
     2. Paints over w2ui's own focus styling cleanly. */
.workflow_designer_props_field input:focus,
.workflow_designer_props_field input:focus-visible,
.workflow_designer_props_field textarea:focus,
.workflow_designer_props_field textarea:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
}
.workflow_designer_props_field:focus-within input.w2ui-input {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
}
/* Dark-mode override — there's an existing .w2ui-select.has-focus
   rule (~line 5431) that forces outline:none + a 1px border, with
   higher specificity. Out-specify it by anchoring to
   html body.appbuilder-dark + the .workflow_designer_props_field
   wrapper + the explicit .w2ui-select class so we beat it cleanly
   in both :focus-within and .has-focus states. */
html body.appbuilder-dark .workflow_designer_props_field:focus-within input.w2ui-input.w2ui-select,
html body.appbuilder-dark .workflow_designer_props_field input.w2ui-input.w2ui-select.has-focus {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	box-shadow: none !important;
	/* Keep the same base border the other dark inputs have so
	   nothing shifts; the outline paints over it visually. */
	border: 1px solid #505050 !important;
}
.workflow_designer_props_field input:disabled,
.workflow_designer_props_field textarea:disabled {
	background-color: #ECE9E2;
	color: #888;
}

body.appbuilder-dark .workflow_designer_splitter,
body.appbuilder-dark .ontology_designer_splitter {
	background-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_designer_props {
	background-color: var(--bg-strong, #242424);
}
body.appbuilder-dark .workflow_designer_props_header {
	color: var(--fg-strong, #e6e6e6);
	border-bottom-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_designer_props_field label {
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .workflow_designer_props_field input,
body.appbuilder-dark .workflow_designer_props_field textarea {
	background-color: var(--bg, #1a1a1a);
	border-color: var(--bd, #3a3a3a);
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .workflow_designer_props_field input:disabled,
body.appbuilder-dark .workflow_designer_props_field textarea:disabled {
	background-color: var(--bg-strong, #242424);
	color: var(--fg-muted, #a0a0a0);
}

/* Dark-mode theming. The designer top bar inherits .builder_application_title
   text color via the existing rule, but the bar background, palette,
   and canvas have their own surfaces that need to flip too. */
body.appbuilder-dark .workflow_designer_layout {
	background-color: var(--bg, #1a1a1a);
}
body.appbuilder-dark .workflow_designer_top {
	background-color: var(--bg-strong, #242424);
	border-bottom-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_designer_title {
	color: var(--fg-strong, #e6e6e6);
}
body.appbuilder-dark .workflow_designer_palette {
	background-color: var(--bg-strong, #242424);
	border-right-color: var(--bd, #3a3a3a);
}
body.appbuilder-dark .workflow_designer_canvas {
	background-color: var(--bg, #1a1a1a);
}

/* Directory user card — @userid handle and work title stack tightly
   under the fullname, with a small visual hierarchy. */
.applications_element_userid {
	margin: 1px 0 0 0;
	color: #808080;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
}
.applications_element_worktitle {
	margin: 1px 0 2px 0;
	color: #555;
	font-size: 12px;
	font-style: italic;
	font-family: OpenSans, sans-serif;
}
/* Contact lines (email / mobile / phone) stack vertically and sit tight
   under the work title — same muted color as the handle. */
.applications_element_contact {
	margin: 1px 0 0 0;
	color: #808080;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	line-height: 1.4;
}
.applications_element_contact i.fa {
	width: 14px;
	text-align: center;
	margin-right: 2px;
}
/* Role badges (Admin / Builder) — top-right corner of the user card,
   inline on the same row, wrapping onto a second line if both are
   present and the card is narrow. flex-end keeps them right-anchored
   regardless of wrap state. */
.user_card_roles {
	position: absolute;
	top: 8px;
	right: 8px;
	display: flex;
	flex-flow: row wrap;
	justify-content: flex-end;
	align-items: flex-start;
	gap: 4px;
	max-width: 60%;
	pointer-events: none;
}
.user_badge {
	display: inline-block;
	padding: 1px 8px;
	border-radius: 10px;
	font-size: 11px;
	font-family: OpenSans, sans-serif;
	font-weight: 600;
	line-height: 1.6;
	background-color: #eef2f7;
	color: #455565;
}
.user_badge_admin   { background-color: #fdecea; color: #8e2a26; }
.user_badge_builder { background-color: #e6f0ff; color: #1a4f99; }
/* Synthetic-user "Agent enabled" chip — pinned to the upper-right of
   the card (mirror of user_card_lock_overlay's upper-left placement).
   Only rendered on synthetic-user cards (RenderCardHTML gate). The
   disabled state is the one that matters — the "you forgot to flip
   the enabled toggle in Tools & MCP" case — so it uses a bold amber
   disc that reads as "warning" without competing with the red lock
   icon's "locked out" semantics. Enabled uses a subdued green so the
   normal case isn't visually loud on a page of synthetic users. */
.applications_element .user_card_agent_status {
	position: absolute;
	top: 6px;
	right: 6px;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	color: #fff;
	font-size: 11px;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
	text-shadow: none;
	z-index: 3;
	pointer-events: auto;
}
.applications_element .user_card_agent_status.user_agent_status_on  { background: #43a047; }
.applications_element .user_card_agent_status.user_agent_status_off { background: #e65100; }
body.appbuilder-dark .applications_element .user_card_agent_status.user_agent_status_on  { background: #66bb6a; }
body.appbuilder-dark .applications_element .user_card_agent_status.user_agent_status_off { background: #ff8f00; }
/* Lock badge — a solid red disc with a white fa-lock glyph centered
   inside, pinned to the upper-left of the avatar. Reads at a glance
   as "this user is locked" rather than a faint red icon. Lives on
   the card (not inside the logo div) so the avatar's overflow:hidden
   circular clip doesn't crop it. A thin white ring lifts the disc
   off avatars whose own color is in the same red family. */
.applications_element .user_card_lock_overlay {
	position: absolute;
	top: 6px;
	left: 6px;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background: #d32f2f;
	color: #fff;
	font-size: 11px;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
	text-shadow: none;
	z-index: 3;
	pointer-events: auto;
}
/* Applications row — chips listing the apps the user has access to.
   Generous top margin separates the row from the contact / userid
   lines above. Selector matches the parent so it wins the cascade
   against `.applications_element_text > p { margin: 0 }`. */
.applications_element_text > p.applications_element_apps {
	margin: 4px 0 0 0;
	padding: 0;
	color: #666;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	line-height: 1.8;
}
.user_app_chip {
	display: inline-block;
	padding: 1px 8px;
	margin: 0 4px 4px 0;
	border-radius: 8px;
	background-color: #eef2f7;
	color: #455565;
	font-size: 11px;
	line-height: 1.6;
}
/* ChapsBuilder chip — accent blue with white text so the builder-
   access app is visually distinct from regular CVAPPLICATION rows. */
.user_app_chip.user_app_chip_builder {
	background-color: #1a4f99;
	color: #ffffff;
	font-weight: 600;
}
.applications_element_desc {
	margin: 4px 0 0 0;
	color: #444;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	/* Clamp to 3 lines with an ellipsis so long descriptions don't
	   blow up the card height. Newlines have been flattened to spaces
	   in JS so the clamp produces a clean "… " cutoff. */
	display: -webkit-box;
	-webkit-line-clamp: 3;
	line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
	word-break: break-word;
}
/* ----- Directory Properties form: optional left-column layout ----
   Used by Users to host the round avatar / logo picker without
   making the popup any taller. */
.directory_form_flex {
	display: flex;
	flex-direction: row;
	width: 100%;
	height: 100%;
	gap: 18px;
	box-sizing: border-box;
}
.directory_form_left {
	flex: 0 0 150px;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding-top: 8px;
}
.directory_form_right {
	flex: 1 1 auto;
	min-width: 0;
	height: 100%;
}

/* Wrapper provides the positioning context for the × clear badge so
   the badge sits on the upper-right corner of the avatar circle. */
.user_form_avatar_wrap {
	position: relative;
	width: 130px;
	height: 130px;
}

/* Round avatar tile in the user Properties form. Mirrors the colors
   of the directory cards (blue = human, violet = synthetic) and falls
   back to initials when no logo is set. Click → file picker; the
   small × badge in the top-right corner clears the logo. */
.user_form_avatar {
	width: 130px;
	height: 130px;
	border-radius: 50%;
	background: #6b7fb3;
	color: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	cursor: pointer;
	border: 2px solid transparent;
	box-sizing: border-box;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
	user-select: none;
}
.user_form_avatar:hover {
	border-color: #4477aa;
	box-shadow: 0 0 0 3px rgba(68, 119, 170, 0.15);
}
.user_form_avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.user_form_avatar_initials {
	font-family: OpenSans, sans-serif;
	font-weight: 600;
	font-size: 38px;
	letter-spacing: 1px;
}
.user_form_avatar_synth { background: #8a6cb1; }
.user_form_avatar_synth:hover { border-color: #6c4f93; box-shadow: 0 0 0 3px rgba(108, 79, 147, 0.18); }

.user_form_avatar_hint {
	font-family: OpenSans, sans-serif;
	font-size: 11px;
	color: #888;
	text-align: center;
	margin-top: 10px;
	line-height: 1.4;
}

/* Small × badge anchored to the top-right of an image / avatar.
   Used by the User Properties avatar and by the application Overview
   logo preview — same affordance in both places. */
.avatar_clear {
	position: absolute;
	top: -4px;
	right: -4px;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	border: 2px solid #ffffff;
	background: #c0392b;
	color: #ffffff;
	font-size: 11px;
	line-height: 1;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	box-shadow: 0 1px 3px rgba(0,0,0,0.25);
	transition: background-color 0.15s ease, transform 0.1s ease;
	z-index: 2;
}
.avatar_clear:hover  { background: #a93226; }
.avatar_clear:active { transform: scale(0.92); }
body.appbuilder-dark .avatar_clear { border-color: #2a2a2a; }
body.appbuilder-dark .user_form_avatar       { background: #4a5a85; }
body.appbuilder-dark .user_form_avatar_synth { background: #5b4a85; }
body.appbuilder-dark .user_form_avatar_hint  { color: #9aa0a8; }

/* ----- Group Members dialog ------------------------------------- */
/* Three sibling views inside the popup; only one is visible at a time. */
.members_root {
	display: flex;
	flex-direction: column;
	height: 100%;
}
.members_view {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0;
	height: 100%;
}

.members_section {
	display: flex;
	flex-direction: column;
	flex: 1 1 0;
	min-height: 0;
}
.members_section_head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 4px 2px;
	border-bottom: 1px solid #e2e2e2;
}
.members_section_title {
	font-weight: 600;
	color: #2C2C2C;
	font-size: 13px;
}
.members_section_title i.fa { margin-right: 6px; color: #6b7fb3; }
.members_list {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 6px;
	background: #FAF8F5;
	border: 1px solid #e2e2e2;
	border-top: 0;
	border-radius: 0 0 4px 4px;
	/* Containing block for the absolutely-centered .anylist_empty
	   message used when the section is empty. */
	position: relative;
	min-height: 80px;
}
.members_chip {
	display: flex;
	align-items: center;
	padding: 6px 8px;
	margin: 2px 0;
	background: #fff;
	border: 1px solid #e2e2e2;
	border-radius: 4px;
}
.members_chip_icon { width: 22px; text-align: center; color: #6b7fb3; margin-right: 8px; }

/* Round avatar tile shown to the left of each member chip (and each
   picker row). Reuses the directory color palette so a row visually
   reads the same as the corresponding card on the parent panel. */
.members_avatar {
	width: 30px;
	height: 30px;
	flex: 0 0 30px;
	border-radius: 50%;
	margin-right: 10px;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	color: #ffffff;
	font-family: OpenSans, sans-serif;
	font-weight: 600;
	font-size: 11px;
	letter-spacing: 0.5px;
}
.members_avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.members_avatar i.fa { font-size: 14px; line-height: 1; }
.members_avatar_user        { background: #6b7fb3; }  /* human */
.members_avatar_user_synth  { background: #8a6cb1; }  /* synthetic */
.members_avatar_group       { background: #7a9f7a; }  /* group   = green */
.members_avatar_orgunit     { background: #c98654; }  /* org unit = warm orange */
body.appbuilder-dark .members_avatar_user        { background: #4a5a85; }
body.appbuilder-dark .members_avatar_user_synth  { background: #5b4a85; }
body.appbuilder-dark .members_avatar_group       { background: #53755a; }
body.appbuilder-dark .members_avatar_orgunit     { background: #8e5b3a; }
.members_chip_text { flex: 1 1 auto; min-width: 0; }
.members_chip_label { font-size: 13px; color: #2C2C2C; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.members_chip_sub   { font-size: 11px; color: #808080; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.members_chip_badge { color: #888; margin-right: 4px; }
.members_chip_remove {
	background: transparent;
	border: 0;
	color: #888;
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	padding: 2px 6px;
	border-radius: 4px;
}
.members_chip_remove:hover { background: #fde2e2; color: #c43; }

/* Picker view layout: header (with right-aligned search) /
   scrollable rows / footer. */
.members_picker_head {
	display: flex;
	align-items: center;
	padding: 4px 0 8px 0;
	border-bottom: 1px solid #e2e2e2;
	margin-bottom: 8px;
	gap: 6px;
}
.members_back { margin-right: 4px; }

/* Wraps the search input + magnifier icon, rendered on the right
   side of the picker header — same look as the toolbar searches in
   the parent group panel. */
.members_picker_search_wrap {
	position: relative;
	display: flex;
	align-items: center;
}
.members_picker_search_wrap input.toolbar-search {
	width: 220px;
	padding: 4px 26px 4px 8px;
	box-sizing: border-box;
}
.members_picker_search_icon {
	position: absolute !important;
	right: 6px;
	top: 50%;
	transform: translateY(-50%);
	pointer-events: none;
	opacity: 0.6;
}
.members_picker_results {
	flex: 1 1 auto;
	overflow-y: auto;
	border: 1px solid #e2e2e2;
	border-radius: 4px;
	background: #FAF8F5;
	/* Containing block + min-height so the absolutely-positioned
	   .anylist_empty centers correctly when there are no matches. */
	position: relative;
	min-height: 80px;
}
.members_picker_footer {
	display: flex;
	align-items: center;
	padding: 8px 0 0 0;
	border-top: 1px solid #e2e2e2;
	margin-top: 8px;
	gap: 6px;
}
.members_picker_count {
	font-size: 12px;
	color: #808080;
}
.members_picker_row {
	display: flex;
	align-items: center;
	padding: 6px 8px;
	cursor: pointer;
	border-bottom: 1px solid #f0f0f0;
}
.members_picker_row:hover { background: #f4f6fb; }
.members_picker_row:last-child { border-bottom: 0; }
.members_picker_row.selected { background: #eaf1ff; }
/* Selection checkbox — mimics the w2ui grid select-cell box: a
   small rounded blue-bordered square that fills with blue and a
   white check when "checked". */
.members_picker_check {
	display: inline-block;
	width: 16px;
	height: 16px;
	margin-right: 10px;
	flex: 0 0 16px;
	border: 1.5px solid #6699cc;
	border-radius: 4px;
	background: #ffffff;
	box-sizing: border-box;
	position: relative;
	transition: background-color 0.1s ease, border-color 0.1s ease;
}
.members_picker_check.checked {
	background: #5a87c2;
	border-color: #5a87c2;
}
.members_picker_check.checked::after {
	content: "";
	position: absolute;
	left: 4px;
	top: 1px;
	width: 4px;
	height: 8px;
	border: solid #ffffff;
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}
.members_picker_row:hover .members_picker_check {
	border-color: #4477aa;
}
body.appbuilder-dark .members_picker_check          { background: #2a2a2a; border-color: #6f8db5; }
body.appbuilder-dark .members_picker_check.checked  { background: #5a87c2; border-color: #5a87c2; }

body.appbuilder-dark .members_section_title { color: #E8E8E8; }
body.appbuilder-dark .members_section_head  { border-bottom-color: #444; }
body.appbuilder-dark .members_list          { background: #2a2a2a; border-color: #444; }
body.appbuilder-dark .members_chip          { background: #333; border-color: #444; }
body.appbuilder-dark .members_chip_label    { color: #E8E8E8; }
body.appbuilder-dark .members_chip_sub      { color: #9aa0a8; }
body.appbuilder-dark .members_picker_head    { border-bottom-color: #444; }
body.appbuilder-dark .members_picker_results { background: #2a2a2a; border-color: #444; }
body.appbuilder-dark .members_picker_footer  { border-top-color: #444; }
body.appbuilder-dark .members_picker_row     { border-bottom-color: #3a3a3a; }
body.appbuilder-dark .members_picker_row:hover    { background: #3a3a3a; }
body.appbuilder-dark .members_picker_row.selected { background: #2a3950; }

body.appbuilder-dark .applications_element_userid    { color: #9aa0a8; }
body.appbuilder-dark .applications_element_worktitle { color: #c0c4cc; }
body.appbuilder-dark .applications_element_contact   { color: #9aa0a8; }
body.appbuilder-dark .applications_element_desc      { color: #d0d4da; }
body.appbuilder-dark .directory_initials       { background: #4a5a85; }
body.appbuilder-dark .directory_initials_synth { background: #5b4a85; }
body.appbuilder-dark .directory_group_icon     { background: #53755a; }
body.appbuilder-dark .directory_orgunit_icon   { background: #8e5b3a; }
/* App chips in dark mode: regular ones tone down to a dim gray so
   the ChapsBuilder chip (kept on its accent blue) is the only one
   that pops. */
body.appbuilder-dark .user_app_chip { background-color: #3a3f47; color: #b8bec7; }
body.appbuilder-dark .user_app_chip.user_app_chip_builder { background-color: #1a4f99; color: #ffffff; }

/* ==============================================================
 * Tab strip visibility — shown ONLY in test mode. JS toggles
 * body.appbuilder-no-tabs; this rule hides the main panel's tab
 * strip and promotes its content to fill the full panel height.
 * ============================================================== */
body.appbuilder-no-tabs #layout_layout_panel_main > .w2ui-panel-tabs,
body.appbuilder-no-tabs .w2ui-panel-main > .w2ui-panel-tabs {
	display: none !important;
}
body.appbuilder-no-tabs #layout_layout_panel_main > .w2ui-panel-content,
body.appbuilder-no-tabs .w2ui-panel-main > .w2ui-panel-content {
	top: 0 !important;
}

/* ==============================================================
 * Overview panel (replaces the old nested w2layout)
 * ============================================================== */
.overview-flex {
	display: flex;
	flex-direction: row;
	width: 100%;
	height: 100%;
	overflow: hidden;
}
.overview-left-panel {
	width: 200px;
	flex: 0 0 200px;
	height: 100%;
	border-right: 1px solid #e2e2e2;
	background-color: #F2F0EC;
	overflow: visible;
	box-sizing: border-box;
}
.overview-right-panel {
	flex: 1 1 auto;
	height: 100%;
	display: flex;
	flex-direction: column;
	min-width: 0;
}
.overview-toolbar-mount {
	flex: 0 0 40px;
	height: 40px;
	border-bottom: 1px solid #e2e2e2;
	background-color: #fafafa;
	box-sizing: border-box;
	overflow: hidden;
}
.overview-main-panel {
	flex: 1 1 auto;
	min-height: 0;
	background-color: #FAF8F5;
	position: relative;
}

/* ==============================================================
 * Save Version top-bar button (styled to match .buildapp / .testapp
 * but in a distinct neutral tone so it doesn't compete with the
 * mode-switching primary actions).
 * ============================================================== */
.saveversion {
	position: absolute;
	right: 248px;   /* sits to the LEFT of .buildapp / .testapp (right:120px, width:120px) with an 8px gap. */
	top: 16px;
	width: 120px;
	height: 32px;
	border-radius: 6px;
	box-sizing: border-box;
	padding: 0 12px;
	background-color: #5a6268;
	color: white;
	text-align: center;
	cursor: pointer;
	user-select: none;
}
.saveversion:hover  { background-color: #494f55; }
.saveversion:active { background-color: #373b40; }
.saveversion > span {
	line-height: 32px;
	font-family: OpenSans;
	font-size: 14px;
}
body.appbuilder-dark .saveversion        { background-color: #5a6268 !important; color: white !important; }
body.appbuilder-dark .saveversion:hover  { background-color: #494f55 !important; }
body.appbuilder-dark .saveversion:active { background-color: #373b40 !important; }

/* ==============================================================
 * Overview → Versions subpanel
 * ============================================================== */
.overview_versions_panel {
	display: flex;
	flex-direction: column;
	gap: 12px;
	padding: 20px;
	box-sizing: border-box;
}
.overview_versions_loading,
.overview_versions_empty {
	color: #888;
	font-family: OpenSans, sans-serif;
	font-size: 14px;
	text-align: center;
	padding: 40px 20px;
}
.overview_versions_empty i {
	display: block;
	font-size: 40px;
	opacity: 0.35;
	margin-bottom: 10px;
}
.overview_versions_empty_sub {
	font-size: 12px;
	color: #9e9e9e;
	margin-top: 4px;
}

.overview_version_card {
	background: #ffffff;
	border: 1px solid #e2e2e2;
	border-radius: 8px;
	padding: 12px 14px;
	font-family: OpenSans, sans-serif;
}
.overview_version_card_head {
	display: flex;
	align-items: center;
	gap: 10px;
}
.overview_version_number {
	font-weight: 700;
	color: #269DF0;
	font-size: 14px;
	background: rgba(38, 157, 240, 0.08);
	padding: 2px 8px;
	border-radius: 10px;
}
.overview_version_name {
	font-weight: 600;
	font-size: 14px;
	color: #2C2C2C;
}
.overview_version_spacer { flex: 1 1 auto; }
.overview_version_restore,
.overview_version_publish {
	padding: 4px 10px !important;
	font-size: 12px !important;
	margin-left: 4px;
}
.overview_version_badge {
	display: inline-block;
	padding: 2px 8px;
	margin-left: 8px;
	border-radius: 10px;
	color: #fff;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
	vertical-align: middle;
}
.overview_version_desc {
	margin-top: 6px;
	font-size: 12px;
	color: #555;
	line-height: 1.45;
	white-space: pre-wrap;
}
.overview_version_meta {
	margin-top: 8px;
	font-size: 11px;
	color: #888;
}
.overview_version_meta i { margin-right: 4px; opacity: 0.75; }

body.appbuilder-dark .overview_version_card {
	background: var(--bg-elev);
	border-color: var(--border);
}
body.appbuilder-dark .overview_version_name { color: var(--fg-strong); }
body.appbuilder-dark .overview_version_desc { color: var(--fg); }
body.appbuilder-dark .overview_version_meta { color: var(--fg-muted); }

/* ==============================================================
 * Migration picker + progress dialog
 *   - picker: clickable rows listing Published source versions
 *   - progress: per-table state list polled from the job
 * ============================================================== */
.migrate_pick_intro {
	padding: 0 4px 10px 4px;
	color: #555;
	line-height: 1.45;
}
.migrate_pick_body {
	display: flex;
	flex-direction: column;
	gap: 6px;
	max-height: 360px;
	overflow-y: auto;
}
.migrate_pick_row {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 12px;
	border: 1px solid #d6d5d2;
	border-radius: 6px;
	background: #fff;
	cursor: pointer;
	transition: background-color 0.12s ease-out, border-color 0.12s ease-out;
}
.migrate_pick_row:hover {
	background: #f4f6fa;
	border-color: #269DF0;
}
.migrate_pick_label { font-weight: 600; }
.migrate_pick_sub { margin-left: auto; opacity: 0.75; font-size: 12px; }
body.appbuilder-dark .migrate_pick_intro { color: var(--fg-muted); }
body.appbuilder-dark .migrate_pick_row {
	background: var(--bg-elev);
	border-color: var(--border);
	color: var(--fg);
}
body.appbuilder-dark .migrate_pick_row:hover {
	background: rgba(38, 157, 240, 0.12);
	border-color: #269DF0;
}

.migration_progress_status {
	font-size: 13px;
	margin-bottom: 12px;
	padding: 8px 10px;
	background: #f8fafa;
	border-radius: 4px;
}
.migration_progress_tables {
	display: flex;
	flex-direction: column;
	gap: 4px;
	max-height: 380px;
	overflow-y: auto;
}
.migration_table_row {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 10px;
	border-radius: 4px;
	font-size: 12px;
}
.migration_table_row:hover { background: rgba(0,0,0,0.03); }
.migration_table_name { font-weight: 500; }
body.appbuilder-dark .migration_progress_status {
	background: var(--bg-input);
	color: var(--fg);
}
body.appbuilder-dark .migration_table_row { color: var(--fg); }
body.appbuilder-dark .migration_table_row:hover { background: rgba(255,255,255,0.04); }

/* ==============================================================
 * Overview → Logo subpanel
 * ============================================================== */
.overview_logo_panel {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 32px 24px;
	gap: 16px;
	font-family: OpenSans, sans-serif;
}
.overview_logo_preview {
	width: 128px;
	height: 128px;
	border-radius: 64px;
	background-color: #F2F0EC;
	border: 1px solid #e2e2e2;
	display: flex;
	align-items: center;
	justify-content: center;
	/* Containing block for the × clear badge (overflow stays visible
	   so the badge isn't clipped at the circle's edge). */
	position: relative;
	overflow: visible;
}
/* The image / placeholder still gets clipped to a circle; only the
   badge is allowed to escape. */
.overview_logo_preview > img,
.overview_logo_preview > .overview_logo_placeholder {
	border-radius: 64px;
	overflow: hidden;
}
.overview_logo_preview img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.overview_logo_placeholder {
	font-size: 48px;
	color: #B0B0B0;
}
/* Match the Mass Import dropzone look — dashed blue border on a
   subtle blue-tinted background. */
.overview_logo_dropzone {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	max-width: 440px;
	min-height: 200px;
	border: 2px dashed #269DF0;
	border-radius: 16px;
	background-color: rgba(38, 157, 240, 0.04);
	color: #269DF0;
	font-family: OpenSans;
	font-size: 16px;
	font-weight: 600;
	text-align: center;
	padding: 20px;
	box-sizing: border-box;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease;
}
.overview_logo_dropzone:hover,
.overview_logo_dropzone_hover {
	background-color: rgba(38, 157, 240, 0.10);
	border-color: #1F84C6;
}
.overview_logo_dropzone span {
	pointer-events: none;
}
.overview_logo_actions {
	display: flex;
	justify-content: center;
}
body.appbuilder-dark .overview_logo_preview {
	background-color: var(--bg-elev);
	border-color: var(--border);
}
body.appbuilder-dark .overview_logo_placeholder {
	color: var(--fg-muted);
}
/* Dark mode: keep the dashed blue on a dark-tinted blue, matching
   the Mass Import dropzone in dark mode. */
body.appbuilder-dark .overview_logo_dropzone {
	background-color: rgba(38, 157, 240, 0.08);
	border-color: #269DF0;
	color: #269DF0;
}
body.appbuilder-dark .overview_logo_dropzone:hover,
body.appbuilder-dark .overview_logo_dropzone_hover {
	background-color: rgba(38, 157, 240, 0.16);
	border-color: #1F84C6;
}
body.appbuilder-dark .overview-left-panel {
	background-color: var(--bg);
	border-right-color: var(--border);
}
body.appbuilder-dark .overview-toolbar-mount {
	background-color: var(--bg-alt);
	border-bottom-color: var(--border);
}
body.appbuilder-dark .overview-main-panel {
	background-color: var(--bg);
}

.versions-standalone-panel,
.coverpage-standalone-panel {
	background-color: #FAF8F5;
}
body.appbuilder-dark .versions-standalone-panel,
body.appbuilder-dark .coverpage-standalone-panel {
	background-color: var(--bg);
}
body.appbuilder-dark .versions-standalone-panel .w2ui-panel-main,
body.appbuilder-dark .versions-standalone-panel .w2ui-panel-content,
body.appbuilder-dark .coverpage-standalone-panel .w2ui-panel-main,
body.appbuilder-dark .coverpage-standalone-panel .w2ui-panel-content {
	background-color: var(--bg) !important;
}
/* Same fix as for the Description panel: the top-toolbar slot was
   created with inline background-color:#fafafa, so without an
   explicit dark-mode override the toolbar reads as a white stripe
   against the dark page. */
body.appbuilder-dark .versions-standalone-panel .w2ui-panel-top,
body.appbuilder-dark .versions-standalone-panel .w2ui-panel-top .w2ui-toolbar,
body.appbuilder-dark .coverpage-standalone-panel .w2ui-panel-top,
body.appbuilder-dark .coverpage-standalone-panel .w2ui-panel-top .w2ui-toolbar {
	background-color: var(--bg) !important;
	border-bottom-color: var(--border) !important;
}
body.appbuilder-on-versions .saveversion { display: none !important; }

/* ==============================================================
 * Shared "STEP N OF 8" header used at the top of each build step.
 * Lives inside .step_layout — a flex column wrapper so the body
 * underneath still grows to fill the remaining vertical space.
 * Description has its own richer header inline; this one covers
 * Documentation, Thesaurus, Requirements, Domains, Data model,
 * Workflows / Microservices and Versions & Publish.
 * ============================================================== */
.step_layout {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
}
/* Builder_Editor's application_body normally pins itself to
   100% height of its parent panel. Inside a step_layout it has
   to share the column with the header, so override to flex. */
.step_layout .application_body.step_body,
.step_layout .step_body {
	flex: 1 1 auto;
	min-height: 0;
	height: auto !important;
}

.step_header_block {
	flex: 0 0 auto;
	padding: 14px 20px 12px;
	background-color: #FAF8F5;
	border-bottom: 1px solid #EEECEA;
	box-sizing: border-box;
	/* Force OpenSans here too: this block lives inside w2ui panels
	   whose default font is Times New Roman, so without an explicit
	   font-family the eyebrow / title / intro picked it up. */
	font-family: OpenSans, sans-serif;
	color: #27251E;
}
.step_header_eyebrow {
	font-family: OpenSans, sans-serif;
	font-size: 11px;
	letter-spacing: 0.08em;
	color: #808080;
	font-weight: 600;
}
.step_header_title {
	font-family: OpenSans, sans-serif;
	font-size: 18px;
	font-weight: 600;
	line-height: 1.3;
	margin-top: 2px;
	color: #27251E;
}
.step_header_intro {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	color: #808080;
	line-height: 1.5;
	max-width: 760px;
	margin-top: 4px;
}
body.appbuilder-dark .step_header_block {
	background-color: var(--bg);
	border-bottom-color: var(--border);
}
body.appbuilder-dark .step_header_title { color: var(--fg); }
body.appbuilder-dark .step_header_eyebrow,
body.appbuilder-dark .step_header_intro { color: var(--fg-muted, #b7bcc4); }

/* ==============================================================
 * Description panel (redesigned) — Phase 1
 *
 * Two-column layout: sticky readiness rail on the left, main column
 * with six numbered widget-cards. Each card and the rail share the
 * same widget styling used elsewhere on the cover page (white card,
 * #EEECEA border in light mode; var(--bg-elev) / var(--border) dark).
 * ============================================================== */
.description-standalone-panel {
	background-color: #FAF8F5;
}
body.appbuilder-dark .description-standalone-panel {
	background-color: var(--bg);
}
body.appbuilder-dark .description-standalone-panel .w2ui-panel-main,
body.appbuilder-dark .description-standalone-panel .w2ui-panel-content {
	background-color: var(--bg) !important;
}
/* Top toolbar slot was created with inline background-color:#fafafa
   so the Save Changes button + chip would sit on a white stripe in
   dark mode. Repaint the slot (and the toolbar widget inside it)
   with the panel's dark background. */
body.appbuilder-dark .description-standalone-panel .w2ui-panel-top,
body.appbuilder-dark .description-standalone-panel .w2ui-panel-top .w2ui-toolbar {
	background-color: var(--bg) !important;
	border-bottom-color: var(--border) !important;
}

.desc_body {
	width: 100%;
	height: 100%;
	overflow-y: auto;
	box-sizing: border-box;
	padding: 24px 28px 40px;
	color: #27251E;
	font-family: OpenSans, sans-serif;
}
body.appbuilder-dark .desc_body { color: var(--fg); }

.desc_layout {
	display: grid;
	grid-template-columns: 240px minmax(0, 1fr);
	gap: 24px;
	align-items: start;
}

/* --- Rail -----------------------------------------------------
   The rail itself is now a single rounded card matching the
   section-card surface (#F2F0EC). The readiness widget inside
   flips to white to act as a "card-in-card" highlight; the TIP
   keeps its blue pill style. */
.desc_rail {
	position: sticky;
	top: 0;
	background-color: #F2F0EC;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	padding: 12px;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	gap: 12px;
}
body.appbuilder-dark .desc_rail {
	background-color: var(--bg-alt) !important;
	border-color: var(--border) !important;
}

.desc_rail_readiness {
	background-color: #ffffff;
	border: 1px solid #EEECEA;
	border-radius: 10px;
	padding: 10px 12px;
	box-sizing: border-box;
}
.desc_rail_tip {
	background-color: rgba(38, 157, 240, 0.15);
	border: 1px solid transparent;
	border-radius: 10px;
	padding: 10px 12px;
	box-sizing: border-box;
}
body.appbuilder-dark .desc_rail_readiness {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
}
body.appbuilder-dark .desc_rail_tip {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
}
/* Light-mode TIP text uses the same blue as its tint. Dark mode
   keeps the rail-widget border + standard fg colors. */
.desc_rail_tip .desc_rail_tip_label,
.desc_rail_tip .desc_rail_tip_text {
	color: #269DF0;
}
.desc_rail_readiness_head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
}
.desc_rail_readiness_label {
	font-size: 10px;
	letter-spacing: 0.08em;
	color: #808080;
}
body.appbuilder-dark .desc_rail_readiness_label { color: #b7bcc4; }
.desc_rail_readiness_value {
	font-size: 16px;
	font-weight: 700;
}
.desc_rail_readiness_sub {
	font-size: 11px;
	color: #808080;
	margin-top: 4px;
	line-height: 1.4;
}
body.appbuilder-dark .desc_rail_readiness_sub { color: #b7bcc4; }

.desc_rail_nav {
	display: flex;
	flex-direction: column;
	gap: 2px;
}
/* Light-mode rail items mirror the test/run-mode left sidebar
   (New thread / My tasks / My calendar): 14px OpenSans, gray hover,
   white selected state, no borders. Dark mode keeps the widget
   look defined below so the rail stays legible on the dark page. */
.desc_rail_item {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 10px;
	border-radius: 6px;
	cursor: pointer;
	font-family: OpenSans, sans-serif;
	font-size: 14px;
	line-height: 24px;
	color: #27251E;
	user-select: none;
	border: 1px solid transparent;
}
.desc_rail_item:hover { background-color: #EAE8E4; }
.desc_rail_item_active {
	background-color: #ffffff;
	color: #27251E;
}
body.appbuilder-dark .desc_rail_item { color: #b7bcc4; }
body.appbuilder-dark .desc_rail_item:hover { background-color: rgba(38, 157, 240, 0.06); }
body.appbuilder-dark .desc_rail_item_active {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
.desc_rail_num {
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.04em;
	color: #808080;
	min-width: 18px;
}

.desc_rail_tip_label {
	font-size: 10px;
	letter-spacing: 0.08em;
	font-weight: 700;
	color: #808080;
	margin-bottom: 4px;
}
.desc_rail_tip_text {
	font-size: 11px;
	color: #808080;
	line-height: 1.5;
}
body.appbuilder-dark .desc_rail_tip_label,
body.appbuilder-dark .desc_rail_tip_text { color: #b7bcc4; }

/* --- Main column header ---------------------------------------
   Aligned in sizes and colors with the shared .step_header_block
   used by the other build steps so every step's header reads as
   the same family. */
.desc_main_head { margin-bottom: 18px; }
.desc_main_eyebrow {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.08em;
	color: #808080;
	margin-bottom: 4px;
}
body.appbuilder-dark .desc_main_eyebrow { color: #b7bcc4; }
.desc_main_title {
	font-size: 18px;
	font-weight: 600;
	line-height: 1.3;
	margin-bottom: 6px;
	color: #27251E;
}
body.appbuilder-dark .desc_main_title { color: var(--fg); }
.desc_main_intro {
	font-size: 12px;
	color: #808080;
	max-width: 760px;
	line-height: 1.5;
	margin-bottom: 12px;
}
body.appbuilder-dark .desc_main_intro { color: #b7bcc4; }
.desc_main_actions {
	display: flex;
	gap: 8px;
	margin-bottom: 8px;
}
/* Header actions. Primary keeps the app blue (used by .buildapp and
   the rest of the builder's primary CTAs); secondary mirrors the
   workflow .wf-intent-suggest convention (white bg, #C0C0C0 border,
   #F1F1F1 hover) so the two action affordances read as the same
   family across the builder. */
.desc_btn_primary, .desc_btn_secondary {
	height: 34px;
	padding: 0 16px;
	border-radius: 6px;
	font-size: 13px;
	font-family: OpenSans, sans-serif;
	cursor: pointer;
	border: 1px solid transparent;
}
.desc_btn_primary {
	background-color: #269DF0;
	color: #fff;
	border-color: #269DF0;
}
.desc_btn_primary:hover { background-color: #1F84C6; border-color: #1F84C6; }
.desc_btn_secondary {
	background-color: #ffffff;
	color: #27251e;
	border-color: #C0C0C0;
}
.desc_btn_secondary:hover { background-color: #F1F1F1; }
body.appbuilder-dark .desc_btn_secondary {
	background-color: var(--bg-elev, #242424);
	color: var(--fg, #e6e6e6);
	border-color: var(--border, #333);
}
body.appbuilder-dark .desc_btn_secondary:hover { background-color: var(--bg-hover, #2a2a2a); }

/* "Unsaved changes" chip on the Description top toolbar.
   Sits next to the Save Changes button and toggles via inline
   display:none/'' from _DescriptionMarkDirty(). Pulsing dot draws
   attention without being noisy. */
.desc_unsaved_chip {
	/* w2toolbar's button sits on a slightly different baseline than
	   plain text in an html slot. inline-block + vertical-align:middle
	   gets close, then `position:relative; top:2px` nudges the pill
	   down the last 1–2 px so its centre matches the Save Changes
	   button exactly. */
	display: inline-block;
	vertical-align: middle;
	position: relative;
	top: 2px;
	margin-left: 12px;
	padding: 3px 10px;
	border-radius: 12px;
	background-color: rgba(242, 153, 74, 0.15);
	color: #C56A1A;
	font-family: OpenSans, sans-serif;
	font-size: 11px;
	font-weight: 600;
	line-height: 16px;
	user-select: none;
}
.desc_unsaved_chip .fa {
	margin-right: 4px;
	font-size: 7px;
	/* The w2ui dark-mode catch-all `.w2ui-reset * { color: var(--w2-fg) }`
	   recolours every icon descendant to bright white, breaking color
	   inheritance from the chip. Set the dot colour explicitly in
	   both modes so it always matches the chip text. */
	color: #C56A1A;
	animation: desc_unsaved_pulse 1.6s ease-in-out infinite;
}
@keyframes desc_unsaved_pulse {
	0%, 100% { opacity: 0.55; }
	50%      { opacity: 1; }
}
body.appbuilder-dark .desc_unsaved_chip {
	background-color: rgba(242, 153, 74, 0.18);
	color: #F5B26A;
}
body.appbuilder-dark .desc_unsaved_chip .fa {
	color: #F5B26A;
}

/* "Suggest improvements" popup — list of editorial suggestions
   the user applies by hand. */
.desc_suggest_body {
	padding: 14px 18px 6px;
	font-family: OpenSans, sans-serif;
}
.desc_suggest_intro {
	font-size: 12px;
	color: #808080;
	line-height: 1.5;
	margin-bottom: 12px;
}
.desc_suggest_list {
	margin: 0;
	padding-left: 22px;
}
.desc_suggest_item {
	font-size: 13px;
	line-height: 1.5;
	color: #27251E;
	margin-bottom: 8px;
}
body.appbuilder-dark .desc_suggest_item { color: var(--fg, #e6e6e6); }
body.appbuilder-dark .desc_suggest_intro { color: var(--fg-muted, #b7bcc4); }

/* --- Section cards -------------------------------------------- */
.desc_sections {
	display: flex;
	flex-direction: column;
	gap: 14px;
}
.desc_section {
	background-color: #F2F0EC;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	padding: 18px 20px;
	box-sizing: border-box;
}
body.appbuilder-dark .desc_section {
	background-color: var(--bg-alt) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
.desc_section_head {
	display: flex;
	align-items: center;
	gap: 10px;
}
.desc_section_num {
	font-size: 11px;
	font-weight: 700;
	color: #808080;
	letter-spacing: 0.04em;
}
.desc_section_title {
	font-size: 16px;
	font-weight: 600;
	flex: 1 1 auto;
}
.desc_section_pill {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font-size: 11px;
	padding: 2px 8px;
	border-radius: 10px;
	font-weight: 500;
}
.desc_section_pill_empty     { background-color: rgba(154, 160, 166, 0.18); color: #808080; }
.desc_section_pill_partial   { background-color: rgba(38, 157, 240, 0.15);  color: #269DF0; }
.desc_section_pill_done      { background-color: rgba(38, 157, 240, 0.15);  color: #269DF0; }
/* AI-extracted from a spec, awaiting human review. */
.desc_section_pill_suggested { background-color: rgba(245, 166, 35, 0.18);  color: #9A6B00; }

/* "Fill from spec" dialog. The file picker and the steps list both reuse
   .dm-check-list / .dm-check-row for borders, separators and dark-mode
   colours — these classes only add layout (flex, hover, ellipsis) on top. */
.desc_spec_file_list { max-height: 220px; overflow-y: auto; }
.desc_spec_file_row {
	display: flex;
	align-items: center;
	gap: 8px;
	cursor: pointer;
	font-size: 13px;
}
.desc_spec_file_row:hover { background-color: var(--bg-hover, rgba(38, 157, 240, 0.08)); }
.desc_spec_file_row .fa   { color: var(--fg-muted, #808080); }
.desc_spec_file_name {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.desc_spec_section_label {
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--fg-muted, #808080);
	margin-bottom: 6px;
}
.desc_fill_step_row {
	display: flex;
	align-items: center;
	gap: 10px;
}
.desc_fill_step_disabled { opacity: 0.55; }
.desc_fill_step_name {
	flex: 1 1 auto;
	font-size: 13px;
	font-weight: 500;
}
.desc_fill_mode_host {
	flex: 0 0 230px;
	width: 230px;
	text-align: right;
}
.desc_fill_mode_disabled { color: var(--fg-muted, #B0B0B0); }

.desc_fill_badge {
	flex: 0 0 auto;
	font-size: 10px;
	font-weight: 600;
	padding: 2px 7px;
	border-radius: 9px;
	white-space: nowrap;
}
.desc_fill_badge_empty     { background-color: rgba(154, 160, 166, 0.18); color: #808080; }
.desc_fill_badge_suggested { background-color: rgba(245, 166, 35, 0.18);  color: #9A6B00; }
.desc_fill_badge_reviewed  { background-color: rgba(38, 157, 240, 0.15);  color: #269DF0; }
.desc_fill_badge_soon      { background-color: rgba(154, 160, 166, 0.12); color: #A0A0A0; }

.desc_section_subtitle {
	font-size: 12px;
	color: #808080;
	margin-top: 4px;
	margin-bottom: 12px;
	border-bottom: 1px solid #EEECEA;
	padding-bottom: 12px;
}
body.appbuilder-dark .desc_section_subtitle {
	color: #b7bcc4;
	border-bottom-color: var(--border);
}
.desc_section_body { display: flex; flex-direction: column; gap: 16px; }

/* --- Fields --------------------------------------------------- */
.desc_field { display: flex; flex-direction: column; gap: 4px; }
.desc_field_head { display: flex; align-items: center; gap: 4px; }
/* Match the existing form-label convention used elsewhere in the
   builder (.overview_field_label): bold, slightly muted neutral. */
.desc_field_label {
	font-size: 13px;
	font-weight: 700;
	color: #656164cc;
}
body.appbuilder-dark .desc_field_label { color: var(--fg); }
.desc_required { color: #d2453a; font-weight: 700; }
/* Help-tip glyph. Light mode reuses the same light-blue tint used
   by the Partial / Optional pills and the TIP card — readable
   against the form bg without a hard outline. Dark mode keeps a
   neutral border + muted text since the blue-on-blue tint reads
   poorly on the dark page. */
.desc_field_tip {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 14px;
	height: 14px;
	font-size: 9px;
	font-weight: 700;
	border: 1px solid transparent;
	border-radius: 50%;
	background-color: rgba(38, 157, 240, 0.15);
	color: #269DF0;
	cursor: default;
	user-select: none;
	outline: none;
}
.desc_field_tip:hover { background-color: rgba(38, 157, 240, 0.25); }
body.appbuilder-dark .desc_field_tip {
	background-color: transparent;
	border-color: var(--border, #333);
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .desc_field_tip:hover {
	background-color: rgba(38, 157, 240, 0.18);
	border-color: rgba(38, 157, 240, 0.35);
	color: #6FB8F5;
}
.desc_field_helper {
	font-size: 11px;
	color: #808080;
}
body.appbuilder-dark .desc_field_helper { color: #b7bcc4; }
/* Inputs/textareas mirror the workflow .wf-intent-longdesc /
   .wf-intent-chip-add convention: 1px neutral border, 2px blue
   outline on focus (inset via outline-offset:-1px so the surrounding
   layout stays put). Same focus look in dark mode. Placeholder
   color is handled globally elsewhere in this stylesheet. */
.desc_input,
.desc_textarea {
	width: 100%;
	border: 1px solid #C0C0C0;
	border-radius: 6px;
	padding: 6px 10px;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	background-color: #ffffff;
	color: #27251E;
	box-sizing: border-box;
	outline: none;
}
.desc_textarea {
	resize: vertical;
	min-height: 100px;
	line-height: 1.45;
}
.desc_input:focus,
.desc_input:focus-visible,
.desc_textarea:focus,
.desc_textarea:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	border-color: #C0C0C0 !important;
	box-shadow: none !important;
}
body.appbuilder-dark .desc_input,
body.appbuilder-dark .desc_textarea {
	background-color: var(--bg-elev, #242424);
	color: var(--fg, #e6e6e6);
	border-color: var(--border, #333);
}
html body.appbuilder-dark .desc_input:focus,
html body.appbuilder-dark .desc_input:focus-visible,
html body.appbuilder-dark .desc_textarea:focus,
html body.appbuilder-dark .desc_textarea:focus-visible {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	border-color: var(--border, #333) !important;
	box-shadow: none !important;
}
.desc_field_footer {
	display: flex;
	align-items: center;
	gap: 12px;
	font-size: 11px;
	color: #808080;
}
.desc_spacer { flex: 1 1 auto; }
.desc_field_counter { color: #808080; }
.desc_field_counter_near { color: #d2453a; }
.desc_field_extra {
	color: #269DF0;
	cursor: pointer;
	text-decoration: none;
}
.desc_field_extra:hover { text-decoration: underline; }

.desc_textarea_actions { display: flex; gap: 14px; }
.desc_textarea_actions a {
	color: #269DF0;
	font-size: 11px;
	cursor: pointer;
	text-decoration: none;
}
.desc_textarea_actions a:hover { text-decoration: underline; }

/* --- Lists / multilists --------------------------------------- */
.desc_list, .desc_multilist {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 4px;
}
.desc_list_row {
	display: flex;
	align-items: center;
	gap: 6px;
}
.desc_list_idx {
	font-size: 11px;
	color: #808080;
	min-width: 14px;
	text-align: right;
}
/* Match the surrounding input's vertical footprint so the × button
   sits centered against the input on every row regardless of
   whether the row contains a column label above the input (multilist
   sections) or not (simple lists). Inline-flex centers the glyph. */
.desc_row_remove {
	width: 28px;
	height: 28px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: none;
	background: transparent;
	color: #808080;
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	border-radius: 4px;
	flex-shrink: 0;
}
.desc_row_remove:hover { background-color: rgba(210, 69, 58, 0.08); color: #d2453a; }
.desc_multilist_row {
	display: flex;
	align-items: flex-end;
	gap: 6px;
}
.desc_multilist_cells {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
	gap: 8px;
	flex: 1 1 auto;
}
.desc_multilist_cell { display: flex; flex-direction: column; gap: 4px; }
.desc_multilist_collabel {
	font-size: 9px;
	letter-spacing: 0.08em;
	font-weight: 700;
	color: #808080;
}
/* "+ Add …" buttons mirror the workflow .wf_list_add convention:
   dashed neutral border, muted label, hover flips to blue (same
   blue used for input focus outlines). */
.desc_add_btn {
	align-self: flex-start;
	margin-top: 8px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background-color: transparent;
	border: 1px dashed #c7c2b8;
	color: #555;
	padding: 6px 10px;
	border-radius: 6px;
	font-size: 12px;
	font-family: OpenSans, sans-serif;
	cursor: pointer;
	transition: border-color 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}
.desc_add_btn:hover {
	border-color: #4a90e2;
	color: #4a90e2;
	background-color: rgba(74, 144, 226, 0.06);
}
body.appbuilder-dark .desc_add_btn {
	border-color: var(--border, #333);
	color: var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .desc_add_btn:hover {
	border-color: #4a90e2;
	color: #4a90e2;
}

/* --- Two-column layout (Scope, Reality bottom) ---------------- */
.desc_twocol {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 24px;
}
@media (max-width: 720px) { .desc_twocol { grid-template-columns: 1fr; } }

/* --- Logo widget ----------------------------------------------
   Compact tile: the rounded image preview is itself the click
   target. A "×" remove button overlays on hover when a logo is
   set. The drop target is the *whole* Logo section (see
   .desc_section_dropping below) — no separate drop zone tile. */
.desc_logo_slot {
	background-color: transparent;
}
.desc_logo_widget {
	display: flex;
	align-items: center;
	gap: 12px;
}
.desc_logo_tile {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 96px;
	height: 96px;
	background-color: #ffffff;
	border: 1px solid #C0C0C0;
	border-radius: 50%;
	cursor: pointer;
	/* overflow:visible so the small "×" remove button can sit on
	   the circle's upper-right edge without being clipped. The
	   image is clipped to a circle via clip-path on the <img>. */
	overflow: visible;
	outline: none;
	transition: background-color 0.12s ease, border-color 0.12s ease;
}
/* Blue hover affordance only applies to the empty state — when a
   logo is already set the user just needs the × remove control,
   not another "click to upload" cue. */
.desc_logo_tile:not(.desc_logo_tile_has):hover {
	background-color: rgba(38, 157, 240, 0.08);
	border-color: #269DF0;
}
.desc_logo_tile:focus-visible {
	outline: 2px solid #4a90e2;
	outline-offset: -1px;
}
.desc_logo_tile img {
	width: 100%;
	height: 100%;
	display: block;
	object-fit: cover;
	clip-path: circle(50%);
}
.desc_logo_placeholder {
	font-size: 28px;
	color: #C0C0C0;
}
.desc_logo_tile:not(.desc_logo_tile_has):hover .desc_logo_placeholder { color: #269DF0; }
.desc_logo_remove {
	position: absolute;
	top: -2px;
	right: -2px;
	width: 22px;
	height: 22px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 50%;
	background-color: rgba(0, 0, 0, 0.55);
	color: #fff;
	font-size: 11px;
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.12s ease, background-color 0.12s ease;
}
.desc_logo_tile_has:hover .desc_logo_remove,
.desc_logo_tile_has:focus-within .desc_logo_remove { opacity: 1; }
.desc_logo_remove:hover { background-color: #d2453a; }

/* Dark-mode tile mirrors the input/textarea convention: same
   --bg-elev fill and --border-strong stroke as desc_input et al.,
   so the icon reads as a real form control. */
body.appbuilder-dark .desc_logo_tile {
	background-color: var(--bg-elev, #242424);
	border: 1px solid var(--border-strong, #505050);
}
body.appbuilder-dark .desc_logo_tile:not(.desc_logo_tile_has):hover {
	background-color: rgba(38, 157, 240, 0.12);
	border-color: #4a90e2;
}
body.appbuilder-dark .desc_logo_placeholder { color: var(--fg-muted, #a0a0a0); }
body.appbuilder-dark .desc_logo_tile:not(.desc_logo_tile_has):hover .desc_logo_placeholder { color: #6FB8F5; }

/* Whole-section drop state — applied while a file is being dragged
   over the Logo section card. Blue-tinted bg + 2px dashed accent
   border, with an absolutely-positioned overlay message rendered
   via ::after so we don't need extra DOM. The section is already
   .desc_section (position: static); make it relative so the
   overlay anchors correctly. */
.desc_section[data-desc-section='logo'] {
	position: relative;
}
.desc_section.desc_section_dropping {
	background-color: rgba(38, 157, 240, 0.08) !important;
	border: 2px dotted #269DF0 !important;
	/* Compensate for the +1px border width so nothing shifts. */
	padding: 17px 19px;
}
.desc_section.desc_section_dropping::after {
	content: 'Drop an image to set as logo';
	position: absolute;
	left: 0; right: 0; bottom: 12px;
	text-align: center;
	font: 600 12px OpenSans, sans-serif;
	color: #269DF0;
	letter-spacing: 0.02em;
	pointer-events: none;
}
body.appbuilder-dark .desc_section.desc_section_dropping {
	background-color: rgba(38, 157, 240, 0.12) !important;
	border-color: #4a90e2 !important;
}
body.appbuilder-dark .desc_section.desc_section_dropping::after {
	color: #6FB8F5;
}
@media (max-width: 900px) {
	.desc_layout { grid-template-columns: 1fr; }
	.desc_rail { position: static; }
}

/* ==============================================================
 * Cover Page — first build step (Phase 1: static layout, dummy
 * metrics, wired navigation). Color tokens fall through to
 * dark-mode --bg/--bg-alt/--border/--text variables where set.
 * ============================================================== */
:root {
	--cp-accent:        #269DF0;
	--cp-accent-strong: #1F84C6;
	--cp-muted:         #808080;
	--cp-card-bg:       #ffffff;
	--cp-card-border:   #e2e2e2;
	--cp-page-bg:       #FAF8F5;
	--cp-text:          #27251E;
	--cp-text-soft:     #808080;
}
body.appbuilder-dark {
	--cp-card-bg:     var(--bg-alt, #1b1d22);
	--cp-card-border: var(--border, #2a2d33);
	--cp-page-bg:     var(--bg, #14161a);
	--cp-text:        var(--text, #e6e6e6);
	--cp-text-soft:   #b7bcc4;
}

.coverpage_body {
	width: 100%;
	height: 100%;
	overflow-y: auto;
	box-sizing: border-box;
	padding: 24px 28px 32px;
	background-color: var(--cp-page-bg);
	color: var(--cp-text);
	font-family: OpenSans, sans-serif;
}

/* --- Header band ------------------------------------------------ */
.cp_header {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 360px;
	gap: 24px;
	align-items: stretch;
}
.cp_header_left {
	min-width: 0;
	background-color: #ffffff;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	padding: 16px 18px;
	box-sizing: border-box;
}
body.appbuilder-dark .cp_header_left {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
.cp_breadcrumb {
	font-size: 11px;
	letter-spacing: 0.08em;
	color: var(--cp-text-soft);
	margin-bottom: 6px;
}
.cp_title {
	font-size: 26px;
	font-weight: 600;
	line-height: 1.2;
	margin-bottom: 8px;
}
.cp_tagline {
	font-size: 13px;
	color: var(--cp-text-soft);
	line-height: 1.5;
	margin-bottom: 18px;
}
.cp_kpis {
	display: flex;
	gap: 32px;
	border-top: 1px solid var(--cp-card-border);
	padding-top: 14px;
}
.cp_kpi_value {
	font-size: 22px;
	font-weight: 600;
	color: var(--cp-text);
}
.cp_kpi_label {
	font-size: 11px;
	color: var(--cp-text-soft);
	margin-top: 2px;
}
.cp_kpi_clickable {
	cursor: pointer;
	border-radius: 6px;
	padding: 2px 6px;
	margin: -2px -6px;
	transition: background-color 120ms ease;
}
.cp_kpi_clickable:hover {
	background-color: var(--bg-hover, rgba(38, 157, 240, 0.08));
}

/* LLM cost modal (click on Build cost / Test cost tiles). */
.llm_cost_modal {
	padding: 14px 16px;
	font-family: OpenSans, sans-serif;
}
.llm_cost_summary {
	display: flex;
	gap: 28px;
	border-bottom: 1px solid var(--bg-hover, #eee);
	padding-bottom: 10px;
	margin-bottom: 10px;
}
.llm_cost_summary_item {
	display: flex;
	flex-direction: column;
}
.llm_cost_summary_value {
	font-size: 18px;
	font-weight: 600;
}
.llm_cost_summary_label {
	font-size: 11px;
	color: var(--fg-muted, #808080);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.llm_cost_intro {
	font-size: 11px;
	color: var(--fg-muted, #808080);
	margin-bottom: 8px;
}
.llm_cost_table {
	width: 100%;
	border-collapse: collapse;
	font-size: 12px;
}
.llm_cost_table th {
	text-align: left;
	font-weight: 600;
	color: var(--fg-muted, #808080);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-size: 10px;
	padding: 6px 8px;
	border-bottom: 1px solid var(--bg-hover, #eee);
}
.llm_cost_table td {
	padding: 6px 8px;
	border-bottom: 1px solid var(--bg-hover, #f3f3f3);
	vertical-align: top;
}
.llm_cost_ts     { white-space: nowrap; color: var(--fg-muted, #808080); }
.llm_cost_label  { font-weight: 500; }
.llm_cost_fn     { font-size: 11px; color: var(--fg-muted, #808080); margin-top: 2px; }
.llm_cost_model  { white-space: nowrap; }
.llm_cost_tokens { white-space: nowrap; }
.llm_cost_usd    { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
.llm_cost_empty  { text-align: center; color: var(--fg-muted, #808080); padding: 16px; }

.cp_resume {
	background-color: #ffffff;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	padding: 16px 18px;
	display: flex;
	flex-direction: column;
	gap: 8px;
	box-sizing: border-box;
}
body.appbuilder-dark .cp_resume {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
.cp_resume_label {
	font-size: 10px;
	letter-spacing: 0.1em;
	color: var(--cp-text-soft);
}
.cp_resume_title {
	font-size: 16px;
	font-weight: 600;
}
.cp_resume_sub {
	font-size: 12px;
	color: var(--cp-text-soft);
	line-height: 1.4;
	flex: 1 1 auto;
}
.cp_resume_actions {
	display: flex;
	gap: 8px;
	margin-top: 4px;
}
.cp_btn_primary, .cp_btn_secondary {
	height: 32px;
	padding: 0 14px;
	border-radius: 6px;
	font-size: 13px;
	font-family: OpenSans, sans-serif;
	cursor: pointer;
	border: 1px solid transparent;
}
.cp_btn_primary {
	background-color: var(--cp-accent);
	color: #fff;
	border-color: var(--cp-accent);
}
.cp_btn_primary:hover { background-color: var(--cp-accent-strong); border-color: var(--cp-accent-strong); }
.cp_btn_secondary {
	background-color: transparent;
	color: var(--cp-text);
	border-color: var(--cp-card-border);
}
.cp_btn_secondary:hover { background-color: var(--cp-card-border); }
.cp_resume_progress {
	height: 3px;
	background-color: var(--cp-card-border);
	border-radius: 2px;
	overflow: hidden;
	margin-top: 6px;
}
.cp_resume_progress_fill {
	height: 100%;
	background-color: var(--cp-accent);
	border-radius: 2px;
}

/* --- Pipeline stepper ------------------------------------------ */
.cp_pipeline {
	margin-top: 24px;
	padding: 18px 24px;
	background-color: #ffffff;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	display: flex;
	align-items: flex-start;
	gap: 0;
	box-sizing: border-box;
}
body.appbuilder-dark .cp_pipeline {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
.cp_pipeline_node {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	min-width: 70px;
	cursor: pointer;
	outline: none;
	padding: 4px;
	border-radius: 6px;
}
.cp_pipeline_node:hover, .cp_pipeline_node:focus { background-color: rgba(38, 157, 240, 0.08); }
.cp_pipeline_circle {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 13px;
	font-weight: 600;
	box-sizing: border-box;
}
.cp_pipeline_node_done .cp_pipeline_circle {
	background-color: var(--cp-accent);
	color: #fff;
}
.cp_pipeline_node_inprogress .cp_pipeline_circle {
	background-color: transparent;
	border: 2px solid var(--cp-accent);
	color: var(--cp-accent);
}
.cp_pipeline_node_notstarted .cp_pipeline_circle {
	background-color: transparent;
	border: 1px solid var(--cp-muted);
	color: var(--cp-muted);
}
.cp_pipeline_name {
	font-size: 12px;
	font-weight: 600;
	color: var(--cp-text);
	text-align: center;
}
.cp_pipeline_node_notstarted .cp_pipeline_name { color: var(--cp-muted); font-weight: 500; }
.cp_pipeline_status {
	font-size: 10px;
	color: var(--cp-text-soft);
}
.cp_pipeline_node_done       .cp_pipeline_status { color: var(--cp-accent); }
.cp_pipeline_node_inprogress .cp_pipeline_status { color: var(--cp-accent); }
.cp_pipeline_connector {
	flex: 1 1 auto;
	height: 1px;
	background-color: var(--cp-card-border);
	margin-top: 20px;
	min-width: 12px;
}
.cp_pipeline_connector_done { background-color: var(--cp-accent); }

/* --- 8 steps section ------------------------------------------- */
.cp_steps_section { margin-top: 24px; }
.cp_steps_header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 12px;
}
.cp_steps_title { font-size: 16px; font-weight: 600; }
.cp_filters { display: flex; gap: 6px; }
.cp_filter {
	height: 28px;
	padding: 0 12px;
	border-radius: 14px;
	border: 1px solid var(--cp-card-border);
	background-color: transparent;
	font-size: 12px;
	color: var(--cp-text-soft);
	cursor: pointer;
	font-family: OpenSans, sans-serif;
}
.cp_filter:hover { background-color: rgba(38, 157, 240, 0.08); }
.cp_filter_active {
	background-color: var(--cp-accent);
	border-color: var(--cp-accent);
	color: #fff;
}
.cp_filter_count {
	display: inline-block;
	margin-left: 4px;
	font-weight: 600;
	opacity: 0.85;
}

/* Step grid. Column count, card width and gap are recomputed in
   JS (_LayoutCoverpageGrid) so we can satisfy all three constraints
   at once — capped card width [280, 360], capped gap [8, 16], and
   rows that fill the container edge-to-edge when more cards exist
   than fit on a single row. The values here are first-paint fallbacks
   used until ResizeObserver fires. */
.cp_cards_grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 360px));
	gap: 12px;
}

/* Step cards reuse the Thesaurus/Builder widget look: soft neutral
   border on a white card, gentle gray hover. The blue accent is
   reserved for the *current* step so it stands out. */
.cp_card {
	background-color: #ffffff;
	border: 1px solid #EEECEA;
	border-radius: 12px;
	padding: 14px 16px;
	display: flex;
	flex-direction: column;
	gap: 10px;
	cursor: pointer;
	outline: none;
	transition: background-color 0.15s ease-out;
}
.cp_card:hover, .cp_card:focus { background-color: #f4f4f4; }
body.appbuilder-dark .cp_card {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
body.appbuilder-dark .cp_card:hover,
body.appbuilder-dark .cp_card:focus {
	background-color: #3d3d3d !important;
}
.cp_card_active,
.cp_card_active:hover,
.cp_card_active:focus,
body.appbuilder-dark .cp_card_active,
body.appbuilder-dark .cp_card_active:hover,
body.appbuilder-dark .cp_card_active:focus {
	border-color: var(--cp-accent) !important;
	box-shadow: inset 0 0 0 1px var(--cp-accent);
}
/* Baseline-align the head row so the step number and the status
   pill sit on the SAME baseline as the title — `flex-start` made
   the smaller-font number visually float above the title because
   its line box was shorter than the title's. With `baseline`,
   all three line up on the title's first-line baseline regardless
   of the title wrapping. */
.cp_card_head {
	display: flex;
	align-items: baseline;
	gap: 8px;
}
.cp_card_num {
	font-size: 11px;
	font-weight: 700;
	color: var(--cp-text-soft);
	letter-spacing: 0.04em;
	line-height: 1.3;
	flex: 0 0 auto;
}
.cp_card_title {
	font-size: 14px;
	font-weight: 600;
	line-height: 1.3;
	flex: 1 1 auto;
}
.cp_pill {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font-size: 11px;
	line-height: 1.3;
	padding: 2px 8px;
	border-radius: 10px;
	font-weight: 500;
	white-space: nowrap;
	flex: 0 0 auto;
}
.cp_pill_dot { width: 6px; height: 6px; border-radius: 50%; background-color: currentColor; }
.cp_pill_done       { background-color: rgba(38, 157, 240, 0.15); color: var(--cp-accent); }
.cp_pill_inprogress { background-color: rgba(38, 157, 240, 0.15); color: var(--cp-accent); }
.cp_pill_notstarted { background-color: rgba(154, 160, 166, 0.18); color: var(--cp-muted); }

.cp_card_desc {
	font-size: 12px;
	color: var(--cp-text-soft);
	line-height: 1.45;
}
/* Push the entire "bottom block" (progress label + bar + metric
   chips + footer) to the bottom of the card. Cards in a row are
   stretched to equal height by the grid, so margin-top:auto on the
   first item of the block makes every card's progress bar / chips /
   footer line up at the same Y position across the row, no matter
   how short or long each description is. */
.cp_card_progress_row {
	display: flex;
	justify-content: space-between;
	font-size: 11px;
	color: var(--cp-text-soft);
	margin-top: auto;
}
.cp_card_progress_value { font-weight: 600; color: var(--cp-text); }
.cp_card_bar {
	height: 4px;
	background-color: var(--cp-card-border);
	border-radius: 2px;
	overflow: hidden;
}
.cp_card_bar_fill            { height: 100%; border-radius: 2px; }
.cp_card_bar_fill_done       { background-color: var(--cp-accent); }
.cp_card_bar_fill_inprogress { background-color: var(--cp-accent); }
.cp_card_bar_fill_notstarted { background-color: var(--cp-muted); opacity: 0.4; }

.cp_card_metrics {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	font-size: 11px;
	color: var(--cp-text-soft);
}
.cp_metric_value { font-weight: 700; color: var(--cp-text); margin-right: 2px; }

.cp_card_foot {
	display: flex;
	justify-content: space-between;
	align-items: center;
	font-size: 11px;
	color: var(--cp-text-soft);
	border-top: 1px solid var(--cp-card-border);
	padding-top: 8px;
}
.cp_card_action {
	font-weight: 600;
	cursor: pointer;
}
.cp_card_action_done       { color: var(--cp-accent); }
.cp_card_action_inprogress { color: var(--cp-accent); }
.cp_card_action_notstarted { color: var(--cp-muted); }

/* "Mark as done" / "Reopen" toggle in each card footer. Visually
   secondary to the navigate link on the right, so it sits in the
   middle of the foot row as a small text-button. */
/* "Mark as done" / "Reopen" toggle in the card footer. Pill-shaped
   so it reads as an actionable control between the muted "Updated"
   label on the left and the navigate link on the right. */
.cp_card_review {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	background-color: rgba(154, 160, 166, 0.12);
	border: 1px solid var(--cp-card-border);
	border-radius: 12px;
	padding: 3px 10px;
	font-family: OpenSans, sans-serif;
	font-size: 11px;
	font-weight: 600;
	color: var(--cp-text);
	cursor: pointer;
}
.cp_card_review:hover {
	background-color: rgba(38, 157, 240, 0.12);
	border-color: var(--cp-accent);
	color: var(--cp-accent);
}
.cp_card_review .fa { font-size: 10px; }
body.appbuilder-dark .cp_card_review {
	background-color: rgba(154, 160, 166, 0.18);
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .cp_card_review:hover {
	background-color: rgba(38, 157, 240, 0.18);
	color: #6FB8F5;
	border-color: #6FB8F5;
}

/* Kill scroll on the enclosing w2ui-panel-content that wraps the
   overview leftbar — it holds only two fixed items, so there's no
   reason to ever scroll. Defends against a rare race where the
   main-panel form's auto-focus triggers a scroll on the nearest
   overflow:auto ancestor, clipping the first item ("Identity Card")
   out of view. */
.w2ui-panel-content:has(> .builder-leftbar-home) {
	overflow: visible !important;
}

.builder-leftbar-home div {
	line-height: 24px;
	font-family: OpenSans;
	font-size: 14px;
	color: #27251E;
	cursor: pointer;
	padding: 4px;
	border-radius:4px;
	margin: 2px;
	user-select: none;
}

.builder-leftbar-home div[selected] {
	background-color: white !important;
	color: black;
/*	
	background-color: #D9EAFE !important;
	color: rgb(1, 117, 255);
*/	
}

.builder-leftbar-home div:hover {
	background-color: #EAE8E4;
}

/* The home pinned section is a logical group, not a visual box —
   `display:contents` makes its children siblings of the static
   home entries (My Tasks, …) so the section's own div doesn't
   pick up the leftbar's div-level padding/hover background and
   accidentally light up when the user hovers a child. */
.builder-leftbar-home div#id_home_pinned_section {
	display: contents;
}

/* Pinned dashboard entry on the home leftbar — clamp long names
   to a single line with an ellipsis so the leftbar width stays
   stable when a dashboard has a long title. */
.builder-leftbar-home div.builder-leftbar-home-pinned {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Vote bar under an inline Prismo chart in a thread. 👍 saves
   the (prompt, spec) pair into the charts KB so future
   resolves can retrieve this widget as a few-shot. */
.builder-thread-chart-vote {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-top: 6px;
	padding: 4px 4px 0 4px;
	font-size: 12px;
	color: #888;
}
.builder-thread-chart-vote i {
	cursor: pointer;
	font-size: 14px;
	color: #888;
	transition: color 120ms ease;
}
.builder-thread-chart-vote i.fa-thumbs-o-up:hover { color: #2e7d32; }
.builder-thread-chart-vote i.fa-thumbs-up        { color: #2e7d32; cursor: default; }
body.appbuilder-dark .builder-thread-chart-vote   i { color: #aaa; }
body.appbuilder-dark .builder-thread-chart-vote   i.fa-thumbs-o-up:hover { color: #81C784; }
body.appbuilder-dark .builder-thread-chart-vote   i.fa-thumbs-up        { color: #81C784; }

/* Inline "Dashboard ready" card emitted by Prismo in a thread.
   Click opens the dashboard in the right panel of the thread. */
.builder-thread-dashboard-card {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 14px;
	border: 1px solid #d9d6d0;
	border-radius: 6px;
	background: #fff;
	cursor: pointer;
	transition: background 120ms ease, border-color 120ms ease;
}
.builder-thread-dashboard-card:hover {
	background: #f4f1ec;
	border-color: #c0bdb6;
}
.builder-thread-dashboard-card .fa-pie-chart { color: #2F9EEE; font-size: 18px; }
.builder-thread-dashboard-card .fa-external-link { color: #888; font-size: 12px; }
.builder-thread-dashboard-card-text { flex: 1 1 auto; min-width: 0; }
.builder-thread-dashboard-card-title {
	font-size: 13px;
	color: #27251E;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-thread-dashboard-card-meta {
	font-size: 11px;
	color: #888;
	margin-top: 2px;
}
body.appbuilder-dark .builder-thread-dashboard-card {
	background: #2b2b2b;
	border-color: #3a3a3a;
}
body.appbuilder-dark .builder-thread-dashboard-card:hover { background: #333; }
body.appbuilder-dark .builder-thread-dashboard-card-title { color: #e6e6e6; }

/* -----------------------------------------------------------------
   Phase 3 — Artifact card. A standalone, richer presentation than
   the dashboard card: tinted file-icon tile on the left, two-line
   metadata, "Open" pill on the right. Office-style — instantly
   readable as "here's a document I made for you".
   ----------------------------------------------------------------- */
.builder-thread-artifact-card {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 12px 14px;
	border: 1px solid #d9d6d0;
	border-radius: 10px;
	background: #fff;
	cursor: pointer;
	font-family: OpenSans;
	transition: background 120ms ease, border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
.builder-thread-artifact-card:hover {
	background: #fafaf7;
	border-color: #c0bdb6;
	transform: translateY(-1px);
	box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}
.builder-thread-artifact-card-icon {
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 8px;
	background: rgba(43, 87, 154, 0.10);
	color: #2b579a; /* Word blue by default */
	font-size: 22px;
}
.builder-thread-artifact-card-xlsx .builder-thread-artifact-card-icon {
	background: rgba(31, 122, 60, 0.10); color: #1f7a3c;
}
.builder-thread-artifact-card-pptx .builder-thread-artifact-card-icon {
	background: rgba(213, 91, 30, 0.10); color: #d55b1e;
}
.builder-thread-artifact-card-pdf .builder-thread-artifact-card-icon {
	background: rgba(192, 57, 43, 0.10); color: #c0392b;
}
.builder-thread-artifact-card-body {
	flex: 1 1 auto;
	min-width: 0;
}
.builder-thread-artifact-card-title {
	font-family: OpenSans;
	font-size: 14px;
	font-weight: 600;
	color: #27251e;
	line-height: 1.25;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-thread-artifact-card-meta {
	margin-top: 3px;
	font-family: OpenSans;
	font-size: 12px;
	color: #6e6e76;
	display: flex;
	align-items: center;
	gap: 6px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-thread-artifact-card-meta .fa { font-size: 11px; opacity: 0.7; }
.builder-thread-artifact-card-action {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 12px;
	border-radius: 999px;
	background: rgba(74, 144, 226, 0.10);
	color: #4a90e2;
	font-family: OpenSans;
	font-size: 12px;
	font-weight: 600;
}
.builder-thread-artifact-card:hover .builder-thread-artifact-card-action {
	background: rgba(74, 144, 226, 0.20);
}
body.appbuilder-dark .builder-thread-artifact-card {
	background: #2b2b30;
	border-color: #3a3a40;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
body.appbuilder-dark .builder-thread-artifact-card:hover {
	background: #333339;
	border-color: #50505a;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}
body.appbuilder-dark .builder-thread-artifact-card-title { color: #f1f1f4; }
body.appbuilder-dark .builder-thread-artifact-card-meta  { color: #a5a8b9; }
body.appbuilder-dark .builder-thread-artifact-card-icon {
	background: rgba(122, 177, 240, 0.12);
	color: #7AB1F0;
}
body.appbuilder-dark .builder-thread-artifact-card-xlsx .builder-thread-artifact-card-icon {
	background: rgba(88, 200, 132, 0.12); color: #58c884;
}
body.appbuilder-dark .builder-thread-artifact-card-pptx .builder-thread-artifact-card-icon {
	background: rgba(255, 153, 102, 0.12); color: #ff9966;
}
body.appbuilder-dark .builder-thread-artifact-card-pdf .builder-thread-artifact-card-icon {
	background: rgba(239, 110, 94, 0.12); color: #ef6e5e;
}
body.appbuilder-dark .builder-thread-artifact-card-action {
	background: rgba(122, 177, 240, 0.16);
	color: #7AB1F0;
}
body.appbuilder-dark .builder-thread-artifact-card:hover .builder-thread-artifact-card-action {
	background: rgba(122, 177, 240, 0.28);
}

/* -----------------------------------------------------------------
   Phase 3 — Skill artifact side view (right panel). All text in
   OpenSans (the old inline styles inherited Times New Roman in some
   contexts); standard pill download button; tab strip with an
   active state; Payload <pre> readable in both light and dark mode.
   ----------------------------------------------------------------- */
.skill-artifact-panel {
	width: 100%;
	height: 100%;
	overflow: hidden;
	padding: 10px;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	font-family: OpenSans, sans-serif;
	color: #27251e;
}
.skill-artifact-panel-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 4px 6px 10px;
	margin-bottom: 6px;
	border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.skill-artifact-panel-title {
	flex: 1 1 auto;
	min-width: 0;
	font-family: OpenSans, sans-serif;
	font-size: 14px;
	font-weight: 600;
	color: #27251e;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.skill-artifact-panel-download {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 7px 14px;
	border: none;                 /* reset <button> UA border (Modify reuses this) */
	outline: none;
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	border-radius: 999px;
	background: #4a90e2;
	color: #fff !important;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	transition: background 120ms ease, box-shadow 120ms ease;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.skill-artifact-panel-download:hover {
	background: #3a7dca;
	box-shadow: 0 3px 8px rgba(74, 144, 226, 0.30);
}
.skill-artifact-panel-download .fa { font-size: 12px; }
.skill-artifact-panel-tabs {
	display: flex;
	gap: 6px;
	margin-bottom: 8px;
}
.skill-artifact-panel-tab {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	font-weight: 600;
	padding: 6px 12px;
	border-radius: 999px;
	border: 1px solid transparent;
	background: rgba(0, 0, 0, 0.05);
	color: rgb(80, 81, 96);
	cursor: pointer;
	transition: background 120ms ease, color 120ms ease;
}
.skill-artifact-panel-tab:hover { background: rgba(0, 0, 0, 0.09); }
.skill-artifact-panel-tab-active {
	background: rgba(74, 144, 226, 0.12);
	color: #4a90e2;
}
.skill-artifact-panel-tab-active:hover { background: rgba(74, 144, 226, 0.18); }
.skill-artifact-panel-frame {
	flex: 1 1 auto;
	width: 100%;
	border: 1px solid rgba(0, 0, 0, 0.10);
	border-radius: 8px;
	background: #fff;
}
.skill-artifact-panel-payload {
	flex: 1 1 auto;
	width: 100%;
	margin: 0;
	padding: 12px 14px;
	overflow: auto;
	box-sizing: border-box;
	border: 1px solid rgba(0, 0, 0, 0.10);
	border-radius: 8px;
	background: #fafaf7;
	color: rgb(40, 41, 56);
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 12px;
	line-height: 1.5;
	white-space: pre-wrap;
	word-break: break-word;
}
body.appbuilder-dark .skill-artifact-panel { color: #f1f1f4; }
body.appbuilder-dark .skill-artifact-panel-bar { border-color: rgba(255, 255, 255, 0.10); }
body.appbuilder-dark .skill-artifact-panel-title { color: #f1f1f4; }
body.appbuilder-dark .skill-artifact-panel-tab {
	background: rgba(255, 255, 255, 0.06);
	color: rgb(200, 202, 215);
}
body.appbuilder-dark .skill-artifact-panel-tab:hover { background: rgba(255, 255, 255, 0.10); }
body.appbuilder-dark .skill-artifact-panel-tab-active {
	background: rgba(122, 177, 240, 0.18);
	color: #7AB1F0;
}
body.appbuilder-dark .skill-artifact-panel-tab-active:hover { background: rgba(122, 177, 240, 0.26); }
body.appbuilder-dark .skill-artifact-panel-frame {
	/* Keep the document iframe white in dark mode — Word
	   renders dark text and reflects how the artifact prints.
	   Only the surrounding chrome adopts the dark palette. */
	border-color: rgba(255, 255, 255, 0.12);
	background: #fff;
}
body.appbuilder-dark .skill-artifact-panel-payload {
	background: #2b2b30;
	color: #e8e8ea;
	border-color: rgba(255, 255, 255, 0.12);
}

/* DOCX editor (Apryse) "click to start editing" overlay. The Office Editor
   only accepts keystrokes after a real user gesture (browser user-activation),
   so this one-click layer maximizes + focuses the editor. */
.builder-docx-editor-overlay {
	position: absolute;
	inset: 0;
	z-index: 9;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(255, 255, 255, 0.55);
	cursor: pointer;
}
.builder-docx-editor-unlock {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 12px 22px;
	border: none;
	border-radius: 8px;
	cursor: pointer;
	background: #4a90e2;
	color: #fff;
	font-family: OpenSans, sans-serif;
	font-size: 14px;
	font-weight: 600;
	line-height: 1;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
	transition: background 120ms ease, box-shadow 120ms ease;
}
.builder-docx-editor-unlock:hover {
	background: #3a7dca;
	box-shadow: 0 4px 14px rgba(74, 144, 226, 0.35);
}
body.appbuilder-dark .builder-docx-editor-overlay { background: rgba(18, 20, 24, 0.55); }

/* ===== MCP Apps (2026-01-26) — server-supplied UI host =====
   Small self-sized visuals render inline with ZERO chrome (no
   border/header/buttons) so they sit in the conversation like a
   native component. App-like ones collapse to a launcher card
   that opens the live app in the threads right-side panel. */
.mcpui-inlinehost { display: block; width: 100%; margin: 2px 0; }
.mcpui-frame {
	width: 100%; height: 360px; border: 0; display: block;
	background: transparent;
}
.mcpui-panelhost { width: 100%; height: 100%; }
.mcpui-panelhost .mcpui-frame { height: 100%; }

/* Launcher card for app-like components. */
.mcpui-launch {
	display: flex; align-items: center; gap: 8px;
	padding: 10px 12px; margin: 4px 0;
	border: 1px solid #d9d9d9; border-radius: 10px;
	background: #f7f9fb; cursor: pointer; font-size: 13px;
	transition: background .12s, border-color .12s;
}
.mcpui-launch:hover { background: #eef3f8; border-color: #b9c6d2; }
.mcpui-launch .fa-plug { color: #2F9EEE; }
.mcpui-launch-text {
	flex: 1 1 auto; font-weight: 600; color: #333;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mcpui-launch-open { color: #2F9EEE; font-weight: 600; white-space: nowrap; }
body.appbuilder-dark .mcpui-launch {
	background: #232323; border-color: #3a3a3a;
}
body.appbuilder-dark .mcpui-launch:hover { background: #2c2c2c; border-color: #4a4a4a; }
body.appbuilder-dark .mcpui-launch-text { color: #e6e6e6; }

/* Pin-mark icon on Recent / History tiles — small, blue, with a
   tight right margin so it sits as a discreet badge next to the
   dashboard name rather than hijacking the whole row. */
.dash-pin-mark {
	color: #2F9EEE;
	font-size: 10px;
	margin-right: 4px;
	opacity: 0.85;
}

/* Separator between the fixed home entries and the pinned
   dashboards list. Reset div padding so the line itself sits at
   full width without the surrounding entry hover shape. */
.builder-leftbar-home div.builder-leftbar-home-sep {
	height: 1px;
	background-color: #d9d6d0;
	padding: 0;
	margin: 6px 4px;
	border-radius: 0;
	cursor: default;
}
.builder-leftbar-home div.builder-leftbar-home-sep:hover { background-color: #d9d6d0; }
body.appbuilder-dark .builder-leftbar-home div.builder-leftbar-home-sep { background-color: #3a3a3a; }
body.appbuilder-dark .builder-leftbar-home div.builder-leftbar-home-sep:hover { background-color: #3a3a3a; }


.anylist_empty {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	font-family: OpenSans;
	font-size: 24px;
	text-align: center;
	color: rgb(115, 116, 133);
	/* Sized for a one-line "no matches" in a full panel. Without an explicit
	   line-height a wrapped sentence collides with itself at 24px, and callers
	   that explain WHY a list is empty need more than one line. */
	line-height: 1.35;
}


.favorites_container {
	width:100%;
	height:100%;
	overflow:hidden;
	overflow-y:auto;
	overflow-x:auto;
	font-family: OpenSans;
	font-size: 14px;
	cursor: default;
	padding: 8px;
	box-sizing: border-box;
}

.favorites_container div[expanded]
{
	padding: 8px;
	padding-left:0px;
	margin-bottom:4px;
}

.favorites_container div[expanded] > span
{
	background-image: url(../images/smallcollapse.png);
	background-position: right 4px center;
	background-repeat: no-repeat;
	border-radius: 6px;
	padding: 8px;
	padding-right:20px;
	user-select: none;
	cursor: pointer;
}

.favorites_container div[expanded] > span:hover
{
	background-color: #EAEAEA;
}

.favorites_container div[collapsed]
{
	padding: 8px;
	padding-left:0px;
}

.favorites_container div[collapsed] > span
{
	background-image: url(../images/smallexpand.png);
	background-position: right 4px center;
	background-repeat: no-repeat;
	border-radius: 6px;
	padding: 8px;
	padding-right:20px;
	user-select: none;
	cursor: pointer;
}

.favorites_container div[collapsed] > span:hover
{
	background-color: #F1F1F1;
}


.applications_element_template {
	margin-top: 6px !important;
	font-size: 11px !important;
	color: #8A6B1A !important;
	background-color: rgba(230, 168, 23, 0.10);
	border: 1px solid rgba(230, 168, 23, 0.35);
	border-radius: 10px;
	padding: 2px 8px !important;
	display: inline-block;
}

/* Description on application cards — clamp to 3 lines so a long blurb
   doesn't push the Published badge / provenance row out of view. The
   full text is preserved as a tooltip via the title attribute. */
.applications_element_desc {
	display: -webkit-box !important;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
	line-height: 1.4;
}

/* Provenance footer on application cards — creator + creation date.
   Kept visually subdued so the name/description stay primary. */
.applications_element_meta {
	margin-top: 8px !important;
	font-size: 11px !important;
	color: #888888 !important;
}
.applications_element_meta i {
	margin-right: 4px;
	opacity: 0.75;
}
body.appbuilder-dark .applications_element_meta {
	color: #9e9e9e !important;
}
.applications_element_template i {
	margin-right: 4px;
}
body.appbuilder-dark .applications_element_template {
	color: #F6C34A !important;
	background-color: rgba(246, 195, 74, 0.08);
	border-color: rgba(246, 195, 74, 0.35);
}

/* "Published vN · date" badge on application cards.  Pinned to the
   bottom-left of the card's text container so it always sits in the
   same spot regardless of how long the description is. */
.applications_element_published {
	position: absolute;
	left: 0;
	bottom: 6px;
	font-size: 11px !important;
	color: #2e7d32 !important;
	background-color: rgba(46, 125, 50, 0.10);
	border: 1px solid rgba(46, 125, 50, 0.35);
	border-radius: 10px;
	padding: 2px 8px !important;
	display: inline-block;
}
.applications_element_published i {
	margin-right: 4px;
}
body.appbuilder-dark .applications_element_published {
	color: #7DD188 !important;
	background-color: rgba(125, 209, 136, 0.08);
	border-color: rgba(125, 209, 136, 0.35);
}

/* "Running vN" pill on application cards — replaces the green Published
   chip when this app is the one this connection is currently running.
   Click anywhere on the card to re-enter the live session. Same fixed
   bottom anchor as the published badge. */
.applications_element_running {
	position: absolute;
	left: 0;
	bottom: 6px;
	font-size: 11px !important;
	color: #fff !important;
	background-color: #C25700;
	border: 1px solid #A04400;
	border-radius: 10px;
	padding: 3px 10px !important;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
}
.applications_element_running i.fa-bolt { font-size: 10px; }
.applications_element_running_resume {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 1px 8px;
	border-radius: 8px;
	background: rgba(255,255,255,0.18);
	font-size: 10px;
	letter-spacing: 0.4px;
}
.applications_element_running_resume .fa { font-size: 10px; }
.applications_element:hover .applications_element_running_resume { background: rgba(255,255,255,0.30); }

body.appbuilder-dark .applications_element_running {
	background-color: #C25700;
	border-color: #8B3F00;
}

.applications_toolbar_title
{
	display: flex;
	align-items: center;
	height: 100%;
	padding: 0 10px 0 6px;
	font-family: OpenSans, sans-serif;
	font-size: 15px;
	font-weight: 600;
	color: #2C2C2C;
	letter-spacing: 0.2px;
	user-select: none;
	white-space: nowrap;
}
body.appbuilder-dark .applications_toolbar_title {
	color: #E8E8E8;
}
/* Dashboard panel title shows the dashboard name itself (set
   via GetPanelTitle override). Drop the bold so it reads as a
   neutral label rather than a section header. */
.applications_toolbar_title.is-dashboard-title {
	font-weight: 400;
}


.applications_container
{
	width:100%;
	height:100%;
	/*display:table-cell; */
	padding:12px;
	overflow:hidden;
	overflow-y: auto;
	box-sizing: border-box;
}

.applications_element
{
	width:308px;
	height:166px;
	border:1px solid #EEECEA;
	background-color:white;
	border-radius: 12px;
	margin-right:12px;
	margin-bottom:12px;
	padding:6px;
	position: relative;
	display:inline-block;
	cursor: pointer;
	transition: background-color 0.15s ease-out;
}

.applications_element:hover
{
	background-color: #f4f4f4;
}



.applications_element_logo
{
	position:absolute;
	left:10px;
	top:10px;
	width:40px;
	height:40px;
	overflow:hidden;
	border-radius:20px;
}

.applications_element_logo > img
{
	position:absolute;
	top:0;
	left:50%;
	height:100%;
	transform: translate(-50%, 0%);
	object-fit: cover;
}

/* Marketplace panel: tint the (otherwise blue #269DF0) DEFAULT
   logo to match the amber #E6A817 used by the template badge in
   My Applications. Custom logos uploaded by the user keep their
   original colors — only the fallback chapsicon2 gets the hue
   shift.
   Hue shift blue(206°) → amber(42°) = +196°; saturation/lightness
   tweaked to hit the same visual warmth. */
.applications-panel-marketplace .applications_element_logo > img.applications_element_logo_default {
	filter: hue-rotate(196deg) saturate(0.95) brightness(0.95);
}

.applications_element_text
{
	position:absolute;
	left:56px;
	top:10px;
	width:238px;
	height:156px;
	color: #808080;
	user-select: none;
	font-family: OpenSans;
	font-size: 12px;
	overflow: hidden;
	text-overflow: ellipsis;
}


.applications_element_text > span
{
	font-weight: bold;
	user-select: none;
	line-height:20px;
}


.applications_element_text > p
{
	overflow:hidden;
	line-height:16px;
	margin:0px;
}




.agents_body {
	width:100%;
	height:100%;
	padding:6px;
	overflow:hidden;
	overflow-y: auto;
	display:table-cell;
	overflow:hidden;
}

.agents_body_element {
	width:240px;
	height: 130px;
	border:1px solid #EEECEA;
	background-color: white;
	display:inline-block;
	margin-right:12px;
	margin-bottom:12px;
	border-radius: 12px;
	padding:6px;
	cursor: pointer;
	position: relative;
	transition: background-color 0.15s ease-out;
}


.agents_body_element_logo
{
	position:absolute;
	left:10px;
	top:16px;
	width:40px;
	height:40px;
	overflow:hidden;
	border-radius:20px;
}

.agents_body_element_logo > img
{
	position:absolute;
	top:0;
	left:50%;
	height:100%;
	transform: translate(-50%, 0%);
	object-fit: cover;
}

.agents_body_element_text
{
	position:absolute;
	left:56px;
	top:12px;
	width:188px;
	height:120px;
	overflow:hidden;
	text-overflow: ellipsis;
	color: #808080;
	user-select: none;
	font-family: OpenSans;
	font-size: 11px;
	line-height:16px;
}


.agents_body_element_text > span
{
	font-weight: bold;
	user-select: none;
	font-size: 12px;
	line-height:20px;
	white-space: nowrap;
}


.agents_body_element:hover
{
	background-color: #f4f4f4;
}


.application_body {
	width:100%;
	height:100%;
	padding:12px;
	overflow:hidden;
	overflow-y: auto;
	box-sizing: border-box;
	
}

.application_chat {
	width:100%;
	height:100%;
}

.application_element {
	margin-right:8px;
	margin-bottom:8px;
	border:1px solid #EEECEA;
	background-color:white;
	border-radius: 12px;
	padding: 8px;
	width: calc(100% - 40px);
	min-height: 40px;
	box-sizing: border-box;
	font-family: OpenSans;
	font-size: 12px;
	position: relative;
	display:inline-block;
	cursor: pointer;
	transition: background-color 0.15s ease-out;
	user-select: none;
}

.application_element:hover
{
	background-color: #f4f4f4;
}
	
.application_element div[collapse] {
	color: #27251E;
	font-size: 12px;
	padding: 4px;
}


.application_element div[expand] {
	color: #27251E;
	font-size: 12px;
	padding: 4px;
}

/* Column drag & drop reordering (datamodel step) */
.col-drag-grip {
	width: 12px;
	color: #C8C4BE;
	cursor: grab;
	font-size: 10px;
}
.application_element_compact[draggable="true"],
.application_element[draggable="true"] {
	cursor: grab;
}
.col-dragging {
	opacity: 0.4;
}
.col-drop-before {
	box-shadow: inset 0 2px 0 0 #0078D4;
}
.col-drop-after {
	box-shadow: inset 0 -2px 0 0 #0078D4;
}

/* Nested column / relationship rows live inside a table card — strip the
   default .application_element card styling so their title aligns with the
   compact (collapsed) version's title and there's no vertical jump when
   the user expands a column. */
.application_element[data-coldrag],
.application_element[data-relname] {
	display: block;
	padding: 0 0 4px 10px;
	margin: 0 0 4px 0;
	min-height: 0;
	border: 0;
	background-color: transparent;
	border-radius: 0;
	box-shadow: none;
}

/* Data model toolbar type-filter chips — match the widget's .tag-type chip. */
.dm-filter-chip {
	height: 22px;
	line-height: 20px;
	border-radius: 11px;
	border: 1px solid #d0d0d0;
	background: transparent;
	color: #888;
	font-family: OpenSans;
	font-size: 11px;
	padding: 0 12px;
	margin: 0 3px;
	cursor: pointer;
	box-shadow: none;
	vertical-align: middle;
}
.dm-filter-chip:hover {
	background-color: rgba(0, 0, 0, 0.04);
}
.dm-filter-chip.dm-on {
	background-color: #F4DED1;
	color: #000;
	border-color: transparent;
}
body.appbuilder-dark .dm-filter-chip {
	border-color: var(--border);
	color: var(--fg-muted);
}
body.appbuilder-dark .dm-filter-chip:hover {
	background-color: rgba(255, 255, 255, 0.05);
}
body.appbuilder-dark .dm-filter-chip.dm-on {
	background-color: rgba(244, 180, 140, 0.2);
	color: #e8b89a;
	border-color: transparent;
}

/* Read-only "html" form fields (email / url renders in entry forms).
   w2form's type:'html' has no input chrome, so a clickable link sits
   bare on the card with the label floating above it and zero vertical
   alignment with the surrounding readonly text inputs. We wrap the
   link in .builder-readonly-html and apply input-style chrome here so
   it matches its neighbours in both light and dark modes. */
/* Tags field (w2ui type:'enum') — renders an underlying <input> with
   a `.w2ui-field-helper.w2ui-list` absolute overlay on top. w2ui's
   default overlay carries its own border + light-grey background;
   in dark mode the underlying input is painted dark by the catch-
   all and the overlay still looks light, producing the visible
   "double border" (input border + overlay border at slightly
   different colors). Width is also frozen because the overlay's
   absolute box was sized at render time and doesn't track parent
   resize. Fix: stretch the overlay to the field's full width via
   left:0/right:0, and align its background + border with the
   underlying input so they read as a single field. */
/* Tags overlay — diagnostic confirmed (DOM tree dump):
   - The original <input id="tags"> behind the overlay is 438px
     wide, the .w2ui-list overlay on top is only ~423px wide
     (w2ui's enum widget reserves ~15px on the right of the
     overlay for legacy clear/caret affordance). The input pokes
     out on the right edge and, in dark mode, both elements
     inherit the catch-all dark border — so the user sees TWO
     concentric boxes and the inner one (the overlay) sits
     visibly inset within the outer one (the input).
   - Worse, the input is focusable: clicking the exposed strip
     on the right focuses it and Chrome draws its focus ring,
     creating the "ghost" focus the user kept hitting.

   Fix: erase the underlying input's chrome (no border, no
   background) and make it non-interactive. The .w2ui-list
   overlay then is the only visible element. */
.entry-form-block .w2ui-field-helper.w2ui-list .w2ui-multi-items {
	padding: 4px !important;
	box-sizing: border-box !important;
}
.entry-form-block .w2ui-field-helper.w2ui-list .w2ui-multi-items .li-item {
	margin-bottom: 3px !important;
}
/* Hide the underlying <input> behind the tags-enum overlay. Scope
   via :has() — `.w2field` is the base class for every w2field
   widget (including refto's AutocompleteFieldBuilder), so an
   unscoped rule was disabling clicks on refto inputs too. We
   target only fields that contain a .w2ui-list overlay (which is
   what enum/tags fields have). */
.entry-form-block .w2ui-field:has(.w2ui-field-helper.w2ui-list) input.w2ui-input.w2field {
	border: 0 !important;
	background: transparent !important;
	pointer-events: none !important;
	outline: none !important;
}
body.appbuilder-dark .entry-form-block .w2ui-field:has(.w2ui-field-helper.w2ui-list) input.w2ui-input.w2field {
	border: 0 !important;
	background: transparent !important;
}
body.appbuilder-dark .w2ui-field-helper.w2ui-list {
	background-color: var(--bg-input, #2b2b2b) !important;
	border-color: var(--border-strong, #505050) !important;
	color: var(--fg, #e6e6e6);
}
body.appbuilder-dark .w2ui-field-helper.w2ui-list.has-focus,
body.appbuilder-dark .w2ui-field-helper.w2ui-list:focus-within {
	background-color: var(--bg-input, #2b2b2b) !important;
}
/* Read-only tags field — keep the field focusable so the user can
   click into it (e.g. to copy chip text). The overlay itself is
   the tab stop (tabindex=0 set in JS), and a stable focus ring is
   painted via outline. Background stays the input colour even
   when focused so it doesn't flash white in dark mode. */
.w2ui-field-helper.w2ui-list.w2ui-list-readonly {
	cursor: default;
}
body.appbuilder-dark .w2ui-field-helper.w2ui-list.w2ui-list-readonly,
body.appbuilder-dark .w2ui-field-helper.w2ui-list.w2ui-list-readonly.has-focus,
body.appbuilder-dark .w2ui-field-helper.w2ui-list.w2ui-list-readonly:focus-within {
	background-color: var(--bg-input, #2b2b2b) !important;
}
/* Internal text input + multi-item search box should inherit the
   overlay's dark colours rather than fall back to the catch-all
   white-text-on-dark default. */
body.appbuilder-dark .w2ui-field-helper.w2ui-list input[type=text],
body.appbuilder-dark .w2ui-field-helper.w2ui-list .w2ui-multi-items .li-search input[type=text] {
	background-color: transparent !important;
	color: var(--fg, #e6e6e6) !important;
	border: 0 !important;
}

/* Read-only toggles in the entry form — w2ui's default disabled
   styling drops opacity to 0.45 on the label and 0.3 on the toggle
   pill, which makes both look like greyed-out chrome. In RO mode
   the user is reading values, not editing — labels should stay at
   full contrast (just like read-only text inputs do) and the
   toggle pill should read as "locked" rather than "broken". */
.entry-form-block .w2ui-field.w2ui-disabled > label {
	opacity: 1;
}
.entry-form-block input[type="checkbox"].w2ui-toggle:disabled + div {
	opacity: 1;
	cursor: not-allowed;
	/* Slightly muted track + a thin inset shadow that reads as
	   "locked": still recognizable as a toggle, clearly not editable. */
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.entry-form-block input[type="checkbox"].w2ui-toggle:disabled + div > div {
	/* Knob */
	box-shadow: 0px 0px 1px #888, 0 0 0 1px rgba(180, 180, 180, 0.6);
	background-color: #f0f0f0;
}
/* Read-only + checked — keep the blue affordance so the on/off
   state still reads at a glance, but use lighter tones than the
   editable :checked colors (dark blue border + saturated blue fill).
   The lighter palette signals "on, but not editable" instead of
   competing with the active inputs around it. */
.entry-form-block input[type="checkbox"].w2ui-toggle:disabled:checked + div {
	border-color: #a3cdef !important;
	box-shadow: inset 0 0 0 12px #c5e1f7 !important;
}
.entry-form-block input[type="checkbox"].w2ui-toggle:disabled:checked + div > div {
	box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15), 0 0 0 1px #a3cdef !important;
	background-color: #ffffff;
}

body.appbuilder-dark .entry-form-block input[type="checkbox"].w2ui-toggle:disabled + div {
	background-color: var(--bg-input, #2b2b2b);
	border-color: var(--border-strong, #3a3a3a);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
body.appbuilder-dark .entry-form-block input[type="checkbox"].w2ui-toggle:disabled + div > div {
	background-color: #d8d8d8;
	box-shadow: 0px 0px 1px #000, 0 0 0 1px rgba(100, 100, 100, 0.7);
}
body.appbuilder-dark .entry-form-block input[type="checkbox"].w2ui-toggle:disabled:checked + div {
	border-color: #4a7fa8 !important;
	box-shadow: inset 0 0 0 12px #2a4a66 !important;
}
body.appbuilder-dark .entry-form-block input[type="checkbox"].w2ui-toggle:disabled:checked + div > div {
	box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3), 0 0 0 1px #4a7fa8 !important;
	background-color: #ffffff;
}

/* Light-mode form field background — w2ui ships text <input> and
   <textarea> with the same #f8fafa fill, but <select> uses a gradient
   ending at #f8f8f8 (a hair greyer than #f8fafa) which reads as a
   different surface. We force all three to the same background so the
   form row backgrounds line up. */
.entry-form-block input.w2ui-input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]),
.entry-form-block textarea.w2ui-input,
.entry-form-block select.w2ui-input {
	background-color: #f8fafa;
}
/* Drop the gradient on <select> so it picks up the solid fill above —
   keep the dropdown-caret image at its original right-edge position. */
.entry-form-block select.w2ui-input {
	background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAALCAQAAACnzwd+AAAAcklEQVR4AcXMsQFBQQDG4P9tAgC0gJYRQJZgKQMwCqCku6vVAAAA+NJHP4KHOk0aV2pRw61n4BBmyOxKQ8I4ehZeuhd3HTx6DQEGZ7sBfr2OOOOj3Yi43kMKs9sZknofOexqZ8npMygwWZTX51CipP+YA1OiZJbYYg9lAAAAAElFTkSuQmCC');
	background-size: 17px 6px;
	background-position: right center;
	background-repeat: no-repeat;
}

/* Clicking empty space inside the map field row (e.g. left of the
   "Geocode from address" button) used to draw a blue focus / text-
   selection outline because the parent .w2ui-field content area
   grabs focus on click. The map row is tagged with .addr-map-row by
   RenderAddressMaps so we can target it without :has(). Suppress
   outline + box-shadow on the row, its inner content <div>, the map
   host and every descendant; user-select:none kills the text-marquee
   that also reads as a blue selection on empty clicks. */
.w2ui-field.addr-map-row,
.w2ui-field.addr-map-row * {
	user-select: none;
}
/* w2form renders type:'html' fields inside <div class="w2ui-input"
   tabindex="N">. We strip its tabindex and absorb its mousedown
   (see RenderAddressMaps) so it can never receive focus on click —
   that's what was both drawing the blue ring AND triggering the
   tiny layout reflow that "compressed" the map. Keep these rules
   as a safety net in case focus is forced programmatically. */
.w2ui-field.addr-map-row div.w2ui-input,
.w2ui-field.addr-map-row div.w2ui-input:focus,
.w2ui-field.addr-map-row div.w2ui-input:focus-visible,
.w2ui-field.addr-map-row div.w2ui-input:focus-within {
	outline: none !important;
	box-shadow: none !important;
	border-color: transparent !important;
}

/* Open-in-Google-Maps button overlaid on top-right of the address
   map. Inherits the .linkedinbutton chrome from ChapsV_AppSFA.css
   (rounded white circle); we just nail the glyph colour so it stays
   visible against the map tiles in both themes — without this the
   dark-theme catch-all turns the <i> the same colour as the disc
   underneath and the icon disappears. */
.addr-map-open,
.addr-map-open i {
	color: #555 !important;
}
.addr-map-open:hover {
	background-color: #ffffff !important;
}
.addr-map-open:hover i {
	color: #222 !important;
}
body.appbuilder-dark .addr-map-open {
	background-color: rgba(255, 255, 255, 0.92) !important;
	border-color: rgba(0, 0, 0, 0.12) !important;
}
body.appbuilder-dark .addr-map-open,
body.appbuilder-dark .addr-map-open i {
	color: #333 !important;
}
body.appbuilder-dark .addr-map-open:hover {
	background-color: #ffffff !important;
}
body.appbuilder-dark .addr-map-open:hover i {
	color: #000 !important;
}

/* Address group view toggle — a single button on the right side of
   the "Address: <group>" title bar, painted with the project's
   standard primary-action blue (#269DF0). Its label is the OTHER
   view's name (Map when Details is visible, Details when Map is
   visible) so the user always sees what they're switching TO. */
.w2ui-group-title { display: flex; align-items: center; }
.w2ui-group-title > .addr-view-toggle {
	margin-left: auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 3px 12px;
	border: 0;
	background: #269DF0;
	color: #ffffff;
	font-size: 12px;
	font-weight: 500;
	line-height: 1;
	border-radius: 14px;
	cursor: pointer;
	user-select: none;
	transition: background-color 0.12s ease-out;
}
.w2ui-group-title > .addr-view-toggle:hover { background: #1a8ad8; }
.w2ui-group-title > .addr-view-toggle > .fa { font-size: 11px; }
body.appbuilder-dark .w2ui-group-title > .addr-view-toggle {
	background: #269DF0;
	color: #ffffff;
}
body.appbuilder-dark .w2ui-group-title > .addr-view-toggle:hover {
	background: #1a8ad8;
}

/* The Address group itself — breathing room above so it doesn't sit
   flush against the preceding field. We tighten the bottom margin of
   the fields container because w2ui's default 14px stacks on top of
   any spacing from the next section. */
.w2ui-group.addr-group-wrap {
	margin-top: 14px;
}
.w2ui-group.addr-group-wrap > .w2ui-group-fields {
	margin-bottom: 0;
}

/* Sentinel "group" appended right after the address section to force
   w2form to close the run of fields (without one, every subsequent
   field would stay nested inside the Address group). We hide the
   title outright and strip every bit of layout the .w2ui-group
   wrapper, the fields container and the title might still contribute,
   so the section is dimensionally invisible. */
.w2ui-group.addr-close-sentinel-wrap {
	margin: 0 !important;
	padding: 0 !important;
}
.w2ui-group.addr-close-sentinel-wrap > .w2ui-group-title {
	display: none !important;
	height: 0 !important;
	padding: 0 !important;
	margin: 0 !important;
}
.w2ui-group.addr-close-sentinel-wrap > .w2ui-group-fields {
	margin: 0 !important;
	padding: 0 !important;
	border: 0 !important;
	background: transparent !important;
}

/* Refto inputs — AutocompleteFieldBuilder wraps the <input> in
   `.refto-input-wrap` (a tight block container so the icon's
   absolute positioning has the input's own bounds as reference, not
   the larger w2ui-field area that also holds the label) and prepends
   a `<i class="fa fa-..."> .refto-input-icon` whose class comes from
   the referenced table's `icon` (default: arrow-in-circle used for
   unspecified join tables). Icon stays neutral grey in both edit and
   read-only modes — blue is reserved for the value text. */
.refto-input-wrap {
	position: relative;
	display: block;
	width: 100%;
	margin: 0;
	padding: 0;
}
.refto-input-icon {
	/* Centered vertically by `top: 50%` + a negative margin equal to
	   half the rendered glyph height — works regardless of the input's
	   actual height (varies between themes / w2ui versions). Explicit
	   width/height + text-align so FontAwesome's ::before glyph has a
	   sized box to paint into when the <i> is otherwise empty. */
	position: absolute;
	left: 9px;
	top: 50%;
	/* -7px would centre a 14px glyph; we nudge it +10px down because
	   the wrap also covers the label area above the input, so the
	   geometric centre of the wrap sits roughly 10px above the input's
	   own centre. Adjust this single value if w2ui changes its field
	   layout / label spacing. */
	margin-top: 3px;
	width: 14px;
	height: 14px;
	line-height: 14px;
	text-align: center;
	color: #606060;
	pointer-events: none;
	font-size: 14px;
	z-index: 1;
}
body.appbuilder-dark .refto-input-icon { color: #b8b8b8; }

/* Format-bound inputs (email / url / phone). The icon background and
   left-padding are pinned via attribute selectors so they survive
   w2ui's runtime class shuffling — using a class via attr is
   unreliable because w2ui rewrites the input's className.
   Blue link colour + pointer cursor + hover-underline ONLY apply in
   read-only mode (input[readonly]) — in edit mode the field looks and
   behaves like a normal text input, just with the small icon. */
input.w2ui-input[data-fmt] {
	background-repeat: no-repeat;
	background-position: 7px center;
	background-size: 14px 14px;
	padding-left: 28px !important;
}
input.w2ui-input[data-fmt="email"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23606060' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='5' width='18' height='14' rx='2'/><path d='M3 7l9 7 9-7'/></svg>");
}
input.w2ui-input[data-fmt="url"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23606060' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M3 12h18'/><path d='M12 3a14 14 0 0 1 0 18'/><path d='M12 3a14 14 0 0 0 0 18'/></svg>");
}
input.w2ui-input[data-fmt="phone"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23606060' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 16.92v3a2 2 0 0 1-2.18 2 19.86 19.86 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.86 19.86 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.69 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.33 1.85.56 2.81.69A2 2 0 0 1 22 16.92z'/></svg>");
}
/* Link-style affordance — read-only mode only.
   !important here because w2ui's own .w2ui-input rule paints a darker
   text colour with comparable or higher specificity, swallowing ours
   otherwise. For refto we drop the [readonly] guard: the .inputurl
   class is itself only added by AutocompleteFieldBuilder when the
   field is non-editable, so the class presence is enough. */
input.w2ui-input[data-fmt="email"][readonly],
input.w2ui-input[data-fmt="url"][readonly],
input.w2ui-input.inputurl {
	color: #0a66c2 !important;
	cursor: pointer;
}

/* ONE link treatment everywhere a reference is clickable: refto cells in entry
   search grids, the Screener's Name column, email / url format columns, task
   cards. #0a66c2 is the colour the read-only autocomplete refto field paints
   itself directly above — this makes the grids agree with the forms instead of
   each screen picking its own.

   Previously: base .gridurl was `color: black` (ChapsV_AppSFA.css:3514) and lost
   in dark mode to w2ui's grid-cell colour rules, so links rendered white; task
   cards overrode to a different blue (#1F84C6) with a permanent underline; and
   the Screener had a third variant. Three looks for one concept.

   !important because the dark-mode grid rules it must beat are themselves
   !important and far more specific — the same reason the .inputurl rule above
   needs it. Underline on HOVER only, matching the form field. */
.gridurl,
a.gridurl,
.w2ui-grid .gridurl {
	color: #0a66c2 !important;
	text-decoration: none;
	cursor: pointer;
}
.gridurl:hover,
a.gridurl:hover,
.w2ui-grid .gridurl:hover {
	text-decoration: underline;
}
/* Dark mode uses the LIGHTER blue, exactly as the refto input does at
   line ~11946. #0a66c2 is a light-mode colour: against the dark grid it sits
   near 3:1 contrast and reads muddy. The two are a pair — setting only the
   light half is what made the grids disagree with the form field they were
   supposed to match. */
body.appbuilder-dark .gridurl,
body.appbuilder-dark a.gridurl,
body.appbuilder-dark .w2ui-grid .gridurl {
	color: #7ab1f0 !important;
}
input.w2ui-input[data-fmt="email"][readonly]:hover,
input.w2ui-input[data-fmt="url"][readonly]:hover,
input.w2ui-input.inputurl:hover {
	text-decoration: underline;
}
/* Dark-mode icon recolour — switch the stroke to a lighter grey so the
   glyph stays legible against var(--bg-input). The inline style sets
   the light-mode icon; these rules win via specificity in dark mode. */
body.appbuilder-dark input.w2ui-input[data-fmt="email"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b8b8b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='5' width='18' height='14' rx='2'/><path d='M3 7l9 7 9-7'/></svg>") !important;
}
body.appbuilder-dark input.w2ui-input[data-fmt="url"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b8b8b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M3 12h18'/><path d='M12 3a14 14 0 0 1 0 18'/><path d='M12 3a14 14 0 0 0 0 18'/></svg>") !important;
}
body.appbuilder-dark input.w2ui-input[data-fmt="phone"] {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b8b8b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 16.92v3a2 2 0 0 1-2.18 2 19.86 19.86 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.86 19.86 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.69 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.33 1.85.56 2.81.69A2 2 0 0 1 22 16.92z'/></svg>") !important;
}
/* Dark-mode blue — read-only only, to match light-mode behaviour.
   The dark catch-all at line 8840 paints `color: var(--fg) !important`
   onto every <input> via a `:not()` chain that bumps its specificity
   above any plain selector. We have to replicate that same chain to
   win the cascade for our format / refto inputs. */
html body.appbuilder-dark input.w2ui-input[data-fmt="email"][readonly]:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]),
html body.appbuilder-dark input.w2ui-input[data-fmt="url"][readonly]:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]),
html body.appbuilder-dark input.w2ui-input.inputurl:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]) {
	color: #7ab1f0 !important;
	-webkit-text-fill-color: #7ab1f0 !important;
}

/* Dark-mode w2ui toggle — track uses the input-field palette so it
   doesn't pop too hard on dark backgrounds; the knob stays white so
   it's still clearly visible in both on and off states. */
body.appbuilder-dark input[type="checkbox"].w2ui-toggle + div {
	background-color: var(--bg-input);
	border-color: var(--border-strong);
}
body.appbuilder-dark input[type="checkbox"].w2ui-toggle + div > div,
body.appbuilder-dark input[type="checkbox"].w2ui-toggle:checked + div > div {
	background-color: #ffffff;
	box-shadow: 0 0 1px #000, 0 0 0 1px var(--border);
}

/* Inline edit / delete icons on columns & relationships — revealed on row hover */
.builder-edit-icon-inline,
.builder-del-icon-inline {
	color: #C8C4BE;
	cursor: pointer;
	font-size: 11px;
	margin-left: 6px;
	opacity: 0;
	transition: opacity 0.12s ease-out;
}
[data-colname]:hover .builder-edit-icon-inline,
[data-colname]:hover .builder-del-icon-inline,
[data-relname]:hover .builder-edit-icon-inline,
[data-relname]:hover .builder-del-icon-inline {
	opacity: 1;
}
.builder-edit-icon-inline:hover {
	color: #0078D4;
}
.builder-del-icon-inline:hover {
	color: #D13438;
}

/* Data model check / migration dialog list */
.dm-check-list {
	max-height: 320px;
	overflow: auto;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	padding: 4px 8px;
}
.dm-check-row {
	padding: 6px 4px;
	border-bottom: 1px solid #efefef;
}
.dm-check-row:last-child {
	border-bottom: 0;
}
.dm-check-finding {
	color: #808080;
	margin-left: 24px;
}
body.appbuilder-dark .dm-check-list {
	border-color: transparent;
	background-color: var(--bg-elev);
}
body.appbuilder-dark .dm-check-row {
	border-bottom-color: var(--bg-hover);
}
body.appbuilder-dark .dm-check-finding {
	color: var(--fg-muted);
}

/* Schema-drift dialog — flex column so buttons stick to the bottom and
   the expanded details section fills the remaining height. */
.dm-drift-box {
	display: flex;
	flex-direction: column;
	height: 100%;
	box-sizing: border-box;
	padding: 18px;
	font-size: 13px;
	line-height: 1.5;
}
.dm-drift-box > .dm-drift-intro { flex: 0 0 auto; }
.dm-drift-details-toggle {
	flex: 0 0 auto;
	margin-top: 8px;
	color: #666;
	cursor: pointer;
	user-select: none;
}
body.appbuilder-dark .dm-drift-details-toggle {
	color: var(--fg-muted);
}
.dm-drift-details-body {
	display: none;
	margin-top: 8px;
	flex: 0 0 auto;
}
.dm-drift-box.dm-expanded .dm-drift-details-body {
	display: block;
	flex: 1 1 auto;
	min-height: 0;
	max-height: none;
	overflow: auto;
}
.dm-drift-buttons {
	flex: 0 0 auto;
	margin-top: 14px;
	display: flex;
	justify-content: flex-end;
	gap: 6px;
	flex-wrap: nowrap;
}

/* ==============================================================
 * UI Design toggle — small ON/OFF switch sitting just to the LEFT
 * of .buildapp during a TEST session. Lets the user flip between
 * UI test and UI design (rearrange / edit components). Claude-logo
 * orange (--ui-design-color) when ON, neutral gray when OFF. This
 * same orange is the canonical color for ALL visual-edit clues —
 * reuse var(--ui-design-color) wherever a design-mode affordance
 * needs to be surfaced.
 * ============================================================== */
:root {
	--ui-design-color:        #D97757;   /* Claude logo orange */
	--ui-design-color-hover:  #C66544;
	--ui-design-color-active: #A85436;
}
.uidesign {
	position: absolute;
	right: 248px;   /* 8px gap left of .buildapp (right:120px + width:120px = 240px) */
	top: 16px;
	height: 32px;
	padding-left: 12px;              /* match .buildapp horizontal padding */
	padding-right: 12px;
	border-radius: 6px;              /* squared, matches .buildapp / .testapp */
	box-sizing: border-box;
	background-color: #5a6268;       /* OFF — neutral gray */
	color: white;
	cursor: pointer;
	user-select: none;
	display: flex;                   /* set by JS when shown */
	align-items: center;
	gap: 6px;
}
.uidesign[data-state='on'] {
	background-color: var(--ui-design-color);
}
.uidesign:hover                   { filter: brightness(1.08); }
.uidesign:active                  { transform: scale(0.96); }

.uidesign_track {
	position: relative;
	display: inline-block;
	width: 26px;
	height: 14px;
	border-radius: 7px;
	background-color: rgba(0,0,0,0.25);
	transition: background-color 0.15s ease;
}
.uidesign[data-state='on'] .uidesign_track { background-color: rgba(255,255,255,0.35); }
.uidesign_knob {
	position: absolute;
	top: 1px;
	left: 1px;
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background-color: white;
	transition: left 0.15s ease;
	box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.uidesign[data-state='on'] .uidesign_knob { left: 13px; }

.uidesign_text {
	font-family: OpenSans;
	font-size: 14px;                 /* match .buildapp > span */
	line-height: 32px;
}

body.appbuilder-dark .uidesign                       { background-color: #5a6268 !important; color: white !important; }
body.appbuilder-dark .uidesign[data-state='on']      { background-color: var(--ui-design-color) !important; }
body.appbuilder-dark .uidesign:hover                 { filter: brightness(1.1); }

.buildapp {
	position: absolute;
	right: 120px;
	top: 16px;
	width: 120px;
	height: 32px;
	border-radius: 6px;
	box-sizing:border-box;
	padding-left:12px;
	padding-right:12px;
	background-color: #269DF0;
	color: white;
	text-align: center;
	cursor: pointer;
}

.buildapp:hover {
	background-color: #1F84C6;
}

.buildapp > span
{
	line-height: 32px;
	font-family: OpenSans;
	font-size: 14px;
	user-select: none; /* Standard */
}


.testapp {
	position: absolute;
	right: 120px;
	top: 16px;
	width: 120px;
	height: 32px;
	border-radius: 6px;
	box-sizing:border-box;
	padding-left:12px;
	padding-right:12px;
	background-color: #2CA85E;
	color: white;
	text-align: center;
	cursor: pointer;
}

.testapp:hover {
	background-color: #238B4D;
}

/* Mode badge — colored tag shown next to the application title
   indicating whether we're in Build or Test mode. Colors match
   the .buildapp / .testapp top-bar buttons for consistency. */
.builder_mode_badge {
	display: inline-block;
	margin-left: 10px;
	padding: 2px 10px;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: white;
	border-radius: 10px;
	vertical-align: middle;
	line-height: 18px;
	/* Nudge up 1px so the cap-height visually aligns with the app
	   title text (text baselines don't match because the badge
	   font is smaller). */
	position: relative;
	top: -1px;
	user-select: none;
}
.builder_mode_badge.builder_mode_build { background-color: #269DF0; }
.builder_mode_badge.builder_mode_test  { background-color: #2CA85E; }
.builder_mode_badge.builder_mode_run   {
	background-color: #C25700;            /* warm orange — visible call-out that we're on a real DB */
	padding: 2px 6px 2px 10px;            /* tight against the inline Stop link */
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.builder_mode_badge.builder_mode_run .fa-bolt { font-size: 10px; }
.builder_mode_run_stop {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	padding: 1px 8px;
	border-radius: 8px;
	background: rgba(255,255,255,0.15);
	color: #fff;
	cursor: pointer;
	font-size: 10px;
	letter-spacing: 0.3px;
	text-transform: uppercase;
}
.builder_mode_run_stop:hover { background: rgba(255,255,255,0.30); }
.builder_mode_run_stop .fa { font-size: 11px; }

/* Run target on My Applications cards — the entire green "Published vN"
   chip is clickable, with an inner solid-green Run pill as the
   call-to-action. Click anywhere on the chip (chip text, padding,
   inner pill) starts the run; the runBtn intercept in the click handler
   reads the data-* attrs from the outermost matching element via
   .closest(".applications_element_run"). */
.applications_element_published {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 3px 4px 3px 10px !important;  /* tighter right side; inner pill has its own padding */
	cursor: pointer;
}
.applications_element_published:hover { filter: brightness(0.96); }

.applications_element_run_inner {
	background: #2e7d32;
	color: #fff !important;
	border-radius: 10px;
	padding: 4px 12px;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	line-height: 1.3;
}
.applications_element_run_inner .fa { font-size: 11px; }
.applications_element_published:hover .applications_element_run_inner { background: #25652a; }

body.appbuilder-dark .applications_element_run_inner               { background: #3FA34A; color: #fff !important; }
body.appbuilder-dark .applications_element_published:hover .applications_element_run_inner { background: #4ABA56; }

/* Run button on Versions panel rows. Green to match the Published badge. */
.overview_version_run {
	padding: 4px 10px !important;
	font-size: 12px !important;
	margin-left: 4px;
	background: #2e7d32 !important;
	color: #fff !important;
	border-color: #25652a !important;
	font-weight: 700;
}
.overview_version_run:hover { background: #25652a !important; }
body.appbuilder-dark .overview_version_run        { background: #3FA34A !important; border-color: #2e7d32 !important; }
body.appbuilder-dark .overview_version_run:hover  { background: #4ABA56 !important; }

.testapp > span
{
	line-height: 32px;
	font-family: OpenSans;
	font-size: 14px;
	user-select: none; /* Standard */
}




.builder_recentobjects_container
{
	width:100%;
	height:100%;
	overflow:hidden;
	padding:12px;
	box-sizing: border-box;
	background-color:#F2F0EC;
	border-radius:12px;
}

.builder_recentobjects_element
{
	width:200px;
	height: 100%;
	border:1px solid #EEECEA;
	background-color: white;
	display:inline-block;
	margin-right:8px;
	margin-bottom:8px;
	border-radius:12px;
	padding:6px;
	cursor: pointer;
	position: relative;
	box-sizing: border-box;
}
	
.builder_recentobjects_tags
{
	position:absolute;
	top:6px;
	left:10px;
	width:180px;
	height:4px;
	overflow: hidden;
}

.builder_recentobjects_tags div {
	position:absolute;
	top:0px;
	width:32px;
	height:4px;
	border-radius:2px;
}

.builder_recentobjects_element_alert
{
	position:absolute;
	left:40px;
	top:16px;
	width:12px;
	height:12px;
	border-radius:16px;
	background-color: red;
	z-index:10000;
}

.builder_recentobjects_element_logo
{
	position:absolute;
	left:10px;
	top:16px;
	width:40px;
	height:40px;
	overflow:hidden;
	border-radius:20px;
}

.builder_recentobjects_element_logo > img
{
	position:absolute;
	top:0;
	left:50%;
	height:100%;
	transform: translate(-50%, 0%);
	object-fit: cover;
}

.builder_recentobjects_element_text
{
	position:absolute;
	left:56px;
	top:12px;
	width:148px;
	height:80px;
	overflow:hidden;
	text-overflow: ellipsis;
	overflow : hidden;
	color: #808080;
	user-select: none;
	font-family: OpenSans;
	font-size: 11px;
	line-height:16px;
	white-space: nowrap;
}


.builder_recentobjects_element_text > span
{
	font-weight: bold;
	user-select: none;
	font-size: 12px;
	line-height:20px;
	white-space: nowrap;
}

/* Instrument favorite card, stacked: name · symbol · last · (chg  chg%). The
   symbol/quote spans are NOT bold (the `> span` rule above is scoped to direct
   children of the text block; these live inside it too, so re-declare), and use
   a tighter line-height so all four lines fit the card's text block. */
.favorites_container .fav-sym {
	font-weight: normal; font-size: 10.5px; line-height: 15px; color: #9aa0ac;
}
.favorites_container .fav-quote { font-weight: normal; font-size: 11.5px; line-height: 15px; }
.favorites_container .fav-quote .fav-last { font-weight: 600; color: #27251E; }
.favorites_container .fav-quote.is-up   .fav-chg { color: #1a7f37; }
.favorites_container .fav-quote.is-down .fav-chg { color: #b3261e; }
body.appbuilder-dark .favorites_container .fav-quote .fav-last { color: var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .favorites_container .fav-quote.is-up   .fav-chg { color: #7ddb9a; }
body.appbuilder-dark .favorites_container .fav-quote.is-down .fav-chg { color: #ef9a9a; }



.builder_recentobjects_element:hover
{
	background-color: #f8f8f8;
}


.builder_secondarypanel_cards_container
{
	width:100%;
	height:100%;
	padding:12px;
	overflow:hidden;
	overflow-y: auto;
	box-sizing: border-box;
	background-color:#FAF8F5;
}

.builder_secondarypanel_card
{
	height:80px;
	vertical-align: top;
}

/* ===================================================================
   Tasks panel — Cards view
   Mirrors the BuilderSecondaryPanel pattern (flex-wrap container +
   individual card) scaled up to accommodate the richer task content
   (status, schedule, owner, entry). Two-file scope: class names here
   are referenced only from BaseTasksClass._BuildTaskCardHtml and
   _SetTaskView in ChapsV_AppSFA.js.
   =================================================================== */

/* Container — fills the panel box (absolute inset:0 in JS). Uses flex
   so cards wrap naturally at the container edge. Scrollable vertically
   when there are more cards than the panel height can show. */
.tasks-cards-host {
	display: flex;
	flex-wrap: wrap;
	align-content: flex-start;
	gap: 12px;
	padding: 12px;
	box-sizing: border-box;
	background-color: #FAF8F5;
}

/* Individual card — fixed width, auto height (min ~140px in practice).
   Hover lifts shadow so it reads as clickable. Position:relative anchors
   the status pill in the top-right corner via flexbox inside the card. */
.tasks-card {
	width: 300px;
	min-height: 100px;
	border: 1px solid #E2E0DC;
	border-radius: 8px;
	padding: 10px 12px;
	background-color: #ffffff;
	box-sizing: border-box;
	cursor: pointer;
	position: relative;
	transition: box-shadow 0.12s ease;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	color: #555;
}
.tasks-card {
	/* Background tween so the hover swap below feels smooth instead
	   of snapping. Matches the secondary-panel cards (no shadow tween
	   there either — bg only). */
	transition: background-color 0.12s ease;
}
.tasks-card:hover {
	/* IDENTICAL to the secondary-panel hover (line 10182:
	   `.builder_recentobjects_element:hover { background-color:#f8f8f8 }`).
	   No shadow, no border-color change — bg-only keeps the two
	   surfaces visually consistent. */
	background-color: #f8f8f8;
}

/* Title — bold, truncate with ellipsis if the name is very long. */
.tasks-card-title {
	font-size: 14px;
	font-weight: 700;
	color: #222;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	line-height: 20px;
}

/* Status pill area — aligned to the right in the flex header row.
   The __Builder_RenderTaskStatusCell output is an inline-flex span
   so no extra wrapper sizing is needed. */
.tasks-card-status {
	flex-shrink: 0;
}

/* Meta rows — owner, schedule, next firing, entry.
   Small text, consistent icon + text pattern. */
.tasks-card-row {
	display: flex;
	align-items: center;
	font-size: 12px;
	color: #777;
	margin-top: 5px;
	line-height: 16px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
/* Task-card links deliberately carry NO override any more — they used
   #1F84C6 with a permanent underline, a third look for the same concept.
   They now inherit the shared .gridurl treatment (#0a66c2, underline on
   hover) so a reference reads identically on a card, in a grid and in a
   form. Re-adding a colour here reintroduces the inconsistency. */

/* Overdue card — dusty-rose tint matching the grid's late-row treatment.
   Light mode: red border + pale-red bg. Dark mode overrides further down. */
.tasks-card.task-overdue-card {
	border-color: #c82627;
	background-color: #fff5f5;
}
.tasks-card.task-overdue-card .tasks-card-title {
	color: #c82627;
}

/* Completed card — same visual treatment as the grid's completed
   row (PlanClass.GetRecordStyle stamps 60% opacity + line-through
   on the row's style). Keeps the chip pill brightness consistent
   between list and cards views — without this, the same green
   #2e7d32 looks markedly more saturated on a full-opacity card
   than on a 60%-opacity row. */
.tasks-card.tasks-card-completed {
	opacity: 0.6;
}
.tasks-card.tasks-card-completed .tasks-card-title {
	text-decoration: line-through;
}

/* Dark mode ------------------------------------------------------------- */
body.appbuilder-dark .tasks-cards-host {
	/* !important to override the inline `background:#fff` set on the
	   host at mount time (needed in light mode so the host opaquely
	   covers the grid behind it — the same inline would blast white
	   in dark mode without this override). */
	background-color: #1a1a1a !important;
}
body.appbuilder-dark .tasks-card {
	background-color: #232323;
	border-color: #3a3a3a;
	color: #ccc;
}
body.appbuilder-dark .tasks-card:hover {
	/* IDENTICAL to body.appbuilder-dark .builder_recentobjects_element:hover
	   (line 11428: `background-color: #3d3d3d !important`). bg-only,
	   no shadow / border change, so the two card surfaces feel the
	   same in dark mode too. */
	background-color: #3d3d3d;
}
body.appbuilder-dark .tasks-card-title {
	color: #e6e6e6;
}
body.appbuilder-dark .tasks-card-row {
	color: #aaa;
}
body.appbuilder-dark .tasks-card.task-overdue-card {
	border-color: #d98a8a;
	background-color: #2d1e1e;
}
body.appbuilder-dark .tasks-card.task-overdue-card .tasks-card-title {
	color: #d98a8a;
}

/* Overdue card hover — same bg-only swap as the generic case,
   just with a rose-tinted lighter / darker shade so the overdue
   theme is preserved on hover. The specificity bump (.tasks-card
   plus .task-overdue-card plus :hover = 0,3,1) is what makes
   this win over the resting overdue rule (0,3,0). */
.tasks-card.task-overdue-card:hover {
	background-color: #ffe9e9;
}
body.appbuilder-dark .tasks-card.task-overdue-card:hover {
	background-color: #3a2424;
}


/* Overview Identity Card field label */
.overview_field_label {
	font-size: 14px;
	padding: 4px;
	color: #656164cc;
	font-weight: 700;
}

/* Let the Overview form flow naturally inside #id_overviewformcontainer so the
   scroll happens on the outer container (scrollbar at the right edge of the
   panel) instead of on w2ui's .w2ui-page (scrollbar next to the form). */
#id_overviewformcontainer .w2ui-form,
#id_overviewformcontainer .w2ui-form > .w2ui-form-box {
	position: static;
	height: auto;
	overflow: visible;
}
#id_overviewformcontainer .w2ui-form .w2ui-page {
	position: static;
	overflow: visible;
	height: auto;
}

/* Dark mode — paint the form with the panel's default background
   (--bg, #1A1A1A) so the form blends into the container and there's no
   two-tone split. */
body.appbuilder-dark #id_overviewformcontainer,
body.appbuilder-dark #id_overviewformcontainer_shift,
body.appbuilder-dark #id_overviewformcontainer_inner,
body.appbuilder-dark #id_overviewformcontainer .w2ui-form,
body.appbuilder-dark #id_overviewformcontainer .w2ui-form .w2ui-page {
	background-color: var(--bg) !important;
}

/* GoJS diagram overview (minimap) box */
.diagram_overview_box {
	position: absolute;
	top: 10px;
	left: 10px;
	width: 200px;
	height: 150px;
	background-color: white;
	border: 1px solid #B4D0DE;
	border-radius: 8px;
	z-index: 1000000;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
	overflow: hidden;
}
body.appbuilder-dark .diagram_overview_box {
	background-color: #242424 !important;
	border: 1px solid #3a3a3a !important;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6) !important;
}


/* ================================================================
 * Theme mode toggle (light/dark switch next to the user icon)
 * ================================================================ */

.thememode {
	position: absolute;
	top: 12px;
	right: 72px;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background-color: #F0F0F0;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.15s ease, transform 0.1s ease;
}

.thememode il {
	font-size: 18px;
	color: #404040;
	transition: transform 0.1s ease;
}

.thememode:hover {
	background-color: #E4E4E4;
}
.thememode:hover il {
	transform: scale(1.08);
}
.thememode:active {
	transform: scale(0.92);
}
.thememode:active il {
	transform: scale(0.9);
}


/* ================================================================
 * Press / compression feedback for topbar action buttons
 * (no glowing box-shadow ring, no browser focus outline)
 * ================================================================ */

.createany,
.buildapp,
.testapp,
.userid {
	transition: background-color 0.15s ease, transform 0.1s ease, box-shadow 0.1s ease;
	outline: none !important;
}

/* Nudge topbar avatar + theme toggle down so they center vertically */
.topmainform .userid {
	top: 12px;
}

/* ================================================================
 * Input focus — replace the layered blue+white browser ring with
 * a single clean blue border
 * ================================================================ */

.w2ui-reset input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):focus,
.w2ui-reset select:focus,
.w2ui-reset textarea:focus,
.w2ui-input:focus,
input.w2ui-input:focus,
textarea.w2ui-input:focus,
select.w2ui-input:focus,
div.w2ui-input:focus {
	outline: none !important;
	outline-offset: 0 !important;
	border: 1px solid #269DF0 !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
	-webkit-appearance: none !important;
}

body.appbuilder-dark .w2ui-reset input:focus,
body.appbuilder-dark .w2ui-reset textarea:focus,
body.appbuilder-dark .w2ui-reset select:focus,
body.appbuilder-dark .w2ui-input:focus,
body.appbuilder-dark input.w2ui-input:focus,
body.appbuilder-dark textarea.w2ui-input:focus {
	outline: none !important;
	outline-offset: 0 !important;
	border: 1px solid #269DF0 !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
	background-color: var(--bg-input) !important;
	color: var(--fg) !important;
}

/* Catch-all (high-specificity) dark styling for form inputs.
   The w2ui base rule input:not([type=button]):not([type=submit]).w2ui-input:focus
   has specificity (0,4,1). We include the same :not() chain so our rules
   win the cascade. */
html body.appbuilder-dark input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):not(.color),
html body.appbuilder-dark textarea,
html body.appbuilder-dark select {
	background-color: var(--bg-input) !important;
	color: var(--fg) !important;
	-webkit-text-fill-color: var(--fg) !important;
	caret-color: var(--fg) !important;
	border: 1px solid var(--border-strong) !important;
	border-radius: 3px !important;
}

/* Chrome autofill (:-webkit-autofill) — the browser forces a white
   background and black text on autofilled inputs, which is awful in
   dark mode. The standard workaround is an inset box-shadow of the
   desired colour (which fills the padding box) and a long transition
   to prevent a flash. */
html body.appbuilder-dark input:-webkit-autofill,
html body.appbuilder-dark input:-webkit-autofill:hover,
html body.appbuilder-dark input:-webkit-autofill:focus,
html body.appbuilder-dark input:-webkit-autofill:active,
html body.appbuilder-dark textarea:-webkit-autofill,
html body.appbuilder-dark textarea:-webkit-autofill:hover,
html body.appbuilder-dark textarea:-webkit-autofill:focus,
html body.appbuilder-dark select:-webkit-autofill {
	-webkit-box-shadow: 0 0 0 1000px #2b2b2b inset !important;
	box-shadow: 0 0 0 1000px #2b2b2b inset !important;
	-webkit-text-fill-color: #e6e6e6 !important;
	caret-color: #e6e6e6 !important;
	transition: background-color 5000s ease-in-out 0s !important;
}

/* Exception: inputs inside a w2field helper (search box overlaid on
   type='list' fields) must stay transparent so the main input's text
   shows through. */
html body.appbuilder-dark .w2ui-field-helper input {
	background: transparent !important;
	background-color: transparent !important;
	border: 1px solid transparent !important;
	color: var(--fg) !important;
	-webkit-text-fill-color: var(--fg) !important;
}

html body.appbuilder-dark input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):focus,
html body.appbuilder-dark textarea:focus,
html body.appbuilder-dark select:focus {
	outline: none !important;
	outline-offset: 0 !important;
	border: 1px solid #269DF0 !important;
	border-radius: 3px !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
	background-color: var(--bg-input) !important;
	color: var(--fg) !important;
	-webkit-text-fill-color: var(--fg) !important;
}

/* Exception: the charts typeahead inputs live INSIDE a bordered field
   (chips + input + button as one control) whose :focus-within draws the
   ring for all of them. The catch-all above was painting its own border
   and blue focus box on the bare input — the gray/blue vertical bars
   inside the instrument box — and !important meant even inline styles
   lost. The selector REPEATS the catch-all's :not() chain on purpose:
   each :not([type=…]) scores at class level, so the catch-all sits at
   ~6 classes and a plain two-class exception LOSES to it regardless of
   source order. Same chain + one more class = this wins. */
html body.appbuilder-dark input.charts_symbol_input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):not(.color),
html body.appbuilder-dark input.charts_symbol_input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):focus,
html body.appbuilder-dark input.screener_nl_input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):not(.color),
html body.appbuilder-dark input.screener_nl_input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):focus {
	background: transparent !important;
	background-color: transparent !important;
	border: none !important;
	border-radius: 0 !important;
	outline: none !important;
	box-shadow: none !important;
}

/* The helper's search input should never get the blue focus border —
   the main input owns that visual. Keep the helper transparent on focus. */
html body.appbuilder-dark .w2ui-field-helper input:focus {
	outline: none !important;
	border: 1px solid transparent !important;
	background: transparent !important;
	background-color: transparent !important;
	box-shadow: none !important;
}

/* Light mode: same specificity bump for the focus border so text inputs
   get the 2px blue border like textareas do. Base rules for light mode
   stay as-is (1px grey border at rest). */
html .w2ui-popup input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):focus,
html .w2ui-popup textarea:focus,
html .w2ui-popup select:focus,
html .w2ui-form input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):focus,
html .w2ui-form textarea:focus,
html .w2ui-form select:focus {
	outline: none !important;
	outline-offset: 0 !important;
	border: 1px solid #269DF0 !important;
	border-radius: 3px !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
}

/* Placeholder text */
body.appbuilder-dark .w2ui-popup input::placeholder,
body.appbuilder-dark .w2ui-form input::placeholder,
body.appbuilder-dark .w2ui-popup textarea::placeholder,
body.appbuilder-dark .w2ui-form textarea::placeholder {
	color: var(--fg-muted) !important;
	-webkit-text-fill-color: var(--fg-muted) !important;
}
/* Global dark-mode placeholder — applies everywhere an input
   or textarea is rendered in dark mode (workflow properties
   panel, screen forms, dialogs, chat composer, …). The actual
   text color is `--fg` (#e6e6e6 — bright white-gray) and the
   default placeholder pseudo-element inherits that color,
   making it indistinguishable from real input. Forcing a much
   darker tone (#666) gives the placeholder an obvious "this
   is a hint, not real content" cue.
   Using a single `html body.appbuilder-dark` selector +
   !important so this beats the per-control overrides above
   that resolve to the lighter --fg-muted (#a0a0a0). */
html body.appbuilder-dark input::placeholder,
html body.appbuilder-dark textarea::placeholder {
	color: #666 !important;
	-webkit-text-fill-color: #666 !important;
	opacity: 1 !important;
}

/* ================================================================
 * .w2ui-select special cases
 * This class is applied to single-select picklist inputs (type:
 * 'list') and w2ui forces color: black !important with a PNG down
 * arrow as background-image. The focus state is a .has-focus class
 * (not :focus), so :focus rules never hit it.
 * ================================================================ */

/* Light mode: replace the ugly auto outline with a clean blue border */
.w2ui-select.has-focus {
	outline: none !important;
	border: 2px solid #269DF0 !important;
}

/* Dark mode: force text color and dark background on the main input.
   Keep the SVG chevron separate so a potential data-URL parse error
   on the background-image won't invalidate the entire rule. */
html body.appbuilder-dark input[class*="w2ui-select"],
html body.appbuilder-dark input.w2ui-input.w2ui-select {
	color: #e6e6e6 !important;
	-webkit-text-fill-color: #e6e6e6 !important;
	caret-color: #e6e6e6 !important;
	background-color: #2b2b2b !important;
	background-repeat: no-repeat !important;
	background-position: right 8px center !important;
	background-size: 10px 6px !important;
	border: 1px solid #505050 !important;
	border-radius: 3px !important;
	padding-right: 22px !important;
}
/* Background-image chevron in its own rule so a parse failure here
   doesn't take the color/bg properties with it. Hide on readonly. */
html body.appbuilder-dark input[class*="w2ui-select"]:not([readonly]):not([disabled]),
html body.appbuilder-dark input.w2ui-input.w2ui-select:not([readonly]):not([disabled]) {
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2017%206'%3E%3Cpath%20fill='%23e6e6e6'%20d='M0,0%20L17,0%20L8.5,6%20Z'/%3E%3C/svg%3E") !important;
}
html body.appbuilder-dark input[class*="w2ui-select"][readonly],
html body.appbuilder-dark input[class*="w2ui-select"][disabled] {
	background-image: none !important;
}
html body.appbuilder-dark input[class*="w2ui-select"].has-focus,
html body.appbuilder-dark input.w2ui-input.w2ui-select.has-focus {
	outline: none !important;
	outline-offset: 0 !important;
	border: 1px solid #269DF0 !important;
	border-radius: 3px !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
	background-color: #2b2b2b !important;
	color: #e6e6e6 !important;
	-webkit-text-fill-color: #e6e6e6 !important;
}

/* Fallback focus highlight — three mechanisms stacked:
   1. :focus-within on the parent .w2ui-field (covers any descendant
      focus including the search helper input)
   2. Adjacent sibling via :has() — when the preceding
      .w2ui-field-helper contains a focused input, light up the
      neighbouring .w2ui-select
   3. The native has-focus class already handled above */
.w2ui-field:focus-within input.w2ui-select,
.w2ui-field-helper:has(input:focus) + input.w2ui-select,
.w2ui-field.w2ui-field-focused input.w2ui-select {
	outline: none !important;
	border: 1px solid #269DF0 !important;
	border-radius: 3px !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
}
html body.appbuilder-dark .w2ui-field:focus-within input.w2ui-select,
html body.appbuilder-dark .w2ui-field-helper:has(input:focus) + input.w2ui-select,
html body.appbuilder-dark .w2ui-field.w2ui-field-focused input.w2ui-select {
	outline: none !important;
	border: 1px solid #269DF0 !important;
	border-radius: 3px !important;
	box-shadow: inset 0 0 0 1px #269DF0 !important;
	background-color: #2b2b2b !important;
	color: #e6e6e6 !important;
	-webkit-text-fill-color: #e6e6e6 !important;
}

/* The .w2ui-select in light mode also has a dark PNG arrow — make it
   slightly brighter / relocated so it's consistent with the dark SVG */
.w2ui-select {
	background-position: right 8px center !important;
}

/* Picklist / list field wrapper focus — replace browser outline with clean blue ring */
.w2ui-field-helper.w2ui-list.has-focus,
.w2ui-field-helper.w2ui-list:focus-within {
	outline: none !important;
	border: 1px solid #269DF0 !important;
	box-shadow: 0 0 0 1px #269DF0 !important;
}
body.appbuilder-dark .w2ui-field-helper.w2ui-list.has-focus,
body.appbuilder-dark .w2ui-field-helper.w2ui-list:focus-within {
	outline: none !important;
	border: 1px solid #269DF0 !important;
	box-shadow: 0 0 0 1px #269DF0 !important;
	background-color: var(--bg-input) !important;
}

/* The w2ui-field-helper (WITHOUT .w2ui-list) is positioned absolutely
   over the input's right side for type='list' fields. Force it
   transparent so the main input's selected-label text shows through.
   Do NOT target .w2ui-field-helper.w2ui-list — that's the enum/tags
   container which needs its own visible bg and border. */
.w2ui-field-helper:not(.w2ui-list),
.w2ui-field-helper:not(.w2ui-list) input {
	background: transparent !important;
	background-color: transparent !important;
	border-color: transparent !important;
}

/* Tags / enum field inner input — must NOT get the focus border.
   The .w2ui-list container is the visual wrapper. High specificity
   to beat the catch-all input:focus rules. Extra :not()s keep us
   ahead of the dark-mode catch-all rule which has (0,7,3). */
html body .w2ui-field-helper.w2ui-list input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):not(.color),
html body .w2ui-field-helper.w2ui-list input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]):not(.color):focus {
	border: 0 !important;
	outline: none !important;
	box-shadow: none !important;
	background: transparent !important;
	background-color: transparent !important;
}

/* Dropdown arrows — the CSS triangle arrow-down / arrow-up inside a field
   helper is barely visible (grey on grey). Strengthen its color in both
   modes and make it bigger so the picklist has an obvious chevron. */
.w2ui-field-helper .arrow-down,
.w2ui-field-helper > .arrow-down {
	border-left: 5px solid transparent !important;
	border-right: 5px solid transparent !important;
	border-top: 6px solid #404040 !important;
}
.w2ui-field-helper .arrow-up,
.w2ui-field-helper > .arrow-up {
	border-left: 5px solid transparent !important;
	border-right: 5px solid transparent !important;
	border-bottom: 6px solid #404040 !important;
}

body.appbuilder-dark .w2ui-field-helper .arrow-down,
body.appbuilder-dark .w2ui-field-helper > .arrow-down {
	border-top-color: #e6e6e6 !important;
}
body.appbuilder-dark .w2ui-field-helper .arrow-up,
body.appbuilder-dark .w2ui-field-helper > .arrow-up {
	border-bottom-color: #e6e6e6 !important;
}

body.appbuilder-dark .w2ui-field-helper .arrow-down:hover {
	border-top-color: #ffffff !important;
}
body.appbuilder-dark .w2ui-field-helper .arrow-up:hover {
	border-bottom-color: #ffffff !important;
}

/* Version bump marker: picklist-fix-2 */


/* ================================================================
 * w2popup title buttons (close / maximize) — cleaner hover feel
 * ================================================================ */

.w2ui-popup .w2ui-popup-title-btns {
	margin: 7px 10px 0 0 !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button {
	width: 28px !important;
	height: 28px !important;
	margin: 0 0 0 4px !important;
	border-radius: 6px !important;
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	outline: none !important;
	border: 1px solid transparent !important;
	transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button span.w2ui-icon {
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	width: 24px !important;
	height: 24px !important;
	margin: 0 !important;
	line-height: 1 !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button:hover {
	background-color: #e8e8e8 !important;
	color: #222 !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button.w2ui-popup-close:hover {
	background-color: #ff5252 !important;
	color: #fff !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button:active {
	transform: scale(0.9) !important;
	background-color: #d0d0d0 !important;
}
.w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button.w2ui-popup-close:active {
	background-color: #c62828 !important;
}

/* Dark mode */
body.appbuilder-dark .w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .w2ui-popup .w2ui-popup-title-btns .w2ui-popup-button.w2ui-popup-close:hover {
	background-color: #d32f2f !important;
	color: #fff !important;
}


/* ================================================================
 * Tabs — drop the :active press-shrink. Tabs are sticky navigation
 * (clicked tab becomes active and stays selected), so the brief
 * scale-down looked like the panel was glitching on every tab change.
 * Other clickable surfaces (popup buttons, toolbar buttons, the
 * builder title pill) still keep the press feedback.
 * ================================================================ */

.w2ui-tabs .w2ui-scroll-wrapper .w2ui-tab {
	outline: none !important;
	transition: background-color 0.15s ease, color 0.15s ease !important;
}
.w2ui-tabs .w2ui-scroll-wrapper .w2ui-tab:focus {
	outline: none !important;
}

/* ================================================================
 * w2toolbar buttons ("New Application", "Refresh", view toggles...)
 * Remove the white+bordered click state; use the same flat bg shift
 * + scale(0.94) press as topbar / dialog buttons.
 * ================================================================ */

/* Vertically center flex children in the toolbar row.  Without this,
   the default `align-items: stretch` leaves explicit-height items
   pinned to the top of the row — and when a mixed-height item (like
   the `.toolbar-search` input) sits beside the 30 px buttons, the
   button's icon/text looks shifted because the buttons are flush
   with the top of a now-taller row instead of vertically centered. */
.w2ui-toolbar .w2ui-scroll-wrapper {
	align-items: center !important;
}

.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button {
	outline: none !important;
	transition: background-color 0.15s ease, transform 0.1s ease !important;
}

/* Icon + text inside a toolbar button use float + top-padding which
   doesn't guarantee vertical alignment when their intrinsic heights
   differ (w2ui-font glyph vs. OpenSans label).  Make the button a
   flex row so both children sit on a shared vertical center line.
   IMPORTANT: `display` is set WITHOUT !important on purpose — w2ui
   hides a toolbar item by setting an inline style="display: none"
   (see `hidden?"display: none":""` in w2ui.min.js), and an inline
   style has to be able to win so show/hide keeps working. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html) {
	display: flex;
	align-items: center !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html) .w2ui-tb-icon {
	float: none !important;
	/* Strip the implicit line-height the fontawesome glyph inherits
	   from the surrounding text. Without this, the icon span is
	   taller than the label and the flex `align-items: center` ends
	   up centering ON the bigger box — making the glyph itself sit
	   visually below the text baseline. Forcing line-height:1 here
	   matches what we already set on .w2ui-tb-text so the two boxes
	   have equal height and centre exactly on each other. */
	line-height: 1 !important;
	display: inline-flex !important;
	align-items: center !important;
	/* Inset 6px from the button's left edge. No right margin — the
	   icon-to-label gap is controlled entirely by the text's left
	   padding so the two sides don't compound. */
	margin: 0 0 0 6px !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html) .w2ui-tb-text {
	/* Default symmetric padding for icon-less buttons (e.g.
	   "Workflow Actions", "Apply Filters") — without this the text
	   would sit flush against both button edges. */
	margin: 0 !important;
	padding: 0 8px !important;
	line-height: 1 !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html) .w2ui-tb-icon + .w2ui-tb-text {
	/* When an icon precedes the text, override with the tight icon-
	   adjacent spacing: negative left margin pulls the label 2px
	   tighter to the icon than CSS padding alone allows (FA glyphs
	   carry intrinsic right-side bearing we can't reach via padding
	   on the icon span). 5px on the right keeps breathing room. */
	margin: 0 0 0 -2px !important;
	padding: 0 5px 0 0 !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:focus {
	outline: none !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.over {
	border-color: transparent !important;
	background-color: #eaeaed !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.checked,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.down {
	border-color: transparent !important;
	background-color: #dcdce2 !important;
}
/* Scale press only for real button items — skip html items that
   wrap an input (e.g. the toolbar search field) so typing doesn't
   compress the container. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html):active {
	transform: scale(0.94) !important;
	background-color: #dcdce2 !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:hover,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:active,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html.over,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html.down,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html.checked {
	background-color: transparent !important;
	transform: none !important;
	border-color: transparent !important;
}

/* Dark mode */
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.over {
	background-color: var(--bg-hover) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.checked,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.down {
	background-color: var(--bg-elev) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button:not(.w2ui-tb-html):active {
	background-color: var(--bg-elev) !important;
}
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:hover,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html.over,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:active {
	background-color: transparent !important;
	transform: none !important;
}
.createany > span,
.buildapp > span,
.testapp > span {
	display: inline-block;
	transition: transform 0.1s ease;
}

.buildapp:active,
.testapp:active,
.userid:active {
	transform: scale(0.94);
	box-shadow: none !important;
}
.createany:active {
	transform: translate(-50%, 0) scale(0.94);
	box-shadow: none !important;
}
.buildapp:active > span,
.testapp:active > span {
	transform: scale(0.94);
}

/* Kill the userid hover ring — use a subtle background tint instead */
.userid:hover {
	box-shadow: none;
	background-color: #C9DFFB;
}


/* ================================================================
 * Dialog / popup buttons — match the topbar flat-blue button style
 * (w2ui defaults are a gradient rounded pill; we want the same look
 * as .buildapp / .testapp for consistency)
 * ================================================================ */

input[type=button].w2ui-btn,
button.w2ui-btn {
	border-radius: 6px !important;
	padding: 0 16px !important;
	height: 32px !important;
	min-width: 80px !important;
	line-height: 32px !important;
	font-family: OpenSans, sans-serif !important;
	font-size: 14px !important;
	font-weight: 500 !important;
	border: 1px solid transparent !important;
	background: #E8E8EE !important;
	color: #404040 !important;
	box-shadow: none !important;
	text-shadow: none !important;
	margin: 0 4px !important;
	transition: background-color 0.15s ease, transform 0.1s ease !important;
	outline: none !important;
}
input[type=button].w2ui-btn:hover,
button.w2ui-btn:hover {
	background: #DCDCE2 !important;
	color: #202020 !important;
}
input[type=button].w2ui-btn:active,
button.w2ui-btn:active,
input[type=button].w2ui-btn.clicked,
button.w2ui-btn.clicked {
	background: #D0D0D6 !important;
	transform: scale(0.96) !important;
	text-shadow: none !important;
}
input[type=button].w2ui-btn:focus:before,
button.w2ui-btn:focus:before {
	content: none !important;
	border: none !important;
}

/* Restore compact sizing for small buttons (e.g. delete in tags dialog).
   The w2ui-btn rule above sets min-width/padding that would overflow a row. */
input[type=button].w2ui-btn.w2ui-btn-small,
button.w2ui-btn.w2ui-btn-small {
	padding: 5px !important;
	height: auto !important;
	min-width: 0 !important;
	line-height: normal !important;
}

input[type=button].w2ui-btn-blue,
button.w2ui-btn-blue {
	background: #269DF0 !important;
	color: white !important;
	border: 1px solid #269DF0 !important;
	text-shadow: none !important;
}
input[type=button].w2ui-btn-blue:hover,
button.w2ui-btn-blue:hover {
	background: #1F84C6 !important;
	border-color: #1F84C6 !important;
	color: white !important;
}
input[type=button].w2ui-btn-blue:active,
button.w2ui-btn-blue:active,
input[type=button].w2ui-btn-blue.clicked,
button.w2ui-btn-blue.clicked {
	background: #1268A6 !important;
	border-color: #1268A6 !important;
	color: white !important;
	transform: scale(0.96) !important;
}

/* Red / delete buttons — flat style matching the blue button treatment */
input[type=button].w2ui-btn-red,
button.w2ui-btn-red {
	background: #d32f2f !important;
	background-image: none !important;
	color: white !important;
	border: 1px solid #d32f2f !important;
	text-shadow: none !important;
}
input[type=button].w2ui-btn-red:hover,
button.w2ui-btn-red:hover {
	background: #b71c1c !important;
	border-color: #b71c1c !important;
	color: white !important;
}
input[type=button].w2ui-btn-red:active,
button.w2ui-btn-red:active,
input[type=button].w2ui-btn-red.clicked,
button.w2ui-btn-red.clicked {
	background: #8b0000 !important;
	border-color: #8b0000 !important;
	color: white !important;
	transform: scale(0.96) !important;
}
/* A DISABLED red button must not still look armed. The rules above are all
   !important, so without this the Drop confirmation's button stays bright red
   while it is still inert — which reads as "click me" for the whole time the
   user has not yet typed the confirmation, and makes the guard look broken. */
input[type=button].w2ui-btn-red[disabled],
button.w2ui-btn-red[disabled],
input[type=button].w2ui-btn-red:disabled,
button.w2ui-btn-red:disabled {
	background: #e0b4b4 !important;
	border-color: #e0b4b4 !important;
	color: #fdf2f2 !important;
	cursor: not-allowed !important;
	transform: none !important;
}
body.appbuilder-dark button.w2ui-btn-red[disabled],
body.appbuilder-dark button.w2ui-btn-red:disabled {
	background: #5a3030 !important;
	border-color: #5a3030 !important;
	color: #9a8080 !important;
}
input[type=button].w2ui-btn-red:focus:before,
button.w2ui-btn-red:focus:before {
	content: none !important;
}

/* Dark-mode variants for dialog buttons */
body.appbuilder-dark input[type=button].w2ui-btn,
body.appbuilder-dark button.w2ui-btn {
	background: var(--bg-elev) !important;
	color: var(--fg) !important;
	border-color: var(--border-strong) !important;
}
body.appbuilder-dark input[type=button].w2ui-btn:hover,
body.appbuilder-dark button.w2ui-btn:hover {
	background: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark input[type=button].w2ui-btn-blue,
body.appbuilder-dark button.w2ui-btn-blue {
	background: #269DF0 !important;
	color: white !important;
	border-color: #269DF0 !important;
}
body.appbuilder-dark input[type=button].w2ui-btn-blue:hover,
body.appbuilder-dark button.w2ui-btn-blue:hover {
	background: #1F84C6 !important;
	border-color: #1F84C6 !important;
	color: white !important;
}

/* RED, in dark mode. Why this keeps getting rediscovered:
   `body.appbuilder-dark button.w2ui-btn` above is (0,2,2) and !important, while
   the light-mode `button.w2ui-btn-red` is (0,1,1) and !important. Both are
   !important, so specificity decides and the neutral dark rule wins — every red
   button in the builder silently turns grey the moment dark mode is on, no
   matter how emphatically the red is declared elsewhere.
   Blue already had its dark twin, which is why blue never broke and red did.
   RULE: a colour variant declared for light mode must be declared here too.
   Adding one below without a dark counterpart is adding a bug. */
body.appbuilder-dark input[type=button].w2ui-btn-red,
body.appbuilder-dark button.w2ui-btn-red,
body.appbuilder-dark .w2ui-btn.recipe-danger {
	background: #d32f2f !important;
	color: white !important;
	border-color: #d32f2f !important;
}
body.appbuilder-dark input[type=button].w2ui-btn-red:hover,
body.appbuilder-dark button.w2ui-btn-red:hover,
body.appbuilder-dark .w2ui-btn.recipe-danger:hover {
	background: #b71c1c !important;
	border-color: #b71c1c !important;
	color: white !important;
}


/* ================================================================
 * Dark mode
 * Scoped to body.appbuilder-dark so it only affects the AppBuilder.
 * ================================================================ */

body.appbuilder-dark {
	/* color tokens */
	--bg:          #1a1a1a;
	--bg-alt:      #222222;
	--bg-panel:    #2b2b2b;
	--bg-elev:     #333333;
	--bg-hover:    #3a3a3a;
	--bg-input:    #2b2b2b;
	--fg:          #e6e6e6;
	--fg-muted:    #a0a0a0;
	--fg-strong:   #ffffff;
	--border:      #3a3a3a;
	--border-strong: #505050;
	/* Empty-track colour for every gauge/progress bar in the portfolio panels.
	   Its own token rather than --border: a track is a surface you read a fill
	   against, and it needs more presence on a card than a hairline does. */
	--pf-track:    #3a3a44;
	--accent:      #269DF0;
	--accent-hover:#2685C4;

	background-color: var(--bg);
	color: var(--fg);
}

body.appbuilder-dark .topmainform {
	background-color: var(--bg-alt) !important;
	color: var(--fg);
	border-bottom: 1px solid var(--border);
}

body.appbuilder-dark .builder_title,
body.appbuilder-dark .builder_title div,
body.appbuilder-dark .builder_application_title {
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder_application_title:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}

/* Requirements / objectives acceptance criteria text */
body.appbuilder-dark .builder-acceptable-criteria {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-acceptable-criteria div[followup] {
	border-top-color: var(--border) !important;
}
body.appbuilder-dark .builder-acceptable-criteria div[followup] > div {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-acceptable-criteria div[followup] > span {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .application_element div[expand],
body.appbuilder-dark .application_element div[collapse] {
	color: var(--fg) !important;
}

/* Datamodel column properties table — cell borders use --border-strong
   (#505050) instead of --border (#3a3a3a) because the card background is
   already --bg-elev (#333333); with only 3 units of contrast the grid was
   almost invisible. --border-strong reads as a clear line against it. */
body.appbuilder-dark .builder-table-properties {
	border-color: var(--border-strong) !important;
}
body.appbuilder-dark .builder-table-properties td {
	border-right-color: var(--border-strong) !important;
	border-bottom-color: var(--border-strong) !important;
	color: var(--fg);
}

body.appbuilder-dark .searchall input,
body.appbuilder-dark input.w2ui-input:not(.color),
body.appbuilder-dark textarea.w2ui-input,
body.appbuilder-dark input[type=text]:not(.color),
body.appbuilder-dark input[type=search],
body.appbuilder-dark input[type=number],
body.appbuilder-dark input[type=email],
body.appbuilder-dark input[type=password],
body.appbuilder-dark textarea {
	background-color: var(--bg-input) !important;
	color: var(--fg) !important;
	border-color: var(--border-strong) !important;
}
/* ONE number-field pattern, everywhere: a w2ui input with the browser's own
   stepper (the order ticket's Stop / Target). In dark mode the stepper has
   to be asked for in dark — `color-scheme` on the INPUT, it is not inherited
   usefully from a container — or Chrome paints its light widget on the dark
   field. That mismatch is what once made a hand-drawn stepper appear as a
   second pattern; it is gone, and this rule is why it is not needed. */
input[type=number] { accent-color:var(--accent, #269DF0); }
body.appbuilder-dark input[type=number] { color-scheme:dark; }

/* Color-picker inputs in the tags dialog.  The w2ui.css dark-mode rule
   `body.appbuilder-dark .w2ui-reset input:not([type=button]):not([type=submit])
    :not([type=checkbox]):not([type=radio])` has specificity (0,6,2) and
   forces background-color to var(--w2-bg-input).  Match its :not() chain
   so we reach (0,8,3) and win the cascade.  Background comes from the
   --tag-color-bg custom property the JS sets on the element. */
html body.appbuilder-dark input.w2ui-input.color[readonly]:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]) {
	background-color: var(--tag-color-bg, var(--border-strong)) !important;
	color: transparent !important;
	-webkit-text-fill-color: transparent !important;
	border-color: var(--border-strong) !important;
}

body.appbuilder-dark .createany {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg) !important;
}
body.appbuilder-dark .createany > span {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .createany:hover {
	background-color: var(--bg-hover) !important;
}
body.appbuilder-dark .createany:hover > span {
	color: var(--fg-strong) !important;
}

/* Search input in top bar */
body.appbuilder-dark .searchall > input {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg) !important;
	/* The smallsearch.png has a white circle; hide it and use
	   a CSS filter on the input to show it inverted. */
	background-image: none !important;
}
/* Re-add the search icon via a pseudo-element on the container */
body.appbuilder-dark .searchall {
	position: absolute;
}
body.appbuilder-dark .searchall::before {
	content: '\f002';
	font-family: FontAwesome;
	position: absolute;
	left: 12px;
	top: 50%;
	transform: translateY(-50%);
	font-size: 13px;
	color: var(--fg-muted);
	z-index: 1;
	pointer-events: none;
}
/* Recently viewed popup (.popup-recents) */
body.appbuilder-dark .popup-recents {
	background-color: var(--bg-panel) !important;
	border-color: var(--border) !important;
	color: var(--fg) !important;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6) !important;
}
body.appbuilder-dark .popup-recents p {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .popup-recents > div > div {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .popup-recents > div > div > span {
	color: var(--fg) !important;
	font-weight: 400 !important;
}
body.appbuilder-dark .popup-recents div:hover {
	background-color: var(--bg-hover) !important;
}

/* Autocomplete / recently viewed popup */
body.appbuilder-dark .popup-autocomplete {
	background-color: var(--bg-panel) !important;
	border-color: var(--border) !important;
	color: var(--fg) !important;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6) !important;
}
body.appbuilder-dark .popup-autocomplete-categories {
	background-color: var(--bg-alt) !important;
	border-right-color: var(--border) !important;
}
body.appbuilder-dark .popup-autocomplete-categories div:hover {
	background-color: var(--bg-hover) !important;
}

/* Prevent category names from wrapping */
.popup-autocomplete-categories div {
	white-space: nowrap !important;
	overflow: hidden !important;
	text-overflow: ellipsis !important;
}
body.appbuilder-dark .popup-autocomplete-categories i {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .popup-autocomplete-selected {
	background-color: rgba(38, 157, 240, 0.25) !important;
	border-color: var(--border) !important;
}
body.appbuilder-dark .popup-autocomplete-result > div > div > div {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .popup-autocomplete-result > div > div > div > span {
	color: var(--fg) !important;
	font-weight: 400 !important;
}
body.appbuilder-dark .popup-autocomplete-result div > div:hover {
	background-color: var(--bg-hover) !important;
}

/* Kill the autocomplete wrapper circle */
body.appbuilder-dark .searchall .w2ui-field-helper {
	background: transparent !important;
	border: 0 !important;
	box-shadow: none !important;
}

/* Build and Test are major primary actions — each carries the
   color of the mode it transitions to (blue for Build, green for
   Test), matching the mode badge next to the title. */
body.appbuilder-dark .buildapp {
	background-color: #269DF0 !important;
	color: white !important;
}
body.appbuilder-dark .buildapp:hover  { background-color: #1F84C6 !important; }
body.appbuilder-dark .buildapp:active { background-color: #1268A6 !important; }

body.appbuilder-dark .testapp {
	background-color: #2CA85E !important;
	color: white !important;
}
body.appbuilder-dark .testapp:hover  { background-color: #238B4D !important; }
body.appbuilder-dark .testapp:active { background-color: #1B6A3A !important; }

body.appbuilder-dark .userid {
	background-color: var(--bg-elev);
}
body.appbuilder-dark .userid img {
	border-color: #000 !important;
}
body.appbuilder-dark .userid div {
	color: var(--fg-strong);
}
body.appbuilder-dark .userid:hover {
	box-shadow: none;
	background-color: #404858;
}
body.appbuilder-dark .thememode:hover {
	box-shadow: none;
	background-color: var(--bg-hover);
}

body.appbuilder-dark .thememode {
	background-color: var(--bg-elev);
}
body.appbuilder-dark .thememode il {
	color: #f5d061;
}

/* ================================================================
 * Tower Control standalone profile — published-app picker sits in
 * the top bar to the left of the light/dark toggle. Hidden by
 * default; Builder_PopulateTowerControlAppPicker shows it when the
 * standalone profile is active.
 * ================================================================ */
/* Host container only — the inner .wf-pickbtn (added by
   Builder_Workflow.AppendPickButton) carries its own light/dark
   styling, identical to the Constraints > Type picker. We just
   position the host in the top bar, left of the theme toggle
   (which sits at right:72px), and size it for app names. */
.tc-topbar-picker {
	position: absolute;
	top: 16px;
	right: 124px;
	width: 240px;
	display: flex;
	align-items: center;
}
.tc-topbar-picker .wf-pickbtn {
	height: 32px;
}

/* left sidebar — share background with the top bar */
body.appbuilder-dark .leftbar,
body.appbuilder-dark #mySidebar {
	background-color: var(--bg-alt) !important;
}
body.appbuilder-dark .leftbar_command,
body.appbuilder-dark .leftbar_item {
	color: #c0c0c0 !important;
	border-radius: 6px !important;
	border: 1px solid transparent !important;
	outline: none !important;
	transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease !important;
}
body.appbuilder-dark .leftbar_command:hover,
body.appbuilder-dark .leftbar_item:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
	border: 1px solid transparent !important;
}
body.appbuilder-dark .leftbar_command:active,
body.appbuilder-dark .leftbar_item:active {
	background-color: var(--bg-elev) !important;
	transform: scale(0.97) !important;
}
body.appbuilder-dark .leftbar_command:active i,
body.appbuilder-dark .leftbar_item:active i {
	transform: scale(0.98);
}

/* main application body and cards */
body.appbuilder-dark .application_body,
body.appbuilder-dark .applications_container {
	background-color: var(--bg) !important;
}

body.appbuilder-dark .applications_element,
body.appbuilder-dark .builder_recentobjects_element,
body.appbuilder-dark .builder_secondarypanel_card,
body.appbuilder-dark .application_element,
body.appbuilder-dark .agents_body_element {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg);
}
/* Collapsed columns/relationships inside a datamodel card inherit
   the parent card's background with no distinct tint or hover. */
body.appbuilder-dark .application_element_compact {
	background-color: transparent !important;
	border-color: var(--border) !important;
	color: var(--fg);
}

body.appbuilder-dark .applications_element:hover,
body.appbuilder-dark .application_element:hover,
body.appbuilder-dark .builder_recentobjects_element:hover,
body.appbuilder-dark .agents_body_element:hover {
	background-color: #3d3d3d !important;
}

body.appbuilder-dark .applications_element_text,
body.appbuilder-dark .builder_recentobjects_element_text,
body.appbuilder-dark .agents_body_element_text {
	color: var(--fg-muted);
}
body.appbuilder-dark .applications_element_text > span,
body.appbuilder-dark .builder_recentobjects_element_text > span,
body.appbuilder-dark .agents_body_element_text > span {
	color: var(--fg-strong);
}

body.appbuilder-dark .builder_recentobjects_container {
	background-color: var(--bg-panel) !important;
}

/* Secondary panel cards container */
body.appbuilder-dark .builder_secondarypanel_cards_container {
	background-color: var(--bg) !important;
}

/* Empty list */
body.appbuilder-dark .anylist_empty {
	color: var(--fg-muted);
}

/* Chat / thread body — main scroll area matches page background,
   individual messages get subtle panel tints to stand out. */
body.appbuilder-dark .builder-thread-body-container {
	background-color: var(--bg) !important;
	color: var(--fg);
	border-color: var(--border) !important;
}
/* Current-user prompts — blue tint to clearly distinguish from
   peer-user messages (dark gray) and agent answers (panel tint). */
body.appbuilder-dark .builder-thread-body-prompt {
	background-color: rgba(38, 157, 240, 0.12) !important;
	color: var(--fg) !important;
	border: 1px solid rgba(38, 157, 240, 0.25) !important;
	border-radius: 12px !important;
}
/* Assistant answers — subtle panel tint to distinguish from bg */
body.appbuilder-dark .builder-thread-body-answer {
	background-color: transparent !important;
	color: var(--fg-muted);
	border-color: transparent !important;
}

/* Answer form cards (Create Contact, etc.) */
body.appbuilder-dark .builder-thread-body-answer div[form] {
	background-color: var(--bg-panel) !important;
	color: var(--fg-muted) !important;
	border: 1px solid var(--border);
}
body.appbuilder-dark .builder-thread-body-answer div[form] > div[icon] {
	background-color: var(--bg-elev) !important;
}
body.appbuilder-dark .builder-thread-body-answer div[form] > div[description] > span {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-thread-body-answer div[form]:hover {
	background-color: var(--bg-hover) !important;
}
body.appbuilder-dark .builder-thread-body-answer span[sourceid] {
	background-color: var(--bg-elev) !important;
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .builder-thread-body-answer span[sourceid]:hover {
	background-color: var(--bg-hover) !important;
}

/* Prompt block (the rounded container housing the textarea and
   the + / send buttons) — elevated panel, with no border fighting
   the main page. */
body.appbuilder-dark .builder-thread-prompt {
	background-color: var(--bg-panel) !important;
	border: 1px solid var(--border) !important;
	color: var(--fg);
}

/* Textarea inside the prompt block — blend with the prompt block,
   no border, no focus ring. The prompt block itself provides the
   visual container. */
html body.appbuilder-dark .builder-thread-prompt textarea,
html body.appbuilder-dark .builder-thread-prompt textarea:focus {
	background-color: transparent !important;
	background: transparent !important;
	color: var(--fg) !important;
	-webkit-text-fill-color: var(--fg) !important;
	border: 0 !important;
	outline: none !important;
	box-shadow: none !important;
}
body.appbuilder-dark .builder-thread-prompt textarea::placeholder {
	color: var(--fg-muted) !important;
	-webkit-text-fill-color: var(--fg-muted) !important;
}

/* The "+" / more-options button in the prompt block — neutral */
/* Card chips (invited users, picked agents, uploaded files) sitting
   inside the prompt's #moreinfo area — pale cream in light mode is
   unreadable in dark; switch to the elevated surface tone and tune
   the inner text so name / position lines stay legible. */
body.appbuilder-dark .builder-chatbot-moreinfo > div {
	background-color: var(--bg-elev) !important;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[name] {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-chatbot-moreinfo-agent div[position] {
	color: var(--fg-muted) !important;
}
/* Close (×) glyph defaults to near-black for light mode — invisible
   against the dark card background. Switch to the muted foreground
   tone and brighten the hover halo so the affordance reads. */
body.appbuilder-dark .builder-chatbot-moreinfo div[close] {
	color: var(--fg-muted) !important;
}

body.appbuilder-dark .builder-chatbot-button-icon {
	background-color: var(--bg-elev) !important;
	color: var(--fg) !important;
	transition: background-color 0.15s ease, transform 0.1s ease !important;
}
body.appbuilder-dark .builder-chatbot-button-icon:hover {
	background-color: var(--bg-hover) !important;
}
body.appbuilder-dark .builder-chatbot-button-icon:active {
	transform: scale(0.92) !important;
}

/* The send-message button — brand blue with press feedback */
body.appbuilder-dark .builder-chatbot-button-icon-alt {
	background-color: #269DF0 !important;
	color: white !important;
	transition: background-color 0.15s ease, transform 0.1s ease !important;
}
body.appbuilder-dark .builder-chatbot-button-icon-alt:hover {
	background-color: #1F84C6 !important;
}
body.appbuilder-dark .builder-chatbot-button-icon-alt:active {
	background-color: #1268A6 !important;
	transform: scale(0.92) !important;
}
body.appbuilder-dark .builder-chatbot-button-icon-alt il {
	color: white !important;
}

/* All tags in dark mode — muted semi-transparent backgrounds with
   softer text so they integrate with the dark surface. Compact 6px
   radius on grid tags. */
body.appbuilder-dark .grid_tag,
body.appbuilder-dark .builder-tag,
body.appbuilder-dark .builder-tags > div {
	border-radius: 6px !important;
}
body.appbuilder-dark .tag-added {
	background-color: rgba(46, 204, 113, 0.25) !important;
	color: #6ee7a0 !important;
}
body.appbuilder-dark .tag-updated {
	background-color: rgba(241, 196, 15, 0.2) !important;
	color: #f5d76e !important;
}
body.appbuilder-dark .tag-deleted {
	background-color: rgba(231, 76, 60, 0.25) !important;
	color: #f08070 !important;
}
body.appbuilder-dark .tag-domain {
	background-color: rgba(87, 73, 100, 0.5) !important;
	color: #c4b0d6 !important;
}
body.appbuilder-dark .tag-table {
	background-color: rgba(159, 131, 131, 0.35) !important;
	color: #d4b8b8 !important;
}
body.appbuilder-dark .tag-workflow {
	background-color: rgba(200, 170, 170, 0.25) !important;
	color: #d4b8b8 !important;
}
body.appbuilder-dark .tag-dependency {
	background-color: rgba(255, 218, 179, 0.2) !important;
	color: #f0c89a !important;
}
body.appbuilder-dark .tag-metadata {
	background-color: rgba(200, 170, 170, 0.25) !important;
	color: #d4b8b8 !important;
}
body.appbuilder-dark .tag-relationship {
	background-color: rgba(255, 218, 179, 0.2) !important;
	color: #f0c89a !important;
}
body.appbuilder-dark .tag-column {
	background-color: rgba(200, 170, 170, 0.25) !important;
	color: #d4b8b8 !important;
}
body.appbuilder-dark .tag-status {
	background-color: rgba(100, 150, 220, 0.2) !important;
	color: #8ab4e6 !important;
}
body.appbuilder-dark .tag-priority {
	background-color: rgba(160, 170, 190, 0.2) !important;
	color: #a0aabe !important;
}
body.appbuilder-dark .tag-category {
	background-color: rgba(244, 180, 140, 0.2) !important;
	color: #e8b89a !important;
}
body.appbuilder-dark .tag-is-main-table {
	background-color: rgba(244, 180, 140, 0.2) !important;
	color: #e8b89a !important;
}
body.appbuilder-dark .tag-type {
	background-color: rgba(244, 180, 140, 0.2) !important;
	color: #e8b89a !important;
}
body.appbuilder-dark .tag-related-requirement {
	background-color: rgba(180, 180, 180, 0.15) !important;
	border: 1px solid #505050 !important;
	color: #a0a0a0 !important;
}

body.appbuilder-dark .chat_button {
	background-color: #269DF0 !important;
	color: white !important;
	border: 0 !important;
}
body.appbuilder-dark .chat_button:hover {
	background-color: #1F84C6 !important;
}
body.appbuilder-dark .chat_button:active {
	background-color: #1268A6 !important;
	transform: scale(0.94) !important;
}

/* Diff / preview row markers — softer semantic tints so cards still
   read as "cards" rather than color blocks. */
body.appbuilder-dark .req-row-added    { background-color: #296839 !important; color: var(--fg); }
body.appbuilder-dark .req-row-updated  { background-color: #8a3f24 !important; color: var(--fg); }
body.appbuilder-dark .req-row-deleted  { background-color: #732B3C !important; color: #c0c0c0 !important; }
body.appbuilder-dark .req-row-deprecated { background-color: #262626 !important; color: var(--fg); }
body.appbuilder-dark .req-cell-added { background-color: #296839 !important; color: var(--fg); }
body.appbuilder-dark .req-cell-changed { background-color: #D56938 !important; color: var(--fg); }
body.appbuilder-dark .req-cell-deleted { color: #732B3C !important; }

/* Diff grid rows — w2grid paints TD cells via .w2ui-even/.w2ui-odd
   rules. Include `table` in our selector path so the specificity
   beats body.appbuilder-dark .w2ui-grid .w2ui-grid-records table
   tr.w2ui-even td (which is (0,4,4)). Our rules must be at least
   (0,5,3) to win everywhere, including on the alternating rows
   and on selected rows. */

/* IMPORTANT: specificity matters here.  w2ui.css defines selected-row
   rules like `.w2ui-grid .w2ui-grid-body .w2ui-grid-records tr.w2ui-selected td`
   at (0,5,4).  Our per-state selectors need to beat that unconditionally
   — not win on a source-order tie — otherwise a refresh/cache quirk can
   flip the cascade and the whole diff grid takes on the pale selected-
   row tint instead of the proper green/orange/red state color.  Adding
   `.w2ui-grid-body` to our ancestor chain gives us (0,6,4) which beats
   the w2ui selected rule regardless of loading order. */
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-selected td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added td.w2ui-selected,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-even td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-odd td   { background-color: #296839 !important; }

.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-selected td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated td.w2ui-selected,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-even td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-odd td { background-color: #D56938 !important; }

.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-selected td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted td.w2ui-selected,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-even td,
.w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-odd td { background-color: #732B3C !important; color: #606060 !important; }

body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-selected td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added td.w2ui-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-even td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-added.w2ui-odd td   { background-color: #296839 !important; color: var(--fg) !important; }

body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-selected td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated td.w2ui-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-even td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-updated.w2ui-odd td { background-color: #8a3f24 !important; color: var(--fg) !important; }

body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-selected td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted td.w2ui-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-even td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body .w2ui-grid-records table tr.req-row-deleted.w2ui-odd td { background-color: #732B3C !important; color: #c0c0c0 !important; }

/* Consistent borders on diff grid rows regardless of state
   (w2grid applies dotted / light / dashed borders on .w2ui-even,
   .w2ui-odd and .w2ui-selected which look inconsistent here). */
.w2ui-grid .w2ui-grid-records table tr.req-row-added td,
.w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data,
.w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data-spacer,
.w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data-last,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data-spacer,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data-last,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data-spacer,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data-last {
	border-top: 0 !important;
	border-bottom: 1px solid #e0e0e0 !important;
	border-left: 0 !important;
	border-right: 1px solid #e0e0e0 !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data-spacer,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-grid-data-last,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data-spacer,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-grid-data-last,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data-spacer,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-grid-data-last {
	border-top: 0 !important;
	border-bottom: 1px solid var(--border) !important;
	border-left: 0 !important;
	border-right: 1px solid var(--border) !important;
}

/* Force the checkbox column cell to a solid dark bg in dark mode,
   overriding the w2ui default selection-column tint. Target any
   td/th that contains a checkbox input. */
body.appbuilder-dark .w2ui-grid td:has(input[type="checkbox"]),
body.appbuilder-dark .w2ui-grid th:has(input[type="checkbox"]) {
	background-color: var(--bg) !important;
	border-color: var(--border) !important;
}

/* The CELL above is dark, but the checkbox itself is a NATIVE control the
   browser paints — and it paints a white box, which on a dark grid reads as a
   row of little lights. `color-scheme: dark` asks the browser for its own dark
   rendering instead: mid-grey fill, lighter grey border, and — the reason to
   prefer it over hand-painting — the checked, INDETERMINATE (the header's
   partial-select dash), focus-ring and disabled states all follow, where
   `appearance:none` + a drawn checkmark would have to restate each one and
   loses the dash outright. accent-color puts the app's blue in the checked box
   rather than the browser's default. Excludes .w2ui-toggle: that input is
   visually hidden and drawn by its sibling <div>, so it has no native box. */
body.appbuilder-dark .w2ui-grid input[type="checkbox"]:not(.w2ui-toggle) {
	color-scheme: dark;
	accent-color: var(--accent);
}

/* ================================================================
 * Frozen left panel (checkbox / select column)
 * w2ui renders the selection column in a separate frozen area
 * (.w2ui-grid-frecords / .w2ui-grid-fcolumns) with its own
 * tr.w2ui-odd / .w2ui-even rules. Cover it all in dark mode.
 * ================================================================ */
body.appbuilder-dark .w2ui-grid .w2ui-grid-fcolumns {
	box-shadow: none !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-fcolumns,
body.appbuilder-dark .w2ui-grid .w2ui-grid-fcolumns *,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords {
	background-color: var(--bg) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.w2ui-odd,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.w2ui-even {
	background-color: var(--bg) !important;
	border: 0 !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr td {
	background-color: var(--bg) !important;
	border-right: 1px solid var(--border) !important;
	border-bottom: 1px solid var(--border) !important;
	border-top: 0 !important;
	border-left: 0 !important;
}
/* State-colored rows in the frozen area (diff grids) */
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-added,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-added td {
	background-color: #1d2e22 !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-updated,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-updated td {
	background-color: #2e2818 !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-deleted,
body.appbuilder-dark .w2ui-grid .w2ui-grid-frecords table tr.req-row-deleted td {
	background-color: #2e1d1d !important;
}

/* Kill the light blue/gray selection highlight on checkbox columns
   (w2ui-col-selected / w2ui-row-selected). The row's state color
   should paint everything, including the checkbox cell. */
.w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-col-select.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-added.w2ui-row-selected td.w2ui-col-select { background-color: #e6ffed !important; }
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-col-select.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-updated.w2ui-row-selected td.w2ui-col-select { background-color: #fff9e6 !important; }
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-col-select.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-col-selected,
.w2ui-grid .w2ui-grid-records table tr.req-row-deleted.w2ui-row-selected td.w2ui-col-select { background-color: #ffecec !important; }

body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-col-select.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added td.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-added.w2ui-row-selected td.w2ui-col-select { background-color: #1d2e22 !important; }
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-col-select.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated td.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-updated.w2ui-row-selected td.w2ui-col-select { background-color: #2e2818 !important; }
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-col-select.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted td.w2ui-col-selected,
body.appbuilder-dark .w2ui-grid .w2ui-grid-records table tr.req-row-deleted.w2ui-row-selected td.w2ui-col-select { background-color: #2e1d1d !important; }

/* Column header row — w2ui v2 emits <td class="w2ui-head">, not
   <th>, so target those. Parent .w2ui-grid-columns also needs a
   dark background so the transparent header cells don't show
   white through. */
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns,
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns *,
body.appbuilder-dark .w2ui-grid .w2ui-grid-fcolumns,
body.appbuilder-dark .w2ui-grid .w2ui-grid-fcolumns *,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body,
body.appbuilder-dark .w2ui-grid .w2ui-grid-body > div,
body.appbuilder-dark .w2ui-grid .w2ui-grid-header,
body.appbuilder-dark .w2ui-grid .w2ui-grid-header * {
	background-color: var(--bg-alt) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns td.w2ui-head,
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns td.w2ui-head.w2ui-head-last {
	background-color: var(--bg-alt) !important;
	color: var(--fg) !important;
	border-color: var(--border) !important;
}

/* Selection column on rows WITHOUT a state class stays neutral dark
   (for any other grid). Rows with a req-row-* class inherit their
   state color on the select column via the rules above (which use
   `td` without further qualification, so they match every cell
   including the checkbox column). */
body.appbuilder-dark .w2ui-grid .w2ui-grid-records td.w2ui-col-select {
	background-color: var(--bg) !important;
	border-color: var(--border) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns th.w2ui-col-select,
body.appbuilder-dark .w2ui-grid .w2ui-grid-columns td.w2ui-col-select {
	background-color: var(--bg) !important;
	border-color: var(--border) !important;
}

/* New thread home page — prompt block + label */
body.appbuilder-dark .builder-new-thread-label {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-new-thread-prompt {
	background-color: var(--bg-panel) !important;
	border: 1px solid var(--border) !important;
	color: var(--fg);
}
body.appbuilder-dark .builder-new-thread-prompt textarea,
html body.appbuilder-dark .builder-new-thread-prompt textarea:focus {
	background: transparent !important;
	color: var(--fg) !important;
	-webkit-text-fill-color: var(--fg) !important;
	border: 0 !important;
	outline: none !important;
	box-shadow: none !important;
}
body.appbuilder-dark .builder-new-thread-prompt textarea::placeholder {
	color: var(--fg-muted) !important;
	-webkit-text-fill-color: var(--fg-muted) !important;
}
body.appbuilder-dark .builder-new-thread-logo:hover {
	border-color: var(--border) !important;
}

/* Themeable background classes — used throughout search entries,
   bulk edit, entry details, and secondary panels instead of
   inline background-color. */
.bg-page    { background-color: #FAF8F5; }
.bg-block   { background-color: #F2F0EC; }
.bg-surface { background-color: white; }

body.appbuilder-dark .bg-page    { background-color: var(--bg) !important; }
body.appbuilder-dark .bg-block   { background-color: var(--bg-alt) !important; }
body.appbuilder-dark .bg-surface { background-color: var(--bg-alt) !important; }

/* Dark-mode framing: paint a 1px border on the OUTERMOST .bg-block
   in any nesting chain so each surface card has a visible outline
   against the dark page. Nested .bg-blocks inside another
   .bg-block keep no border, to avoid double-rectangle artifacts
   (FilesClass uses nested bg-blocks for the folder sidebar; the
   entry-screen form uses bg-block inside bg-block too). */
body.appbuilder-dark .bg-block,
body.appbuilder-dark .bg-surface {
	border: 1px solid var(--border);
}
body.appbuilder-dark .bg-block .bg-block,
body.appbuilder-dark .bg-block .bg-surface,
body.appbuilder-dark .bg-surface .bg-block,
body.appbuilder-dark .bg-surface .bg-surface {
	border: none;
}

/* FilesClass framing in dark mode — applies to EVERY instance of
   FilesClass (Documentation step + entry-screen Files tab) so the
   two read identically.
     - Folder sidebar: _WrapInBgBlock creates an OUTER bg-block
       that contains an INNER bg-block. We frame only the outer
       one (the inner is the host for w2sidebar). Selector
       `bg-block:has(> .bg-block)` matches exactly the outer.
     - File display area: only a single bg-block (no nested
       bg-block child). Its frame would double with the w2grid
       outline in Details view, so we suppress it here. The
       inner main_container's drop-zone ring (the
       `_containerFiles…` div, normally `2px solid transparent`)
       flips to `2px solid var(--border)` in dark mode so the
       frame stays visible whether Icons or Grid are rendered. */
body.appbuilder-dark .files-class-root .bg-block:has(> .bg-block) {
	border: 1px solid var(--border);
}
body.appbuilder-dark .files-class-root .bg-block:not(:has(> .bg-block)) {
	border-color: transparent;
}
body.appbuilder-dark .files-class-root [id^="_containerFiles"] {
	border-color: var(--border) !important;
}
/* Clip the file-display contents to the rounded corners.
   main_container is `position:absolute; border-radius:12px` but has
   no overflow:hidden — without this rule the rectangular header
   background and grid rows bleed into the rounded corners,
   producing the "corner covered" look. Applied in both modes
   because the issue is purely geometric. */
.files-class-root [id^="_containerFiles"] {
	overflow: hidden;
}

/* Notification toasts — inherit app font */
#w2ui-notify > div {
	font-family: OpenSans, sans-serif !important;
}

/* Favorites container — group headers and cards */
body.appbuilder-dark .favorites_container {
	color: var(--fg) !important;
}
body.appbuilder-dark .favorites_container div[expanded] > span:hover,
body.appbuilder-dark .favorites_container div[collapsed] > span:hover {
	background-color: var(--bg-hover) !important;
}

/* Home left tab (New Thread, Favorites, Tables) — colors match the
   main sidebar: idle text is #c0c0c0 (same muted gray the sidebar
   icons use in dark mode) and only brightens to var(--fg-strong) on
   hover or when selected, instead of being full-brightness at rest. */
body.appbuilder-dark .builder-leftbar-home div {
	color: #c0c0c0 !important;
}
body.appbuilder-dark .builder-leftbar-home div[selected] {
	background-color: var(--bg-panel) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder-leftbar-home div:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}

/* Thread / Dashboard history list */
body.appbuilder-dark .builder-allthreads-element,
body.appbuilder-dark .builder-alldashboards-element {
	border-bottom-color: var(--border) !important;
}
body.appbuilder-dark .builder-allthreads-element > div[name],
body.appbuilder-dark .builder-alldashboards-element > div[name] {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-allthreads-element > div[description],
body.appbuilder-dark .builder-alldashboards-element > div[description] {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .builder-allthreads-element > div[date],
body.appbuilder-dark .builder-alldashboards-element > div[date] {
	color: var(--fg-muted) !important;
}

/* Threads left sidebar — New Thread, History, Recent + thread list.
   Same muted #c0c0c0 as the main sidebar at rest; brightens to
   var(--fg-strong) on hover / when selected (matching the sidebar
   icon behaviour instead of sitting at full brightness at rest). */
body.appbuilder-dark .builder-threads-home div,
body.appbuilder-dark .builder-dashboards-home div {
	color: #c0c0c0 !important;
}
body.appbuilder-dark .builder-threads-home div[selected],
body.appbuilder-dark .builder-dashboards-home div[selected] {
	background-color: var(--bg-panel) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder-threads-home div[command]:hover,
body.appbuilder-dark .builder-dashboards-home div[command]:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder-threads-home-lastthreads,
body.appbuilder-dark .builder-dashboards-home-lastdashboards {
	border-left-color: var(--border) !important;
}

/* History panel */
body.appbuilder-dark .history_container {
	background-color: var(--bg) !important;
}
body.appbuilder-dark .log_container {
	border-left-color: var(--border) !important;
}
body.appbuilder-dark .log_container > i[small],
body.appbuilder-dark .log_container > i[normal] {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .log_container > div[title] {
	color: var(--fg) !important;
}
body.appbuilder-dark .log_container > div[subtitle],
body.appbuilder-dark .log_container > div[content] {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .logs_more {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
}

/* Entity header */
body.appbuilder-dark .entityheader_title {
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .entityheader_logo img {
	border-color: var(--border) !important;
}

body.appbuilder-dark .overview_field_label {
	color: var(--fg-muted) !important;
}

/* Waiting spinner — white bg + bright blue is harsh in dark mode */
body.appbuilder-dark .waiting_icon {
	background-color: var(--bg-panel) !important;
	box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5) !important;
}
body.appbuilder-dark .waiting_icon > div[spin] {
	border: 5px solid var(--border-strong) !important;
	border-top-color: var(--accent) !important;
}
body.appbuilder-dark .waiting_icon > div[text] {
	color: var(--fg-muted) !important;
}


/* Gallery nav buttons in dark mode — mirror .builder-thread-scrollto
   so vertical and horizontal scroll affordances share one chip. */
body.appbuilder-dark .builder-thread-nav {
	background-color: var(--bg-elev) !important;
	border-color: var(--border) !important;
	color: var(--fg-muted) !important;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4) !important;
}
body.appbuilder-dark .builder-thread-nav:hover {
	background-color: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}

/* Banner "X sources" pill — dark-mode hover: subtle elevated
   panel + teal-blue accent text, mirroring the light-mode hover
   on a dark surface. */
body.appbuilder-dark .builder-thread-body-banner div[sources]:hover {
	background-color: var(--bg-elev) !important;
	color: #E6E6E6 !important;
}

/* Tooltips */
body.appbuilder-dark .builder-thread-body-tooltip {
	background-color: var(--bg-elev) !important;
	color: var(--fg);
	border-color: var(--border) !important;
}

/* Light-mode tooltip text colors are dark-on-light by design; in
   dark mode the same hex values disappear into the panel. Lift
   title to the foreground color and snippet to the muted variant
   so the hierarchy still reads. */
body.appbuilder-dark .builder-thread-body-tooltip div[title] {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-thread-body-tooltip div[title]:hover {
	color: rgb(96, 165, 250) !important;
}
body.appbuilder-dark .builder-thread-body-tooltip div[snippet] {
	color: var(--fg-muted) !important;
}

/* Sources right-panel content — light-mode uses dark-on-light
   grays that leak into the dark theme as nearly-illegible text
   on a dark panel. Recolor the container, the per-source items
   and the table header. */
body.appbuilder-dark .builder-threads-sources {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .builder-threads-sources div[source] > div[header] {
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-threads-sources div[source]:hover {
	background-color: var(--bg-elev) !important;
}
body.appbuilder-dark .builder-threads-source tr[header] {
	border-bottom-color: var(--border) !important;
}
body.appbuilder-dark .builder-threads-source tr[header] div[sources] {
	color: var(--fg) !important;
}

/* Generic w2ui integration (bright panels filled by builder) */
body.appbuilder-dark .w2ui-panel-top,
body.appbuilder-dark .w2ui-panel-main,
body.appbuilder-dark .w2ui-panel-right,
body.appbuilder-dark .w2ui-panel-preview,
body.appbuilder-dark .w2ui-panel-bottom,
body.appbuilder-dark .w2ui-panel-left {
	background-color: var(--bg) !important;
	border-color: var(--border) !important;
}

/* Generic panel style="background-color:#FAF8F5" inline — can't override.
 * Instead, use a filter-layer only where inline styles are used. */

/* ==============================================================
 * Structured search banner inside w2ui-grid toolbar
 * (the row under the grid header showing active filter chips,
 * Save and Clear buttons) — dark-mode colors + button restyling
 * in BOTH modes (w2ui defaults strip the button padding).
 * ============================================================== */

/* Save / Clear buttons in the search banner — restore sensible
 * padding and a clear look in light mode. w2ui sets padding:0
 * on these by default which cramps the text and leaves the base
 * w2ui-btn gradient / shadow looking like an oversized OS button
 * that doesn't fit the 36px banner height. */
/* Make the banner a positioning context so the absolutely-positioned
 * Clear button anchors to it (w2ui ships it as position:absolute with
 * no :relative parent — fine for its own 26px button, broken for ours). */
.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches {
	position: relative;
}

.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn,
.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn.btn-remove {
	box-sizing: border-box !important;
	padding: 0 12px !important;
	margin: 0 3px !important;
	min-width: 64px !important;
	height: 22px !important;
	line-height: 20px !important;
	border-radius: 11px !important;
	border: 1px solid #c8c9ca !important;
	background-image: none !important;
	background-color: #ffffff !important;
	color: #4c9ad6 !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	box-shadow: none !important;
	text-shadow: none !important;
	vertical-align: middle;
}
.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn:hover {
	background-image: none;
	background-color: #F1F7FE;
	color: #1F84C6;
	border-color: #88c3f7;
}
.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn.btn-remove {
	color: #c0392b !important;
	border-color: #e5b6b0 !important;
	background-color: #ffffff !important;
	/* Clear button only shows a cross — override the wider default
	 * min-width / padding we set above, and anchor it at the right
	 * edge of the banner. */
	min-width: 26px !important;
	width: 26px !important;
	padding: 0 !important;
	/* The banner has `margin: 7px -20px` (it extends 20px past the grid
	 * area on each side) and `padding-right: 50px`. Anchoring 28px from
	 * the banner's right edge places the button 8px inside the visible
	 * grid container. */
	position: absolute !important;
	right: 28px !important;
	left: auto !important;
	top: 7px !important;
}
.w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn.btn-remove:hover {
	background-color: #FDECEA;
	color: #922B21;
	border-color: #c0392b;
}

/* Dark-mode banner background + borders + text */
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches {
	background-color: var(--bg-alt) !important;
	border-top-color: var(--border) !important;
	border-bottom-color: var(--border) !important;
	color: var(--fg) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches > span {
	background-color: var(--bg-panel) !important;
	border-color: var(--accent) !important;
	color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches .grid-search-line {
	border-left-color: var(--border) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches .w2ui-grid-search-logic {
	background-color: var(--bg-panel) !important;
	border-color: var(--border-strong) !important;
	color: var(--fg) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn {
	background-color: var(--bg-panel) !important;
	border-color: var(--border-strong) !important;
	color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn:hover {
	background-color: var(--bg-elev) !important;
	color: #7BC0F5 !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn.btn-remove {
	color: #d98a8a !important;
	border-color: #7a3a3a !important;
}
body.appbuilder-dark .w2ui-grid .w2ui-grid-toolbar .w2ui-grid-searches button.grid-search-btn.btn-remove:hover {
	background-color: #3a2222 !important;
	color: #ff8a80 !important;
	border-color: #c0392b !important;
}

/* ==============================================================
 * Date picker (w2ui calendar) and time picker — dark mode.
 * The existing dark block in w2ui.css (~line 4827) uses class names
 * that don't match the real DOM (.w2ui-calendar-title/-days/-previous,
 * .w2ui-date-today, .w2ui-date-selected) so almost nothing there
 * actually applies — the calendar stays white-themed and the time
 * picker has no dark styling at all. These rules use the correct
 * class names (.w2ui-cal-title, .w2ui-cal-days, .w2ui-today,
 * .w2ui-selected, etc.) from w2ui.css lines 1394-1651.
 * ============================================================== */

/* Outer calendar container */
body.appbuilder-dark .w2ui-calendar,
body.appbuilder-dark .w2ui-calendar.w2ui-overlay-body {
	background-color: var(--bg-panel) !important;
	color: var(--fg) !important;
	border-color: var(--border-strong) !important;
	text-shadow: none !important;
	box-shadow: 0 4px 12px rgba(0,0,0,0.6) !important;
}

/* Month / year title bar */
body.appbuilder-dark .w2ui-calendar .w2ui-cal-title,
body.appbuilder-dark .w2ui-calendar .w2ui-time-title {
	background-color: var(--bg-elev) !important;
	color: var(--fg) !important;
	border-top-color: var(--border) !important;
	border-bottom-color: var(--border) !important;
	text-shadow: none !important;
}

/* Previous / next month arrows */
body.appbuilder-dark .w2ui-calendar .w2ui-cal-previous,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-next {
	color: var(--fg-muted) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-previous:hover,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-next:hover {
	background-color: var(--bg-hover) !important;
	border-color: var(--border) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-previous:active,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-next:active {
	background-color: var(--bg-hover) !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-previous > div,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-next > div {
	border-left-color: var(--fg-muted) !important;
	border-top-color: var(--fg-muted) !important;
}

/* Day grid */
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days {
	background-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day {
	background-color: var(--bg-elev) !important;
	color: var(--fg) !important;
	border-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-saturday,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-sunday {
	background-color: var(--bg-elev) !important;
	color: #e85d4d !important;
	border-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-today {
	background-color: rgba(38,157,240,0.22) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day:hover {
	background-color: var(--bg-hover) !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day:active {
	background-color: var(--bg-hover) !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-selected {
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-weekday {
	background-color: var(--bg-panel) !important;
	color: var(--fg-muted) !important;
	border-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-weekday:hover {
	background-color: var(--bg-panel) !important;
	border-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.outside {
	color: var(--fg-muted) !important;
	background-color: var(--bg-panel) !important;
	opacity: 0.5 !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-days .w2ui-day.w2ui-blocked {
	color: var(--fg-muted) !important;
	background-color: var(--bg-panel) !important;
	border-color: var(--bg-panel) !important;
}

/* Month / year jump panel */
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump {
	background-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump #w2ui-jump-month {
	border-right-color: var(--border) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-month,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-year {
	color: var(--fg) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-month:hover,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-year:hover {
	background-color: var(--bg-hover) !important;
	border-color: var(--border) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-month.w2ui-selected,
body.appbuilder-dark .w2ui-calendar .w2ui-cal-jump .w2ui-jump-year.w2ui-selected {
	background-color: var(--accent) !important;
	border-color: var(--accent) !important;
	color: #fff !important;
}

/* "Today & Now" footer button */
body.appbuilder-dark .w2ui-calendar .w2ui-cal-now {
	background-color: var(--bg-elev) !important;
	color: var(--fg) !important;
	border-color: var(--border-strong) !important;
}
body.appbuilder-dark .w2ui-calendar .w2ui-cal-now:hover {
	background-color: var(--bg-hover) !important;
	color: var(--accent) !important;
	border-color: var(--border) !important;
}

/* Time picker (hours / minutes / seconds columns) */
body.appbuilder-dark .w2ui-cal-time {
	background-color: var(--bg-panel) !important;
	color: var(--fg) !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column {
	background-color: var(--bg-panel) !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column:nth-child(even) {
	background-color: var(--bg-elev) !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column span {
	color: var(--fg) !important;
	border-color: transparent !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column span:hover {
	background-color: var(--bg-hover) !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column span:active {
	background-color: var(--bg-hover) !important;
	border-color: var(--accent) !important;
}
body.appbuilder-dark .w2ui-cal-time .w2ui-cal-column span.w2ui-blocked {
	color: var(--fg-muted) !important;
	opacity: 0.5 !important;
}

/* ==============================================================
 * w2ui form validation error tooltip (e.g. "Required field").
 * w2tooltip renders it with class "w2ui-light" on the body, and
 * assigns the overlay a name like "formname-fieldname-error".
 * We target via [name$="-error"] so only validation tooltips are
 * affected — not the many other tooltips that also use w2ui-light.
 * Styled to match ShowError() (w2utils.notify) which uses
 * rgba(255,0,0,0.8).  The :before/:after arrow inherits the body's
 * background + border so it stays in sync automatically.
 * Applies in both light and dark mode — the pale yellow tooltip
 * in light mode is low-contrast and the dark-mode override turns
 * it near-black, neither of which communicates "error" clearly. */
html .w2ui-overlay[name$="-error"] .w2ui-overlay-body,
html .w2ui-overlay[name$="-error"] .w2ui-overlay-body.w2ui-light,
html body.appbuilder-dark .w2ui-overlay[name$="-error"] .w2ui-overlay-body,
html body.appbuilder-dark .w2ui-overlay[name$="-error"] .w2ui-overlay-body.w2ui-light {
	/* Softer muted red — same intent (communicate "error") without
	   the saturated alarm-bell vibe of the original 0.85-alpha pure
	   red. Pairs with the toned-down field background below. */
	background-color: rgba(190, 95, 95, 0.85) !important;
	color: #ffffff !important;
	border-color: rgba(150, 60, 60, 0.85) !important;
	text-shadow: none !important;
	font-weight: 500 !important;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18) !important;
}

/* The outer .w2ui-overlay wrapper gets its own dark bg + box-shadow
   from the catch-all dark-mode overlay rule in w2ui.css — that's the
   dark halo you see under the red tooltip.  Neutralize it here for
   validation overlays only; the body provides all the visual. */
html .w2ui-overlay[name$="-error"],
html body.appbuilder-dark .w2ui-overlay[name$="-error"] {
	background-color: transparent !important;
	box-shadow: none !important;
	border: 0 !important;
}

/* Error field background — dark mode.
   .w2ui-error is applied by w2ui to the input itself when validation
   fails.  The base rule in w2ui.css paints a pale-peach bg / pink
   border (good contrast on a white form).  In dark mode there was no
   override so the field looked unchanged.  Give it a deep red tint
   and a strong red border so it reads as "error" without blinding.
   The :not() chain mirrors the catch-all dark-input rule higher up
   in this file (0,7,3 specificity) so our rule reaches (0,8,3) and
   actually beats it — otherwise the var(--bg-input) wins and the
   field stays neutral dark. */
html body.appbuilder-dark input.w2ui-error:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]),
html body.appbuilder-dark input.w2ui-input.w2ui-error:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):not([type=range]),
html body.appbuilder-dark textarea.w2ui-error,
html body.appbuilder-dark textarea.w2ui-input.w2ui-error,
html body.appbuilder-dark select.w2ui-error {
	/* Subtle red tint that still reads as "error" without the
	   blood-red flash of the previous rgba(200,0,0,0.35). */
	background-color: rgba(190, 95, 95, 0.18) !important;
	border-color: rgba(190, 95, 95, 0.7) !important;
	color: var(--fg) !important;
}

/* ==============================================================
 * Tab / toolbar scroll arrows (`.w2ui-scroll-left` / `.w2ui-scroll-right`).
 * The base rules in w2ui.css hard-code a near-white `#F7F7F7`
 * background + a dark PNG arrow glyph designed for a light theme.
 * On dark mode the light box stands out as a pale gray rectangle.
 * Replace background color and swap the embedded PNG for an inline
 * SVG chevron filled in `--fg` so the arrow reads properly on dark. */
body.appbuilder-dark .w2ui-scroll-left,
body.appbuilder-dark .w2ui-scroll-right {
	background-color: var(--bg-panel) !important;
	box-shadow: 0 0 7px rgba(0, 0, 0, 0.5) !important;
}
body.appbuilder-dark .w2ui-scroll-left {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 15 12'><path fill='%23e6e6e6' d='M10 0 L4 6 L10 12 Z'/></svg>") !important;
}
body.appbuilder-dark .w2ui-scroll-right {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 15 12'><path fill='%23e6e6e6' d='M5 0 L11 6 L5 12 Z'/></svg>") !important;
}
body.appbuilder-dark .w2ui-scroll-left:hover,
body.appbuilder-dark .w2ui-scroll-right:hover {
	background-color: var(--bg-hover) !important;
}

/* ==============================================================
 * w2ui inline panel message / prompt (`.w2ui-message`) — used by
 * grids to surface errors (e.g. "400:" on a failed load) and by
 * w2layout / w2form for inline confirmations.  The base rules in
 * w2ui.css hard-code a white bg / light-grey border / white button
 * bar, which looks completely out of place over a dark layout.
 * Match the theme's panel + border + footer colors. */
body.appbuilder-dark .w2ui-message {
	background-color: var(--bg-panel) !important;
	border-color: var(--border-strong) !important;
	color: var(--fg) !important;
	box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5) !important;
}
body.appbuilder-dark .w2ui-message .w2ui-msg-text,
body.appbuilder-dark .w2ui-message .w2ui-message-body,
body.appbuilder-dark .w2ui-message .w2ui-message-body .w2ui-centered {
	color: var(--fg) !important;
}
body.appbuilder-dark .w2ui-message .w2ui-message-buttons {
	background-color: var(--bg-alt) !important;
	border-top: 1px solid var(--border) !important;
}
body.appbuilder-dark .w2ui-message .w2ui-prompt input,
body.appbuilder-dark .w2ui-message .w2ui-prompt textarea,
body.appbuilder-dark .w2ui-message .w2ui-prompt > label {
	color: var(--fg) !important;
	background-color: var(--bg-input) !important;
	border-color: var(--border-strong) !important;
}

/* ==========================================================================
   Database console (Builder_DatabaseConsole) + HomeTables cards background
   ========================================================================== */

/* Tree node layout (icon/dot/label/suffix inside w2sidebar nodes) */
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node .w2ui-node-text {
	display: block !important;
	overflow: hidden !important;
	padding-right: 20px !important;
	text-overflow: ellipsis;
}
#dbcons-root .dbcons-node {
	display: flex !important;
	align-items: center;
	width: 100%;
	min-width: 0;
	box-sizing: border-box;
}
#dbcons-root .dbcons-node .dbcons-icon {
	flex: 0 0 auto;
	display: inline-block;
	width: 14px;
	text-align: center;
	margin-right: 6px;
	color: #bbb;
	font-size: 12px;
}
#dbcons-root .dbcons-node .dbcons-dot {
	flex: 0 0 auto;
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	margin-right: 6px;
}
#dbcons-root .dbcons-node .dbcons-label {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
#dbcons-root .dbcons-node .dbcons-suffix {
	color: #808080;
	font-size: 11px;
}

/* Let bg-page/bg-block classes show through w2 panels */
#dbcons-root .w2ui-panel-content {
	font-family: OpenSans, sans-serif;
	font-size: 13px;
	background-color: transparent !important;
}
#dbcons-root .bg-block .w2ui-sidebar,
#dbcons-root .bg-block .w2ui-sidebar .w2ui-sidebar-body {
	background-color: transparent !important;
}

/* Sidebar hover / selection styling (mirrors builder-leftbar-home) */
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node:hover {
	background-color: rgba(0,0,0,0.06) !important;
}
body.appbuilder-dark #dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node:hover {
	background-color: rgba(255,255,255,0.08) !important;
}
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected,
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected:hover {
	background-color: #ffffff !important;
	color: #000 !important;
}
body.appbuilder-dark #dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected,
body.appbuilder-dark #dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected:hover {
	background-color: var(--bg-panel) !important;
	color: var(--fg-strong) !important;
}
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected:before,
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-selected:after {
	display: none !important;
	border: 0 !important;
	content: none !important;
}
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node.w2ui-selected,
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node.w2ui-selected:hover,
#dbcons-root .w2ui-sidebar .w2ui-sidebar-body .w2ui-node.w2ui-selected:focus {
	border-color: transparent !important;
	outline: 0 !important;
	box-shadow: none !important;
}

/* Separator between left and main (matches OpenEntry_HTML) */
body.appbuilder-dark #dbcons-root .w2ui-panel.w2ui-panel-left {
	border-right-color: #3a3a3a !important;
}

/* Hide tab bar when no query is open */
#dbcons-root.dbcons-no-queries .w2ui-tabs { display: none !important; }
#dbcons-root.dbcons-no-queries .w2ui-panel-content { top: 0 !important; }

/* Query editor (textarea) */
#dbcons-root .dbcons-query-area { background-color: #FAF8F5; }
body.appbuilder-dark #dbcons-root .dbcons-query-area {
	background-color: #1a1a1a;
	color: #e0e0e0;
}
#dbcons-root textarea.dbcons-editor {
	display: block;
	width: 100%;
	height: 100%;
	box-sizing: border-box;
	border: 0 !important;
	outline: 0 !important;
	box-shadow: none !important;
	resize: none;
	padding: 10px;
	font-family: Consolas, Monaco, 'Courier New', monospace;
	font-size: 13px;
	line-height: 1.5;
	white-space: pre;
	overflow: auto;
	background-color: #FAF8F5 !important;
	color: #27251E;
}
#dbcons-root textarea.dbcons-editor:focus,
#dbcons-root textarea.dbcons-editor:focus-visible {
	border: 0 !important;
	outline: 0 !important;
	box-shadow: none !important;
	background-color: #FAF8F5 !important;
}
#dbcons-root textarea.dbcons-editor::placeholder {
	color: #888 !important;
	-webkit-text-fill-color: #888 !important;
	opacity: 1 !important;
	font-style: italic;
}
body.appbuilder-dark #dbcons-root textarea.dbcons-editor,
body.appbuilder-dark #dbcons-root textarea.dbcons-editor:focus {
	background-color: #1a1a1a !important;
	color: #e0e0e0;
}
body.appbuilder-dark #dbcons-root textarea.dbcons-editor::placeholder {
	color: #888 !important;
	-webkit-text-fill-color: #888 !important;
	opacity: 1 !important;
	font-style: italic;
}

/* HomeTables cards background (inside the bg-page/bg-block wrap) */
.home-tables-cards .w2ui-panel-content {
	background-color: #FAF8F5 !important;
}
body.appbuilder-dark .home-tables-cards .w2ui-panel-content {
	background-color: #1a1a1a !important;
}

/* Query prompt bar (text-to-SQL).
   The chrome (background + bottom border + fixed height) is only
   meaningful in the DB console where the bar sits above the SQL
   editor; in other surfaces (e.g. the dashboard widget editor)
   the bar floats inside a normal form and the chrome shows up as
   an unwanted black/grey strip. So we scope the chrome to the
   console root and keep .dbcons-prompt-bar itself a layout-only
   flex container that works everywhere. */
/* Prompt bar — joined selectors so `.nlpe-*` (Builder_NlPromptExamples)
   and legacy `.dbcons-*` (still-unmigrated Text2Sql / Text2Chart /
   OntologyNlToCypher) stay in lockstep. New callers should use nlpe;
   the dbcons aliases can be dropped once every host has migrated. */
.dbcons-prompt-bar,
.nlpe-prompt-bar {
	display: flex;
	align-items: center;
	gap: 8px;
	box-sizing: border-box;
}
#dbcons-root .dbcons-prompt-bar,
.nlpe-prompt-bar {
	padding: 6px 10px;
	height: 44px;
	background-color: #FAF8F5;
	border-bottom: 1px solid #e8e6e2;
}
body.appbuilder-dark #dbcons-root .dbcons-prompt-bar,
body.appbuilder-dark .nlpe-prompt-bar {
	background-color: #1a1a1a;
	border-bottom-color: #3a3a3a;
}
.dbcons-prompt-field,
.nlpe-prompt-field {
	flex: 1 1 auto;
	position: relative;
	min-width: 0;
}
.dbcons-prompt-input,
.nlpe-prompt-input {
	width: 100%;
	box-sizing: border-box;
	padding: 6px 36px 6px 32px;
	font: 13px OpenSans, sans-serif;
	border: 1px solid #d8d6d2;
	border-radius: 4px;
	background: #ffffff;
	color: #27251E;
	outline: none;
}
.dbcons-prompt-input:focus,
.nlpe-prompt-input:focus { border-color: #2F9EEE; box-shadow: 0 0 0 1px #2F9EEE inset; }
body.appbuilder-dark .dbcons-prompt-input,
body.appbuilder-dark .nlpe-prompt-input { background: #1a1a1a; border-color: #3a3a3a; color: #e6e6e6; }
.dbcons-prompt-icon,
.nlpe-prompt-icon {
	position: absolute;
	left: 12px;
	top: calc(50% - 7px);
	height: 14px;
	line-height: 14px;
	color: #2F9EEE;
	font-size: 14px;
	pointer-events: none;
}
.dbcons-prompt-vote,
.nlpe-prompt-vote {
	position: absolute;
	right: 12px;
	top: calc(50% - 7px);
	height: 14px;
	line-height: 14px;
	display: inline-flex;
	gap: 10px;
	font-size: 14px;
	z-index: 2;
}
.dbcons-prompt-vote i,
.nlpe-prompt-vote i {
	cursor: pointer;
	pointer-events: auto;
	color: #888;
	transition: color 120ms ease;
}
.dbcons-prompt-up:hover, .nlpe-prompt-up:hover     { color: #2e7d32; }
.dbcons-prompt-down:hover, .nlpe-prompt-down:hover { color: #c0392b; }
.dbcons-prompt-up.dbcons-prompt-vote-on, .nlpe-prompt-up.nlpe-prompt-vote-on     { color: #2e7d32; }
.dbcons-prompt-down.dbcons-prompt-vote-on, .nlpe-prompt-down.nlpe-prompt-vote-on { color: #c0392b; }
body.appbuilder-dark .dbcons-prompt-vote i, body.appbuilder-dark .nlpe-prompt-vote i { color: #aaa; }
body.appbuilder-dark .dbcons-prompt-up:hover, body.appbuilder-dark .nlpe-prompt-up:hover     { color: #81C784; }
body.appbuilder-dark .dbcons-prompt-down:hover, body.appbuilder-dark .nlpe-prompt-down:hover { color: #EF9A9A; }
body.appbuilder-dark .dbcons-prompt-up.dbcons-prompt-vote-on, body.appbuilder-dark .nlpe-prompt-up.nlpe-prompt-vote-on     { color: #81C784; }
body.appbuilder-dark .dbcons-prompt-down.dbcons-prompt-vote-on, body.appbuilder-dark .nlpe-prompt-down.nlpe-prompt-vote-on { color: #EF9A9A; }
/* Manage examples button — same button chrome across surfaces. */
.dbcons-manage-examples, .nlpe-manage-examples { flex: 0 0 auto; }

/* Correction dialog (👎 modal) — scoped class so we can style
   labels, read-only field, and dark-mode treatment without
   affecting other w2popup instances. */
.dbcons-fix-dialog,
.nlpe-fix-dialog {
	display: flex;
	flex-direction: column;
	gap: 12px;
	height: 100%;
	font-family: OpenSans, sans-serif;
	font-size: 13px;
}
.dbcons-fix-dialog .dbcons-fix-section,
.nlpe-fix-dialog   .nlpe-fix-section   { display: flex; flex-direction: column; gap: 4px; }
.dbcons-fix-dialog .dbcons-fix-grow,
.nlpe-fix-dialog   .nlpe-fix-grow      { flex: 1 1 auto; min-height: 0; }
.dbcons-fix-dialog .dbcons-fix-label,
.nlpe-fix-dialog   .nlpe-fix-label {
	font-weight: 400;
	font-size: 13px;
	color: #27251E;
}
.dbcons-fix-dialog .dbcons-fix-readonly,
.nlpe-fix-dialog   .nlpe-fix-readonly {
	padding: 6px 10px;
	background: #f1f3f5;
	border: 1px solid #d8d6d2;
	border-radius: 4px;
	color: #27251E;
}
.dbcons-fix-dialog .dbcons-fix-text,
.nlpe-fix-dialog   .nlpe-fix-text {
	width: 100%;
	min-height: 60px;
	padding: 6px 8px;
	border: 1px solid #d8d6d2;
	border-radius: 4px;
	background: #fff;
	color: #27251E;
	font-family: OpenSans, sans-serif;
	font-size: 13px;
	box-sizing: border-box;
	resize: vertical;
}
.dbcons-fix-dialog .dbcons-fix-mono,
.nlpe-fix-dialog   .nlpe-fix-mono {
	font-family: Menlo, Consolas, monospace;
	font-size: 12px;
	min-height: 90px;
}
.dbcons-fix-dialog .dbcons-fix-grow-area,
.nlpe-fix-dialog   .nlpe-fix-grow-area { flex: 1 1 auto; }

body.appbuilder-dark .dbcons-fix-dialog .dbcons-fix-label,
body.appbuilder-dark .nlpe-fix-dialog   .nlpe-fix-label    { color: #e6e6e6; }
body.appbuilder-dark .dbcons-fix-dialog .dbcons-fix-readonly,
body.appbuilder-dark .nlpe-fix-dialog   .nlpe-fix-readonly {
	background: #242424;
	border-color: #3a3a3a;
	color: #e6e6e6;
}
body.appbuilder-dark .dbcons-fix-dialog .dbcons-fix-text,
body.appbuilder-dark .nlpe-fix-dialog   .nlpe-fix-text {
	background: #1a1a1a;
	border-color: #3a3a3a;
	color: #e6e6e6;
}

/* Quill rich-text editor inside the widget editor — dark mode.
   Quill's SVG icons inherit `currentColor`, so setting `color`
   on the toolbar paints them. The container bg is brought in
   line with the form's other text inputs (#2b2b2b panel + dark
   border) so the editor doesn't read as a blinding white block. */
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow,
body.appbuilder-dark .dashboard-edit-form .ql-container.ql-snow {
	border-color: #3a3a3a !important;
	background-color: #2b2b2b;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow {
	color: #e0e0e0;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow .ql-stroke {
	stroke: #e0e0e0 !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow .ql-fill {
	fill: #e0e0e0 !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow .ql-picker {
	color: #e0e0e0 !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow button:hover .ql-stroke,
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow button.ql-active .ql-stroke {
	stroke: #4a90e2 !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow button:hover .ql-fill,
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow button.ql-active .ql-fill {
	fill: #4a90e2 !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-toolbar.ql-snow .ql-picker-options {
	background-color: #2b2b2b !important;
	border-color: #3a3a3a !important;
}
body.appbuilder-dark .dashboard-edit-form .ql-editor {
	color: #e6e6e6;
}
body.appbuilder-dark .dashboard-edit-form .ql-editor.ql-blank::before {
	color: #888 !important;
}

/* Inline help text under the widget-editor pickers. Small,
   muted, slightly indented so it reads as a hint rather than
   a label. */
.dashboard-edit-form .ef-hint {
	margin-top: 4px;
	font-size: 11px;
	color: #888;
	line-height: 1.35;
}
body.appbuilder-dark .dashboard-edit-form .ef-hint {
	color: #9e9e9e;
}

/* Form fields inside the dashboard widget editor dialog. Match
   the .wf-pickbtn appearance (1px #d9d6d0 border, 4px radius,
   blue focus ring) so the Title input, SQL textarea, Prompt and
   Properties JSON read as one consistent styled set with the
   pick buttons next to them. */
.dashboard-edit-form input[type=text],
.dashboard-edit-form textarea {
	box-sizing: border-box;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	background-color: #ffffff;
	color: #27251e;
	font: 12px OpenSans, sans-serif;
}
.dashboard-edit-form textarea { font-family: Menlo, Consolas, monospace; }
.dashboard-edit-form input[type=text]:focus,
.dashboard-edit-form textarea:focus {
	outline: 2px solid #4a90e2 !important;
	outline-offset: -1px !important;
	border-color: #4a90e2;
}
body.appbuilder-dark .dashboard-edit-form input[type=text],
body.appbuilder-dark .dashboard-edit-form textarea {
	background-color: #2b2b2b;
	border-color: #3a3a3a;
	color: #e0e0e0;
}

/* Filter runtime popup — controls used inside the chip popup
   for picklist / refto filters. Scoped class names so both
   light and dark mode render correctly inside the w2popup
   (which doesn't inherit our usual #dbcons-root scope). */
.fp-checklist {
	max-height: 180px;
	overflow: auto;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	padding: 6px;
	background: #fff;
	color: #27251e;
}
.fp-results {
	position: absolute;
	left: 0;
	right: 0;
	top: 54px;
	max-height: 180px;
	overflow: auto;
	border: 1px solid #d9d6d0;
	border-radius: 4px;
	background: #fff;
	color: #27251e;
	z-index: 10;
}
.fp-result {
	padding: 6px 8px;
	cursor: pointer;
	border-bottom: 1px solid #f0eee9;
}
.fp-result:last-child { border-bottom: none; }
.fp-result:hover      { background: #f4f1ec; }
.fp-chip {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 2px 6px;
	border-radius: 10px;
	background: #eef3fa;
	color: #27251e;
	font-size: 11px;
}
.fp-chip i { cursor: pointer; color: #888; }

body.appbuilder-dark .fp-checklist,
body.appbuilder-dark .fp-results {
	background: #222222;
	border-color: #3a3a3a;
	color: #e6e6e6;
}
body.appbuilder-dark .fp-result          { border-bottom-color: #2c2c2c; }
body.appbuilder-dark .fp-result:hover    { background: #2b2b2b; }
body.appbuilder-dark .fp-chip            { background: #243a4d; color: #e6e6e6; }
body.appbuilder-dark .fp-chip i          { color: #aaa; }


/* Pin button on the dashboard editor toolbar — blue tint when
   the dashboard is pinned to the home page. Targets descendants
   too because w2ui sticks the icon inside nested wrappers. */
.dashboard-pin-on,
.dashboard-pin-on *,
.dashboard-pin-on .fa {
	color: #2F9EEE !important;
}

/* Primary blue Save button for w2popup actions. */
.w2ui-popup .w2ui-btn-blue {
	background: #2F9EEE;
	border-color: #2F9EEE;
	color: #fff;
}
.w2ui-popup .w2ui-btn-blue:hover { background: #1f8cd8; border-color: #1f8cd8; }
.dbcons-prompt-input {
	width: 100%;
	box-sizing: border-box;
	height: 30px;
	padding: 0 60px 0 34px;
	border: 2px solid #d8d6d2;
	border-radius: 16px;
	outline: none;
	font-family: OpenSans, sans-serif;
	font-size: 13px;
	background-color: #fff;
	color: #27251E;
}
.dbcons-prompt-input:focus {
	border-color: #2F9EEE;
}
body.appbuilder-dark .dbcons-prompt-input {
	background-color: #2b2b2b;
	border-color: #3a3a3a;
	color: #e0e0e0;
}
body.appbuilder-dark .dbcons-prompt-input:focus {
	border-color: #4A90E2;
}
.dbcons-prompt-input::placeholder {
	color: #999 !important;
	-webkit-text-fill-color: #999 !important;
	opacity: 1 !important;
	font-style: italic;
}
body.appbuilder-dark .dbcons-prompt-input::placeholder {
	color: #888 !important;
	-webkit-text-fill-color: #888 !important;
}
.dbcons-prompt-send {
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	padding: 0;
	border-radius: 50%;
	background-color: #2F9EEE;
	color: #fff;
	border: 0;
	cursor: pointer;
}
.dbcons-prompt-send:hover:not([disabled]) {
	background-color: #2184d0;
}
.dbcons-prompt-send[disabled] {
	opacity: 0.6;
	cursor: default;
}

/* Scroll viewport: scrollbars sit flush with its borders. */
.builder-dashboard-components {
	width: 100%;
	height: 100%;
	overflow: auto;
	padding: 0;
	font-family: OpenSans;
}

/* Chat-inline charts: strip the dashboard chrome so the chart canvas
   uses every pixel of the user-resizable host and the native resize
   handle sits flush at the bottom-right corner of the chart. The
   parent host is `.builder-thread-chart-host` (set by Builder_Thread.
   _RenderChartEnvelope). Without these resets the GridStack canvas
   inherits 12 px of padding and 36 px of header chrome, leaving an
   ugly empty band between the chart bottom and the thumbs-up bar. */
.builder-thread-chart-host .builder-dashboard-surface {
	padding: 0;
	min-height: 0;
	width: 100% !important;
	height: 100% !important;
}
.builder-thread-chart-host .builder-dashboard-components {
	overflow: hidden;   /* host already provides resize + clip */
}
/* The single inline widget fills the resizable host (anchoring is bypassed
   for these single-widget embeds — CSS forces a full-bleed fill). */
.builder-thread-chart-host .builder-dashboard-widget {
	position: absolute !important;
	inset: 0 !important;
	left: 0 !important;
	top: 0 !important;
	width: 100% !important;
	height: 100% !important;
}

/* Absolute-anchor canvas. The surface holds every widget as an absolutely-
   positioned box (left/top/width/height written by Builder_Dashboard.
   _ApplyLayout from each widget's design-space rect + anchor flags). The
   surface grows past the viewport when a keep-size widget extends beyond it,
   so the .builder-dashboard-components scroller provides scrolling. */
.builder-dashboard-surface {
	position: relative;
	width: 100%;
	min-height: 100%;
	box-sizing: border-box;
}
.builder-dashboard-widget {
	position: absolute;
	box-sizing: border-box;
}
.builder-dashboard-widget.is-editing {
	z-index: 10;
}

/* Resize handles (edit mode) — east / south / south-east, matching the old
   GridStack affordances. Positioned on the widget wrapper; the card inside
   already fills it (position:absolute; inset:0). */
.builder-dashboard-rz {
	position: absolute;
	z-index: 6;
	opacity: 0;
	transition: opacity 0.15s ease;
}
.builder-dashboard-widget:hover .builder-dashboard-rz { opacity: 1; }
/* Eight resize zones — four edges + four corners. Insets kept at 0 (not negative)
   so a handle never pokes past the widget box (an overhang would add scroll
   overflow and toggle a scrollbar — the resize blink). Corners sit above edges. */
.builder-dashboard-rz.rz-n  { top: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }
.builder-dashboard-rz.rz-s  { bottom: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }
.builder-dashboard-rz.rz-e  { right: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }
.builder-dashboard-rz.rz-w  { left: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }
.builder-dashboard-rz.rz-ne { top: 0; right: 0; width: 14px; height: 14px; cursor: nesw-resize; z-index: 7; }
.builder-dashboard-rz.rz-nw { top: 0; left: 0;  width: 14px; height: 14px; cursor: nwse-resize; z-index: 7; }
.builder-dashboard-rz.rz-se { bottom: 0; right: 0; width: 14px; height: 14px; cursor: nwse-resize; z-index: 7; }
.builder-dashboard-rz.rz-sw { bottom: 0; left: 0;  width: 14px; height: 14px; cursor: nesw-resize; z-index: 7; }
/* Visible corner marks on all four corners (shown on widget hover). */
.builder-dashboard-rz.rz-ne::after,
.builder-dashboard-rz.rz-nw::after,
.builder-dashboard-rz.rz-se::after,
.builder-dashboard-rz.rz-sw::after {
	content: '';
	position: absolute;
	width: 7px;
	height: 7px;
}
.builder-dashboard-rz.rz-nw::after { top: 3px; left: 3px;  border-left: 2px solid rgba(120,120,130,0.7); border-top: 2px solid rgba(120,120,130,0.7); }
.builder-dashboard-rz.rz-ne::after { top: 3px; right: 3px; border-right: 2px solid rgba(120,120,130,0.7); border-top: 2px solid rgba(120,120,130,0.7); }
.builder-dashboard-rz.rz-sw::after { bottom: 3px; left: 3px;  border-left: 2px solid rgba(120,120,130,0.7); border-bottom: 2px solid rgba(120,120,130,0.7); }
.builder-dashboard-rz.rz-se::after { bottom: 3px; right: 3px; border-right: 2px solid rgba(120,120,130,0.7); border-bottom: 2px solid rgba(120,120,130,0.7); }

.builder-dashboard-component {
	position: absolute;
	inset: 0;
	background: #fff;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	box-shadow: 0 1px 2px rgba(0,0,0,0.03);
	transition: box-shadow 0.15s ease;
}

.builder-dashboard-widget.is-editing .builder-dashboard-component {
	box-shadow: 0 6px 20px rgba(0,0,0,0.18);
	opacity: 0.95;
	user-select: none;
}

.builder-dashboard-component-header {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 8px 10px;
	border-bottom: 1px solid #f0eee9;
	min-height: 18px;
}

/* Headerless widget (no title): the header no longer reserves a row — it floats
   over the content top-right so the body fills the whole card. Handles get a
   readable backing on hover; when idle it's click-through so it doesn't block
   the content beneath. */
.builder-dashboard-component.is-headerless > .builder-dashboard-component-header {
	position: absolute;
	top: 4px;
	right: 4px;
	left: auto;
	width: auto;
	z-index: 5;
	min-height: 0;
	padding: 2px 4px;
	gap: 2px;
	border-bottom: none;
	border-radius: 6px;
	background: transparent;
	pointer-events: none;
}
.builder-dashboard-component.is-headerless > .builder-dashboard-component-header > .builder-dashboard-component-title {
	display: none;
}
.builder-dashboard-component.is-headerless:hover > .builder-dashboard-component-header {
	pointer-events: auto;
	background: rgba(255,255,255,0.9);
	box-shadow: 0 1px 3px rgba(0,0,0,0.14);
}
body.appbuilder-dark .builder-dashboard-component.is-headerless:hover > .builder-dashboard-component-header {
	background: rgba(28,28,34,0.9);
}

.builder-dashboard-component-title {
	font-size: 13px;
	font-weight: 400;
	color: #27251E;
	flex: 1 1 auto;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.builder-dashboard-drag-handle,
.builder-dashboard-edit-handle,
.builder-dashboard-delete-handle {
	flex: 0 0 auto;
	color: rgb(160, 160, 170);
	padding: 2px 4px;
	border-radius: 3px;
	font-size: 12px;
	user-select: none;
	opacity: 0;
	transition: opacity 0.15s ease;
}
.builder-dashboard-drag-handle { cursor: grab; }
.builder-dashboard-drag-handle:active { cursor: grabbing; }
.builder-dashboard-edit-handle,
.builder-dashboard-delete-handle { cursor: pointer; }
.builder-dashboard-component:hover .builder-dashboard-drag-handle,
.builder-dashboard-component:hover .builder-dashboard-edit-handle,
.builder-dashboard-component:hover .builder-dashboard-delete-handle { opacity: 1; }
.builder-dashboard-drag-handle:hover,
.builder-dashboard-edit-handle:hover {
	background: #f2f0ec;
	color: #27251E;
}
body.appbuilder-dark .builder-dashboard-drag-handle:hover,
body.appbuilder-dark .builder-dashboard-edit-handle:hover {
	background: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}

/* Anchor handle — mirrors the edit/delete/drag handles; opens the anchor
   picker popover. */
.builder-dashboard-anchor-handle {
	flex: 0 0 auto;
	color: rgb(160, 160, 170);
	padding: 2px 4px;
	border-radius: 3px;
	font-size: 12px;
	user-select: none;
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.15s ease;
}
.builder-dashboard-component:hover .builder-dashboard-anchor-handle { opacity: 1; }
.builder-dashboard-anchor-handle:hover { background: #f2f0ec; color: #27251E; }
body.appbuilder-dark .builder-dashboard-anchor-handle:hover { background: var(--bg-hover) !important; color: var(--fg-strong) !important; }

/* Anchor picker popover — a small WinForms-style anchor editor: four edge
   bars you toggle on/off, plus presets. */
.builder-dashboard-anchorpop {
	position: fixed;
	z-index: 100000;
	background: #fff;
	border: 1px solid #e2e2e2;
	border-radius: 8px;
	box-shadow: 0 8px 28px rgba(0,0,0,0.18);
	padding: 10px;
	width: 168px;
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	color: #27251E;
	user-select: none;
}
.builder-dashboard-anchorpop .ap-title { font-weight: 600; margin-bottom: 8px; }
.builder-dashboard-anchorpop .ap-box {
	position: relative;
	width: 96px;
	height: 72px;
	margin: 0 auto 10px auto;
	border: 1px dashed #cfccc5;
	border-radius: 4px;
	background: #faf9f7;
}
.builder-dashboard-anchorpop .ap-center {
	position: absolute;
	left: 50%; top: 50%;
	width: 34px; height: 26px;
	transform: translate(-50%, -50%);
	background: #d9d6cf;
	border-radius: 3px;
}
.builder-dashboard-anchorpop .ap-edge {
	position: absolute;
	background: #d9d6cf;
	border: none;
	padding: 0;
	cursor: pointer;
	border-radius: 2px;
}
.builder-dashboard-anchorpop .ap-edge.on { background: #2f6fed; }
.builder-dashboard-anchorpop .ap-top    { left: 50%; top: 4px;    transform: translateX(-50%); width: 6px; height: 22px; }
.builder-dashboard-anchorpop .ap-bottom { left: 50%; bottom: 4px; transform: translateX(-50%); width: 6px; height: 22px; }
.builder-dashboard-anchorpop .ap-left   { top: 50%; left: 4px;    transform: translateY(-50%); height: 6px; width: 22px; }
.builder-dashboard-anchorpop .ap-right  { top: 50%; right: 4px;   transform: translateY(-50%); height: 6px; width: 22px; }
.builder-dashboard-anchorpop .ap-presets { display: flex; flex-direction: column; gap: 4px; }
.builder-dashboard-anchorpop .ap-presets button {
	font-family: OpenSans, sans-serif;
	font-size: 12px;
	text-align: left;
	padding: 4px 8px;
	border: 1px solid #e2e2e2;
	border-radius: 4px;
	background: #fff;
	color: #27251E;
	cursor: pointer;
}
.builder-dashboard-anchorpop .ap-presets button:hover { background: #f2f0ec; }
/* Dark mode */
body.appbuilder-dark .builder-dashboard-anchorpop,
.builder-dashboard-anchorpop.appbuilder-dark {
	background: var(--bg-elevated, #24242b);
	border-color: var(--border, #3a3a44);
	color: var(--fg, #e6e6ea);
}
body.appbuilder-dark .builder-dashboard-anchorpop .ap-box,
.builder-dashboard-anchorpop.appbuilder-dark .ap-box { background: rgba(255,255,255,0.04); border-color: #4a4a55; }
body.appbuilder-dark .builder-dashboard-anchorpop .ap-center,
body.appbuilder-dark .builder-dashboard-anchorpop .ap-edge,
.builder-dashboard-anchorpop.appbuilder-dark .ap-center,
.builder-dashboard-anchorpop.appbuilder-dark .ap-edge { background: #4a4a55; }
body.appbuilder-dark .builder-dashboard-anchorpop .ap-edge.on,
.builder-dashboard-anchorpop.appbuilder-dark .ap-edge.on { background: #4f86ff; }
body.appbuilder-dark .builder-dashboard-anchorpop .ap-presets button,
.builder-dashboard-anchorpop.appbuilder-dark .ap-presets button { background: var(--bg-elevated, #2b2b33); border-color: #3a3a44; color: var(--fg, #e6e6ea); }
body.appbuilder-dark .builder-dashboard-anchorpop .ap-presets button:hover,
.builder-dashboard-anchorpop.appbuilder-dark .ap-presets button:hover { background: var(--bg-hover, #34343d) !important; }

/* Warning badge for widgets whose SQL doesn't match the expected
   shape (e.g. pie with 3 columns, chart with non-numeric series).
   Always visible (unlike edit/delete which appear on hover) so the
   designer notices a mismatch even at a glance. */
.builder-dashboard-warn-handle {
	display: inline-block;
	color: #d49100;
	margin-left: 4px;
	padding: 0 3px;
	border-radius: 3px;
	font-size: 12px;
	cursor: help;
	user-select: none;
}
.builder-dashboard-warn-handle:hover { background: #fff3cd; }
body.appbuilder-dark .builder-dashboard-warn-handle       { color: #ffb84d; }
body.appbuilder-dark .builder-dashboard-warn-handle:hover { background: rgba(255,184,77,0.18) !important; }

.builder-dashboard-component-body {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	padding: 10px 12px;
	font-size: 13px;
	color: #27251E;
	min-height: 0;
}

.builder-dashboard-component-body > .builder-dashboard-chart-host {
	flex: 1 1 auto;
}

.builder-dashboard-loading,
.builder-dashboard-error {
	font-size: 12px;
	color: rgb(115, 116, 133);
}

/* KPI */
.builder-dashboard-kpi {
	display: flex;
	flex-direction: column;
	justify-content: center;
	height: 100%;
	position: relative;
}
.builder-dashboard-kpi .kpi-icon {
	position: absolute;
	top: 0;
	right: 0;
	font-size: 20px;
	color: rgb(180, 180, 190);
}
.builder-dashboard-kpi .kpi-value,
.builder-dashboard-progress .kpi-value {
	font-size: 26px;
	font-weight: 700;
	line-height: 1.1;
	color: #27251E;
}
.builder-dashboard-kpi .kpi-delta {
	font-size: 12px;
	margin-top: 4px;
}
.builder-dashboard-kpi .kpi-delta.is-good { color: #2ca02c; }
.builder-dashboard-kpi .kpi-delta.is-bad  { color: #d62728; }
.builder-dashboard-kpi .kpi-delta em { font-style: normal; opacity: 0.8; }
.kpi-target {
	font-size: 11px;
	color: rgb(115, 116, 133);
	margin-top: 4px;
}

/* Progress */
.builder-dashboard-progress {
	display: flex;
	flex-direction: column;
	justify-content: center;
	height: 100%;
}
.builder-dashboard-progress.is-gauge {
	align-items: center;
	justify-content: center;
}
.builder-dashboard-progress .progress-bar {
	margin-top: 6px;
	background: #f0eee9;
	border-radius: 4px;
	height: 10px;
	overflow: hidden;
}
.builder-dashboard-progress .progress-bar > div {
	height: 100%;
	background: #1f77b4;
	transition: width 0.3s ease;
}

/* Charts */
.builder-dashboard-chart-host {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	min-height: 0;
	min-width: 0;
	overflow: hidden;
}
.builder-dashboard-chart-host.is-gauge {
	align-items: center;
	justify-content: center;
}
/* Trading-chart widget: the advanced candlestick renderer fills this host. */
.tradingchart-host { width:100%; height:100%; min-height:0; min-width:0; overflow:hidden; }
.builder-dashboard-tradingchart-empty {
	width:100%; height:100%; display:flex; flex-direction:column;
	align-items:center; justify-content:center; gap:8px; padding:16px;
	text-align:center; font-family:OpenSans; font-size:12px; color:#9aa0a8;
}
.builder-dashboard-tradingchart-empty > .fa { font-size:26px; color:#c8cdd3; }

/* Add-widget kind chooser — a vertical list of full-width clickable cards:
   icon on the left, title + description stacked on the right. Plain divs, NOT
   w2ui-btn (its fixed height / line-height pushed the second line out of the
   box). */
.dashboard-addkind { display:flex; flex-direction:column; gap:8px; padding:16px; font-family:OpenSans; }
.dashboard-addkind-btn {
	display:flex; align-items:center; gap:12px; width:100%; box-sizing:border-box;
	padding:10px 14px; text-align:left; cursor:pointer;
	border:1px solid #e2e2e2; border-radius:6px; background:#fff;
	transition:background-color 0.12s ease, border-color 0.12s ease;
}
.dashboard-addkind-btn:hover { background:#f6f9fd; border-color:#bcccdc; }
.dashboard-addkind-ic { flex:0 0 auto; width:24px; font-size:18px; text-align:center; color:#1a5c9c; }
.dashboard-addkind-text { display:flex; flex-direction:column; min-width:0; line-height:1.3; }
.dashboard-addkind-text > b { font-weight:600; font-size:12.5px; color:#333; }
.dashboard-addkind-text > small { color:#9aa0a8; font-size:10.5px; line-height:1.35; white-space:normal; margin-top:2px; }

/* Trading-chart config dialog rows (reuses .charts_wl_dlg base). */
.tradingcfg .tradingcfg-row,
.tradingcfg .tradingcfg-dates { display:flex; gap:12px; margin-bottom:14px; }
.tradingcfg .tradingcfg-row > div,
.tradingcfg .tradingcfg-dates > div { flex:1 1 0; min-width:0; }
/* Picklists (AppendPickButton) don't carry the 14px bottom margin the .w2ui-input
   fields do, so the following label used to sit flush against them. Give the
   button full width + the standalone picklist host the same spacing as inputs. */
.tradingcfg .wf-pickbtn { width:100%; box-sizing:border-box; }
.tradingcfg > span { display:block; margin-bottom:14px; }

/* Remaining NATIVE pickers (date, datetime-local, number spinner). The session
   TIME fields are not here — they are w2field('time') now, so their picker is a
   w2ui overlay that the app's own dark theme already styles, which is the whole
   argument for using the platform control instead of the browser's.
   For the ones that are still native: the highlight on the selected day is the
   browser's accent, defaulting to ITS blue rather than ours. Deliberately in
   BOTH themes — this is branding, not a theme signal (the theme signal is
   color-scheme, in the dark block below). */
.tradingcfg input[type=date],
.tradingcfg input[type=datetime-local],
.tradingcfg input[type=number] { accent-color:var(--accent, #269DF0); }

/* Generic wrapper for a conditionally-shown dialog field (label + control), used
   by Builder_Workflow.WireFieldVisibility. Wrapping breaks the direct-child
   `.tradingcfg > span` margin, so restore the field's spacing on the wrapper and
   zero the inner control's own margin to avoid doubling it up. */
.charts_wl_dlg .cfg-field { margin-bottom:14px; }
/* Explanatory line under a field whose NAME does not distinguish it from a
   neighbour — see the `hint` argument in the portfolio wizard. */
.charts_wl_dlg .cfg-hint {
	margin-top:4px; font-size:11px; line-height:1.45; color:#9aa0a8;
	font-family:'Open Sans', sans-serif;
}
body.appbuilder-dark .charts_wl_dlg .cfg-hint { color:#7a808c; }
.charts_wl_dlg .cfg-field > span { display:block; }
.charts_wl_dlg .cfg-field > input,
.charts_wl_dlg .cfg-field > span,
.charts_wl_dlg .cfg-field > textarea { margin-bottom:0; }

/* A "not configured / no data / error" panel that opens the widget's config. */
.builder-dashboard-config-link { cursor:pointer; }
.builder-dashboard-config-link:hover { background:rgba(26,92,156,0.06); }
body.appbuilder-dark .builder-dashboard-config-link:hover { background:rgba(142,194,238,0.08); }

/* Trading widget tables (quotes / screener) — they ARE the standard
   .builder-dashboard-table; the .trading-table modifier only adds the
   instrument cell (icon + clickable ticker) and up/down colour. Nothing else
   differs, so there is one table look across the dashboard. Row height grows
   only where the icon does. */
.trading-table td, .trading-table th { vertical-align:middle; }
.trading-table .tt-instr { display:inline-flex; align-items:center; gap:7px; }
.trading-table .tt-instr-ic { width:22px; height:22px; flex:0 0 auto; }
.trading-table .tt-instr-ic .screener_icon_img,
.trading-table .tt-instr-ic .screener_icon_mono { width:22px; height:22px; font-size:10px; }
.trading-table .tt-instr-ic .screener_icon_img { padding:3px; }
.trading-table .tt-instr-sym { font-weight:600; }
.trading-table .tt-name { max-width:200px; overflow:hidden; text-overflow:ellipsis; }
.trading-table .is-up   { color:#1a7f37; }
.trading-table .is-down { color:#b3261e; }
body.appbuilder-dark .trading-table .is-up   { color:#7ddb9a; }
body.appbuilder-dark .trading-table .is-down { color:#ef9a9a; }

/* ---- Ticker banner widget (tradingbanner) --------------------------------
   A horizontal strip of ticker cells with a sparkline, scrolled by rounded
   ‹ › buttons. Each cell's `color` carries the up/down direction, so the SVG
   sparkline (currentColor) and the change text inherit it, while name/last
   stay in the normal text colour. */
.ticker-banner {
	position: relative;
	height: 100%;
	display: flex;
	align-items: stretch;
	font-family: OpenSans, sans-serif;
}
.ticker-banner .tb-strip {
	display: flex;
	align-items: center;
	gap: 4px;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-behavior: smooth;
	flex: 1 1 auto;
	padding: 2px 34px;              /* room under the ‹ › buttons */
	scrollbar-width: none;          /* the arrows are the affordance */
}
.ticker-banner .tb-strip::-webkit-scrollbar { display: none; }

.ticker-banner .tb-cell {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 6px 14px;
	color: #6b7280;                 /* neutral fallback (flat / unknown) */
}
.ticker-banner .tb-cell + .tb-cell { border-left: 1px solid #ececec; }
.ticker-banner .tb-cell:first-child { padding-left: 4px; }
/* No overflow → hide the arrows and let the tickers hug the left edge. */
.ticker-banner.no-scroll .tb-nav   { display: none; }
.ticker-banner.no-scroll .tb-strip { padding-left: 6px; padding-right: 6px; }
/* Banner fills its widget body edge-to-edge (drop the default card padding). */
.builder-dashboard-component[componenttype='tradingbanner'] .builder-dashboard-component-body { padding: 0; }
/* …but transient states (Loading / empty / error) still need breathing room, or
   they glue to the top-left corner. The config panel centres itself, so leave it. */
.builder-dashboard-component[componenttype='tradingbanner'] .builder-dashboard-component-body > .builder-dashboard-loading,
.builder-dashboard-component[componenttype='tradingbanner'] .builder-dashboard-component-body > .builder-dashboard-error,
.builder-dashboard-component[componenttype='tradingbanner'] .builder-dashboard-component-body > .anylist_empty {
	padding: 12px 14px;
}
.ticker-banner .tb-cell.is-up   { color: #1a7f37; }
.ticker-banner .tb-cell.is-down { color: #b3261e; }

/* FIXED width, not content width. The company name is the only variable-length
   thing in a cell, and letting it size the cell made every ticker a different
   width — "Space Exploration Technologies Corp. Class A Common Stock" rendered
   several times wider than "NVIDIA Corporation", so the strip had no rhythm and
   a scroll step landed somewhere different every time. The name ellipsises and
   carries the full text in a tooltip instead.
   min-width:0 is what actually permits the ellipsis: a flex item defaults to
   min-width:auto, which refuses to shrink below its content. */
.ticker-banner .tb-info {
	display: flex; flex-direction: column; gap: 1px; white-space: nowrap;
	flex: 0 0 168px; width: 168px; min-width: 0;
}
/* The ellipsis lives on the BLOCK, not on the inline link inside it. */
.ticker-banner .tb-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ticker-banner .tb-name .gridurl { font-size: 12px; font-weight: 600; color: #2f6fed; cursor: pointer; }
.ticker-banner .tb-name .gridurl:hover { text-decoration: underline; }
.ticker-banner .tb-last { font-size: 15px; font-weight: 600; color: #27251E; }
.ticker-banner .tb-chg  { font-size: 11px; }   /* inherits the cell's direction colour */

.ticker-banner .tb-spark { width: 76px; height: 34px; flex: 0 0 auto; }
.ticker-banner .tb-svg   { width: 100%; height: 100%; display: block; }

/* Rounded scroll buttons, floated over the strip edges. */
.ticker-banner .tb-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 26px; height: 26px;
	border: 1px solid #e2e2e2;
	border-radius: 50%;
	background: #fff;
	color: #4b5563;
	cursor: pointer;
	display: flex; align-items: center; justify-content: center;
	box-shadow: 0 1px 3px rgba(0,0,0,0.12);
	z-index: 3;
	padding: 0;
	transition: opacity 0.15s ease, background 0.15s ease;
}
.ticker-banner .tb-nav:hover { background: #f2f0ec; color: #27251E; }
.ticker-banner .tb-prev { left: 4px; }
.ticker-banner .tb-next { right: 4px; }
.ticker-banner.at-start .tb-prev,
.ticker-banner.at-end   .tb-next { opacity: 0; pointer-events: none; }

/* Dark mode */
body.appbuilder-dark .ticker-banner .tb-cell         { color: #9aa0ac; }
body.appbuilder-dark .ticker-banner .tb-cell.is-up   { color: #7ddb9a; }
body.appbuilder-dark .ticker-banner .tb-cell.is-down { color: #ef9a9a; }
body.appbuilder-dark .ticker-banner .tb-cell + .tb-cell { border-left-color: var(--border, #3a3a44); }
body.appbuilder-dark .ticker-banner .tb-last { color: var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .ticker-banner .tb-name .gridurl { color: #6ea8ff; }
body.appbuilder-dark .ticker-banner .tb-nav {
	background: var(--bg-elevated, #2b2b33);
	border-color: var(--border, #3a3a44);
	color: var(--fg, #cfd2da);
}
body.appbuilder-dark .ticker-banner .tb-nav:hover { background: var(--bg-hover, #34343d); color: var(--fg-strong, #fff); }

/* ---- News widget (tradingnews) -------------------------------------------
   A vertical list of headlines across the configured instruments / watchlist.
   Sentiment dot + date on the left, headline (and optional instrument chip /
   text snippet) on the right. Colours mirror the instrument panel's news card. */
.dash-news {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overflow-x: hidden;
	font-family: OpenSans, sans-serif;
}
.dash-news .dn-row {
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 8px 2px;
	border-bottom: 1px solid #ececec;
}
.dash-news .dn-row:last-child { border-bottom: 0; }
.dash-news .dn-meta {
	flex: 0 0 44px;
	font-size: 10.5px;
	color: #737485;
	white-space: nowrap;
	line-height: 1.4;
}
.dash-news .dn-dot {
	display: inline-block; width: 6px; height: 6px; border-radius: 50%;
	margin-right: 5px; vertical-align: middle;
}
.dash-news .dn-pos  { background: #00a152; }
.dash-news .dn-neg  { background: #d32f2f; }
.dash-news .dn-flat { background: #c2c7ce; }
.dash-news .dn-main { flex: 1 1 auto; min-width: 0; }
.dash-news .dn-title {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	font-size: 12.5px; line-height: 1.35; color: #27251E; text-decoration: none;
}
a.dn-title { color: #2f6fed; cursor: pointer; }
a.dn-title:hover { text-decoration: underline; }
.dash-news .dn-instr { margin-top: 4px; }
.dash-news .dn-instr .tt-instr-sym { font-size: 11px; }
.dash-news .dn-text {
	margin-top: 4px;
	font-size: 11.5px; line-height: 1.4; color: #6b6c7a;
	display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Dark mode */
body.appbuilder-dark .dash-news .dn-row   { border-bottom-color: var(--border, #3a3a44); }
body.appbuilder-dark .dash-news .dn-meta  { color: var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .dash-news .dn-title { color: var(--fg-strong, #e6e6ea); }
body.appbuilder-dark a.dn-title           { color: #6ea8ff; }
body.appbuilder-dark .dash-news .dn-text  { color: var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .dash-news .dn-pos   { background: #00c853; }
body.appbuilder-dark .dash-news .dn-neg   { background: #ef5350; }
body.appbuilder-dark .dash-news .dn-flat  { background: #55595f; }

/* ---- Events widget (tradingevents) ---------------------------------------
   A date-ordered list of upcoming financial events. Date on the left, a
   colour-coded type badge + instrument (or title) on the right. */
.dash-events {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overflow-x: hidden;
	font-family: OpenSans, sans-serif;
}
.dash-events .de-row {
	display: flex;
	align-items: baseline;
	gap: 10px;
	padding: 8px 2px;
	border-bottom: 1px solid #ececec;
}
.dash-events .de-row:last-child { border-bottom: 0; }
.dash-events .de-date {
	flex: 0 0 60px;
	font-size: 11px; font-weight: 600; color: #6b6c7a;
	white-space: nowrap; line-height: 1.5;
}
.dash-events .de-main { flex: 1 1 auto; min-width: 0; }
.dash-events .de-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dash-events .de-badge {
	flex: 0 0 auto;
	font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px;
	padding: 2px 7px; border-radius: 10px; color: #fff; white-space: nowrap;
}
.dash-events .de-k-earnings { background: #2f6fed; }
.dash-events .de-k-dividend { background: #00a152; }
.dash-events .de-k-split    { background: #8b5cf6; }
.dash-events .de-k-ipo      { background: #f0a030; }
.dash-events .de-k-economic { background: #6b7280; }
.dash-events .de-title { font-size: 12.5px; color: #27251E; }
.dash-events .de-detail { margin-top: 3px; font-size: 11px; color: #737485; line-height: 1.4; }
.dash-events .tt-instr-sym { font-size: 12px; }

/* Config: the event-type checkbox stack. 14px below so the next field's label
   (Horizon) doesn't sit flush against the last checkbox. */
.ev-cfg-types { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 14px; }

/* Dark mode */
body.appbuilder-dark .dash-events .de-row    { border-bottom-color: var(--border, #3a3a44); }
body.appbuilder-dark .dash-events .de-date   { color: var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .dash-events .de-title  { color: var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .dash-events .de-detail { color: var(--fg-muted, #9aa0ac); }

/* ---- Market-sessions widget (tradingsessions) ----------------------------
   Three variants: strip (reuses the ticker-banner shell), timeline, line.
   Colour by state: green open, amber pre-market, red closed. */
.builder-dashboard-component[componenttype='tradingsessions'] .builder-dashboard-component-body { padding: 0; }
.market-sessions { height: 100%; font-family: OpenSans, sans-serif; }

/* Heatmap (tradingheatmap): the ECharts treemap fills the body edge-to-edge. */
.builder-dashboard-component[componenttype='tradingheatmap'] .builder-dashboard-component-body { padding: 0; }
.tradingheatmap-host { width: 100%; height: 100%; position: relative; }
/* Drill "back to overview" pill — a dark chip that reads over the coloured tiles
   in both light and dark dashboards. Hidden until a sector is opened. */
.heatmap-back {
	position: absolute; top: 5px; left: 5px; z-index: 4;
	/* inline-grid with both labels stacked in the SAME cell → the chip width is
	   constant (the wider of the two), so the hover swap can't resize it and make
	   the cursor fall off the edge (the blink). */
	display: inline-grid; align-items: center; justify-items: start;
	padding: 6px 14px; border-radius: 15px;
	background: rgba(30,32,38,0.88); color: #f0f1f4;
	font-family: OpenSans, sans-serif; font-size: 13px; font-weight: 700; cursor: pointer;
	box-shadow: 0 1px 5px rgba(0,0,0,0.4);
	transition: background 0.12s ease;
}
.heatmap-back .hb-title,
.heatmap-back .hb-back { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.heatmap-back .hb-back { visibility: hidden; }
.heatmap-back .fa { font-size: 14px; }
/* Hover the chip → it becomes the "‹ All sectors" back control (accent). */
.heatmap-back:hover { background: #269DF0; }
.heatmap-back:hover .hb-title { visibility: hidden; }
.heatmap-back:hover .hb-back  { visibility: visible; }
/* …but the Loading / error text still needs padding, or it glues to the corner. */
.builder-dashboard-component[componenttype='tradingheatmap'] .builder-dashboard-component-body > .builder-dashboard-loading,
.builder-dashboard-component[componenttype='tradingheatmap'] .builder-dashboard-component-body > .builder-dashboard-error {
	padding: 12px 14px;
}

.ms-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #9aa0a8; flex: 0 0 auto; }
.ms-dot.is-open   { background: #22c55e; }
.ms-dot.is-pre    { background: #f59e0b; }
.ms-dot.is-closed { background: #ef4444; }
.ms-dot.is-local  { background: #22c55e; }

.ms-badge { font-size: 10px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; white-space: nowrap; }
.ms-badge.is-open   { color: #15803d; background: rgba(34,197,94,.16); }
.ms-badge.is-pre    { color: #b45309; background: rgba(245,158,11,.18); }
.ms-badge.is-closed { color: #b91c1c; background: rgba(239,68,68,.15); }

/* strip variant — cards inside the reused .tb-strip */
.market-sessions .mss-card { flex: 0 0 auto; display: flex; flex-direction: column; gap: 2px; padding: 6px 16px; white-space: nowrap; min-width: 118px; }
.market-sessions .mss-card + .mss-card { border-left: 1px solid #ececec; }
.market-sessions .mss-head { display: flex; align-items: center; gap: 7px; }
.market-sessions .mss-name { font-size: 12px; font-weight: 600; color: #27251E; text-transform: uppercase; letter-spacing: .02em; }
.market-sessions .mss-time { font-size: 22px; font-weight: 600; line-height: 1.05; color: #27251E; font-variant-numeric: tabular-nums; }
.market-sessions .mss-sub  { font-size: 11px; color: #6b7280; display: flex; align-items: center; gap: 5px; }
.market-sessions .mss-mic  { color: #9aa0a8; }

/* compact line variant */
.market-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; padding: 8px 12px; height: 100%; overflow: auto; box-sizing: border-box; }
.market-line .msl-item { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: #27251E; }
.market-line .msl-code { font-weight: 700; }
.market-line .msl-time { font-variant-numeric: tabular-nums; }
.market-line .msl-abbr { color: #9aa0a8; font-size: 11px; }

/* timeline variant */
.market-timeline { position: relative; display: flex; flex-direction: column; justify-content: center; gap: 8px; padding: 12px 14px; height: 100%; overflow: auto; box-sizing: border-box; }
.market-timeline .mst-row { display: flex; align-items: center; gap: 10px; }
.market-timeline .mst-label { display: flex; align-items: center; gap: 7px; width: 120px; flex: 0 0 auto; font-size: 13px; font-weight: 600; color: #27251E; }
.market-timeline .mst-track { position: relative; flex: 1 1 auto; height: 10px; border-radius: 5px; background: #eceef1; }
.market-timeline .mst-fills { position: absolute; inset: 0; border-radius: 5px; overflow: hidden; }
.market-timeline .mst-seg { position: absolute; top: 0; bottom: 0; background: #22c55e; }
.market-timeline .mst-seg.is-pre { background: #f59e0b; }
/* Closed market: still show its session, but muted red so it stays subtle. */
.market-timeline .mst-seg.is-closed { background: rgba(239,68,68,0.30); }
/* One continuous "now" line spanning all rows, positioned by _UpdateSessions. */
.market-timeline .mst-nowline { position: absolute; top: 16px; bottom: 10px; width: 2px; background: #3b82f6; z-index: 3; pointer-events: none; }
.market-timeline .mst-now-chip { position: absolute; top: -15px; left: 50%; transform: translateX(-50%); background: #3b82f6; color: #fff; font-size: 10px; font-weight: 700; line-height: 1.4; padding: 1px 5px; border-radius: 6px; white-space: nowrap; }
.market-timeline .mst-right { width: 92px; flex: 0 0 auto; text-align: right; font-size: 12px; color: #6b7280; }

/* config: exchange multi-select checkbox grid. Scoped under .charts_wl_dlg to
   beat that dialog's `label{display:block}` and `input{width:100%;margin-bottom}`
   rules, which otherwise blow the checkboxes up and stack them above the label. */
.charts_wl_dlg .ms-cfg-list { max-height: 340px; overflow: auto; border: 1px solid #e2e2e2; border-radius: 6px; padding: 6px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 2px 14px; margin-bottom: 14px; }
.charts_wl_dlg label.ms-cfg-item { display: flex; align-items: center; gap: 7px; margin: 0; padding: 3px 0; font-size: 12px; font-weight: 400; color: #27251E; cursor: pointer; }
.charts_wl_dlg label.ms-cfg-inline { display: flex; align-items: center; gap: 7px; margin: 8px 0 0; font-size: 12px; font-weight: 400; color: #27251E; }
.charts_wl_dlg .ms-cfg-list input[type=checkbox],
.charts_wl_dlg label.ms-cfg-inline input[type=checkbox] { width: auto; margin: 0; flex: 0 0 auto; }
/* An inline checkbox carries a TOP margin only (it follows a field, which has
   already paid for the gap below itself). A .cfg-field following one therefore
   started flush against the checkbox — "Stale-data action" sat welded to
   "Allow short selling" above it, reading as that checkbox's own sub-label
   rather than as the next field. The gap belongs to whichever element breaks
   the run, so it is stated on the sibling pair rather than added to every
   .cfg-field (which would double up wherever fields simply follow fields).
   Section headers are left out: .pf_wiz_sec carries its own top margin. */
.charts_wl_dlg label.ms-cfg-inline + .cfg-field,
.charts_wl_dlg label.ms-cfg-inline + .ms-cfg-list { margin-top: 14px; }
.ms-cfg-code { color: #9aa0a8; font-size: 11px; }
body.appbuilder-dark .charts_wl_dlg label.ms-cfg-item,
body.appbuilder-dark .charts_wl_dlg label.ms-cfg-inline { color: var(--fg-strong, #e6e6ea); }

/* dark mode */
body.appbuilder-dark .market-sessions .mss-name,
body.appbuilder-dark .market-sessions .mss-time,
body.appbuilder-dark .market-line .msl-item,
body.appbuilder-dark .market-timeline .mst-label { color: var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .market-sessions .mss-card + .mss-card { border-left-color: var(--border, #3a3a44); }
/* The rail and the closed-session fill were both tuned against the LIGHT track
   (#eceef1) and neither survived the move to a dark one. At #2b2b33 the rail was
   within a few points of the panel behind it, so the row read as segments
   floating in space with no track to sit in; and a 30%-alpha red over that dark
   ground blended to roughly #5a3037, which is the barely-there bar in dark mode.
   Lift the rail off the panel, give it a hairline so its extent is legible even
   where it is empty, and carry the closed fill at an alpha that reads as a
   colour rather than a smudge. Open (#22c55e) and pre-market (#f59e0b) are solid
   and already carry themselves on either ground.

   The alpha is measured, not guessed: against this track the closed fill lands
   at 2.6:1 where 0.30 gave 1.35:1, while an OPEN session sits at 5.5:1. Closed
   therefore stays plainly subordinate to open — which is the point of muting it
   — without disappearing into the rail. */
body.appbuilder-dark .market-timeline .mst-track {
	background: #33333d;
	box-shadow: inset 0 0 0 1px rgba(255,255,255,0.07);
}
body.appbuilder-dark .market-timeline .mst-seg.is-closed { background: rgba(239,68,68,0.82); }
body.appbuilder-dark .ms-badge.is-open   { color: #7ddb9a; background: rgba(34,197,94,.18); }
body.appbuilder-dark .ms-badge.is-pre    { color: #fbbf24; background: rgba(245,158,11,.2); }
body.appbuilder-dark .ms-badge.is-closed { color: #f2a3a3; background: rgba(239,68,68,.2); }
body.appbuilder-dark .ms-cfg-list { border-color: #3a3a44; }

/* Native controls on the config dialogs: color-scheme:dark makes the browser
   render its OWN dark versions in dark mode (the same fix as the grid
   checkboxes and .charts_date) instead of the pale defaults.
   Number → a dark spinner. Date/datetime-local → a light picker icon instead of
   near-black on a near-black field, and a dark dropdown panel instead of a white
   sheet. Only the number case was covered before, which is how the trading-chart
   config's From/To fields stayed light. */
body.appbuilder-dark .tradingcfg input[type=number],
body.appbuilder-dark .tradingcfg input[type=date],
body.appbuilder-dark .tradingcfg input[type=datetime-local] { color-scheme:dark; }
.gauge-caption {
	text-align: center;
	margin-top: 2px;
	flex: 0 0 auto;
}

/* Tables & pivot */
.builder-dashboard-table-wrap {
	flex: 1 1 auto;
	overflow: auto;
	min-height: 0;
}
.builder-dashboard-table,
.builder-dashboard-pivot {
	width: 100%;
	border-collapse: collapse;
	font-size: 12px;
}
.builder-dashboard-table th,
.builder-dashboard-table td,
.builder-dashboard-pivot th,
.builder-dashboard-pivot td {
	border-bottom: 1px solid #f0eee9;
	padding: 4px 8px;
	text-align: left;
	white-space: nowrap;
}
/* Currency amounts (and their headings) sit on the right edge in tabular
   digits so the figures line up; counts, rates and percentages keep the
   default. Same specificity as the base rule above; it wins by order. */
.builder-dashboard-table th.tt-money,
.builder-dashboard-table td.tt-money,
th.tt-money, td.tt-money { text-align: right; font-variant-numeric: tabular-nums; }
.builder-dashboard-table th,
.builder-dashboard-pivot th {
	font-weight: 400;
	color: rgb(80, 80, 90);
	background: #faf8f5;
	position: sticky;
	top: 0;
}
.builder-dashboard-pivot td.is-total,
.builder-dashboard-pivot tr.is-total-row th,
.builder-dashboard-pivot tr.is-total-row td {
	font-weight: 600;
	background: #faf8f5;
}

/* List */
.builder-dashboard-list {
	list-style: none;
	margin: 0;
	padding: 0;
	flex: 1 1 auto;
	overflow: auto;
	min-height: 0;
}
.builder-dashboard-list li {
	display: flex;
	gap: 8px;
	padding: 6px 0;
	border-bottom: 1px solid #f0eee9;
	align-items: flex-start;
}
/* Icon and title share an explicit line-height so both first lines sit
   on the same visual row regardless of font metrics. The previous
   padding-top:2px nudge over-shot for the FontAwesome glyphs (their
   line box renders the dot below center) and the title looked above
   the dot. Equal line-height + flex-start = clean alignment. */
.builder-dashboard-list li i {
	color: rgb(140, 140, 150);
	font-size: 12px;
	line-height: 18px;
	flex: 0 0 auto;
}
.builder-dashboard-list li strong {
	display: block;
	font-weight: 600;
	font-size: 12px;
	line-height: 18px;
}
.builder-dashboard-list li span {
	color: rgb(115, 116, 133);
	font-size: 11px;
}

	/* Avatar thumbnail when a list item's icon is a small image URL/data-URI. */
	.builder-dashboard-list li img.builder-dashboard-list-avatar {
		flex: 0 0 auto;
		width: 22px;
		height: 22px;
		border-radius: 50%;
		object-fit: cover;
		background: #ececec;
	}
	body.appbuilder-dark .builder-dashboard-list li img.builder-dashboard-list-avatar {
		background: #2a2e36;
	}

	/* Prismo table result — compact clickable card in the conversation; opens the
   full table in the right-side panel (like the Artifact card). */
.builder-thread-table-card {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 12px;
	margin: 4px 0;
	max-width: 440px;
	border: 1px solid #e5e3de;
	border-radius: 8px;
	background: #fafafa;
	cursor: pointer;
	transition: background 0.12s ease, border-color 0.12s ease;
}
.builder-thread-table-card:hover { background: #f2f6fd; border-color: #cfe0fb; }
.builder-thread-table-card-icon {
	flex: 0 0 auto;
	width: 34px; height: 34px;
	border-radius: 7px;
	background: #eaf2fe;
	color: rgb(38,157,240);
	display: flex; align-items: center; justify-content: center;
	font-size: 15px;
}
.builder-thread-table-card-body { flex: 1 1 auto; min-width: 0; }
.builder-thread-table-card-title {
	font-size: 13px; font-weight: 600; color: #27251E;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.builder-thread-table-card-sub { font-size: 11px; color: rgb(115,116,133); margin-top: 2px; }
.builder-thread-table-card-open { flex: 0 0 auto; color: rgb(160,160,170); font-size: 12px; }
body.appbuilder-dark .builder-thread-table-card { background: var(--bg-elev,#242424); border-color: var(--border,#333); }
body.appbuilder-dark .builder-thread-table-card:hover { background: var(--bg-hover,#2a2a2a); border-color: #3a5170; }
body.appbuilder-dark .builder-thread-table-card-icon { background: rgba(38,157,240,0.18); color: #6fb8f5; }
body.appbuilder-dark .builder-thread-table-card-title { color: var(--fg,#e6e6e6); }
body.appbuilder-dark .builder-thread-table-card-sub { color: var(--fg-muted,#a0a0a0); }

/* Table docked in the right panel: fill the content area so the inner
   flex .builder-dashboard-table-wrap expands to full height and scrolls
   (sticky header + full-width grid come from the shared table rules). */
.builder-thread-table-panel {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	box-sizing: border-box;
	overflow: hidden;
	padding: 12px;                 /* breathing room within the panel */
	font-family: OpenSans, sans-serif;
}
/* The reused .builder-dashboard-component is normally gridstack-positioned
   (position:absolute; inset:0). Here it just fills the padded panel. */
.builder-thread-table-panel .builder-dashboard-component {
	position: relative;
	inset: auto;
	flex: 1 1 auto;
	min-height: 0;
}

.builder-dashboard-meta {
	margin-top: 6px;
	font-size: 11px;
	color: rgb(115, 116, 133);
}

/* Filter */
.builder-dashboard-filter {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 12px;
	height: 100%;
	cursor: pointer;
	padding: 0 6px;
	border-radius: 4px;
	transition: background 120ms ease;
}
.builder-dashboard-filter:hover { background: #f4f1ec; }
.builder-dashboard-filter .flt-label { color: rgb(80, 80, 90); }
.builder-dashboard-filter .flt-value {
	font-weight: 400;
	background: #f2f0ec;
	padding: 2px 8px;
	border-radius: 3px;
}
.builder-dashboard-filter i { color: rgb(140, 140, 150); }
body.appbuilder-dark .builder-dashboard-filter:hover { background: rgba(255,255,255,0.05); }

/* Map (rank bars) */
.builder-dashboard-map {
	flex: 1 1 auto;
	overflow: auto;
	min-height: 0;
	padding-right: 4px;
}
.builder-dashboard-map .map-row {
	display: grid;
	grid-template-columns: 110px 1fr 60px;
	gap: 8px;
	align-items: center;
	font-size: 12px;
	padding: 3px 0;
}
.builder-dashboard-map .map-label {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.builder-dashboard-map .map-bar {
	background: #f0eee9;
	border-radius: 3px;
	height: 10px;
	overflow: hidden;
}
.builder-dashboard-map .map-bar > div {
	background: #1f77b4;
	height: 100%;
}
.builder-dashboard-map .map-value {
	text-align: right;
	color: rgb(80, 80, 90);
}

.builder-dashboard-raw {
	font-size: 11px;
	background: #faf8f5;
	padding: 8px;
	border-radius: 4px;
	overflow: auto;
	flex: 1 1 auto;
	min-height: 0;
}

.builder-dashboard-text {
	flex: 1 1 auto;
	overflow: auto;
	min-height: 0;
}

/* Dark theme */
body.appbuilder-dark .builder-dashboard-component {
	background: var(--bg-panel) !important;
	border-color: var(--border) !important;
	box-shadow: none;
}
body.appbuilder-dark .builder-dashboard-component-header {
	border-bottom-color: var(--border) !important;
}
body.appbuilder-dark .builder-dashboard-component-title,
body.appbuilder-dark .builder-dashboard-component-body,
body.appbuilder-dark .builder-dashboard-kpi .kpi-value,
body.appbuilder-dark .builder-dashboard-progress .kpi-value {
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder-dashboard-drag-handle:hover {
	background: var(--bg-hover) !important;
	color: var(--fg-strong) !important;
}
body.appbuilder-dark .builder-dashboard-table th,
body.appbuilder-dark .builder-dashboard-pivot th,
body.appbuilder-dark .builder-dashboard-pivot td.is-total,
body.appbuilder-dark .builder-dashboard-pivot tr.is-total-row th,
body.appbuilder-dark .builder-dashboard-pivot tr.is-total-row td,
body.appbuilder-dark .builder-dashboard-filter .flt-value {
	background: var(--bg-hover) !important;
	color: var(--fg) !important;
}
body.appbuilder-dark .builder-dashboard-table th,
body.appbuilder-dark .builder-dashboard-pivot th,
body.appbuilder-dark .builder-dashboard-table td,
body.appbuilder-dark .builder-dashboard-pivot td,
body.appbuilder-dark .builder-dashboard-list li {
	border-bottom-color: var(--border) !important;
}
body.appbuilder-dark .builder-dashboard-progress .progress-bar,
body.appbuilder-dark .builder-dashboard-map .map-bar {
	background: var(--bg-hover) !important;
}
body.appbuilder-dark .builder-dashboard-loading,
body.appbuilder-dark .builder-dashboard-error,
body.appbuilder-dark .builder-dashboard-meta,
body.appbuilder-dark .kpi-target,
body.appbuilder-dark .builder-dashboard-list li span,
body.appbuilder-dark .builder-dashboard-filter .flt-label,
body.appbuilder-dark .builder-dashboard-map .map-value,
body.appbuilder-dark .builder-dashboard-tradingchart-empty,
body.appbuilder-dark .dashboard-addkind-text > small,
body.appbuilder-dark .builder-dashboard-drag-handle {
	color: var(--fg-muted) !important;
}
body.appbuilder-dark .builder-dashboard-tradingchart-empty > .fa { color:#4a4f55; }
body.appbuilder-dark .dashboard-addkind-ic { color:#8ec2ee; }
body.appbuilder-dark .dashboard-addkind-btn {
	background:var(--bg-panel); border-color:var(--border);
}
body.appbuilder-dark .dashboard-addkind-btn:hover {
	background:var(--bg-hover); border-color:var(--border-strong, #505050);
}
body.appbuilder-dark .dashboard-addkind-text > b { color:#eee; }


/* FullCalendar — keep typography consistent with the rest of the Builder UI */
.fc, .fc * {
	font-family: OpenSans, sans-serif;
	font-size: 14px;
}
/* Hour axis labels and the "all-day" label on the left margin a touch
   smaller than the rest of the calendar so they stay discreet. */
.fc .fc-timegrid-slot-label,
.fc .fc-timegrid-slot-label-cushion,
.fc .fc-timegrid-axis,
.fc .fc-timegrid-axis-cushion {
	font-size: 12px;
}

/* Strip FullCalendar default borders so the calendar reads lighter, then
   re-add minimal #3A3A3A separators: vertical lines between day columns
   and the time-axis, horizontal lines on the hour boundaries (no minor
   half-hour lines), and a single thin divider under the all-day section. */
.fc {
	--fc-border-color: transparent;
	/* Soft light-blue tint for today (matches mass-import drop-zone hover). */
	--fc-today-bg-color: rgba(38, 157, 240, 0.08);
	/* FullCalendar's default event text color is white; in light mode the
	   pale blue background needs black text to be readable. */
	--fc-event-text-color: #000000;
	/* Single source of truth for the calendar separators: light gray in light
	   mode, dark gray in dark mode. */
	--cal-separator: #d0d0d0;
	/* Background for the Month-view dot-event hover. */
	--cal-dot-hover: rgba(38, 157, 240, 0.12);
	/* Subdued text color for the Month-view dot events (time + title). Dark in
	   light mode (white background needs darker text), light in dark mode. */
	--cal-dot-text: #4a4a4a;
}
body.appbuilder-dark .fc {
	--fc-event-text-color: #ffffff;
	--cal-separator: #3a3a3a;
	--cal-dot-hover: #3a3a3a;
	--cal-dot-text: #b0b0b0;
}
/* Day view shows a single column = today, so the tint fills everything and
   loses meaning. Drop it. The .fc-day-mode class is set via viewClassNames. */
.fc-day-mode {
	--fc-today-bg-color: transparent;
}
.fc .fc-timegrid-col,
.fc .fc-daygrid-day,
.fc .fc-col-header-cell,
.fc .fc-timegrid-axis {
	border-right: 1px solid var(--cal-separator);
}
.fc .fc-timegrid-slot:not(.fc-timegrid-slot-minor) {
	border-top: 1px solid var(--cal-separator);
}
/* Horizontal separator between weeks in the Month view. The default day-cell
   border is suppressed by --fc-border-color above and an inner frame masks
   any direct border on the <td>, so draw the line on the inner frame. */
.fc .fc-daygrid-day-frame {
	border-top: 1px solid var(--cal-separator);
}
/* Meeting events are clickable (open the modify dialog). */
.fc .fc-event {
	cursor: pointer;
	font-size: 12px;
	transition: background-color 0.15s ease, border-color 0.15s ease;
}
/* Time-grid (Day/Week/Workweek) meetings: borderless, same as multi-day bars. */
.fc .fc-event:not(.fc-daygrid-dot-event) {
	border: 0 !important;
	color: #000000 !important;
}
/* The inner title and time elements pick up `color: var(--fc-event-text-color)`
   directly from FC's stylesheet — force them too so the title doesn't read as
   a faded "disabled" gray on the pale-blue background. */
.fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-title,
.fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-time,
.fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-title-container {
	color: #000000 !important;
}
body.appbuilder-dark .fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-title,
body.appbuilder-dark .fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-time,
body.appbuilder-dark .fc .fc-event:not(.fc-daygrid-dot-event) .fc-event-title-container {
	color: #ffffff !important;
}
/* FullCalendar adds a 1px box-shadow ring (--fc-page-bg-color) on time-grid
   events when they overlap, which reads as a white halo in dark mode. */
.fc .fc-timegrid-event,
.fc .fc-timegrid-event-harness-inset .fc-timegrid-event,
.fc .fc-timegrid-event.fc-event-mirror,
.fc .fc-timegrid-more-link {
	box-shadow: none !important;
}
/* Two side-by-side meetings at the same time touch each other with no gap.
   The inner event is absolutely positioned with inset:0 inside its harness;
   nudge its right edge inward by 2px to leave a transparent strip between
   adjacent overlapping meetings. */
.fc .fc-timegrid-event {
	right: 2px !important;
}
/* Short time-grid meetings (e.g. 30-min) clip the bottom of the time chip
   because the slot height is too small for one line of text. Bump the slot
   height, drop the bold from the time chip, and shave font-size +
   line-height inside the event so a 30-min row fits cleanly. */
.fc .fc-timegrid-slot {
	height: 28px !important;
}
.fc .fc-timegrid-event {
	min-height: 22px;
}
.fc .fc-timegrid-event .fc-event-main,
.fc .fc-timegrid-event .fc-event-main-frame,
.fc .fc-timegrid-event .fc-event-time,
.fc .fc-timegrid-event .fc-event-title,
.fc .fc-timegrid-event .fc-event-title-container {
	font-size: 11px !important;
	line-height: 1 !important;
	font-weight: normal !important;
}
/* In dark mode use the Build button blue (and its hover) for events so
   they read clearly on the dark canvas. Exclude the Month view's "dot"
   variant, which is styled separately (transparent background + dot). */
body.appbuilder-dark .fc .fc-event:not(.fc-daygrid-dot-event) {
	background-color: #269DF0 !important;
	border-color: #269DF0 !important;
	color: #ffffff !important;
}
body.appbuilder-dark .fc .fc-event:not(.fc-daygrid-dot-event):hover {
	background-color: #1F84C6 !important;
	border-color: #1F84C6 !important;
}

/* Month view, non all-day meetings: blue dot + time + title, no background,
   light gray text, normal weight. */
.fc .fc-daygrid-dot-event {
	background: transparent !important;
	border: 0 !important;
	line-height: 1.5;
	padding: 4px 6px !important;
	/* Earlier .fc-daygrid-event rule applies a negative margin-bottom to
	   tighten all-day bars; reset it here so dot events keep their full height. */
	margin-bottom: 0 !important;
	min-height: 24px;
	border-radius: 3px;
	box-sizing: border-box;
	transition: background-color 0.15s ease;
}
/* Inter-event spacing comes from the dot-event's own top/bottom padding
   (4px each = 8px between content), so we don't add a harness margin
   here — that would grow the day cell from outside the event box. */
.fc .fc-daygrid-dot-event:hover {
	background-color: var(--cal-dot-hover) !important;
}
/* Multi-day / all-day bars: the leading time chip should not be bold. */
.fc .fc-h-event .fc-event-time,
.fc .fc-daygrid-event .fc-event-time {
	font-weight: normal !important;
}
.fc .fc-daygrid-dot-event .fc-daygrid-event-dot {
	border-color: #269DF0 !important;
}
.fc .fc-daygrid-dot-event .fc-event-time,
.fc .fc-daygrid-dot-event .fc-event-title {
	color: var(--cal-dot-text) !important;
	font-weight: normal !important;
}
.fc .fc-daygrid-dot-event {
	overflow: hidden;
}
.fc .fc-daygrid-dot-event .fc-event-title {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.fc .fc-event .fc-event-title,
.fc .fc-event .fc-event-time {
	font-size: 12px;
	line-height: 1.2;
}
/* Slimmer rows for all-day meetings (top all-day section in time-grid views
   and the multi-day bars in the Month view). Drop the bottom padding by 2px
   and vertically center the title text. */
.fc .fc-daygrid-event,
.fc .fc-h-event {
	padding-top: 1px;
	padding-bottom: 0;
	margin-bottom: -2px;
	min-height: 0;
	display: flex;
	align-items: center;
}
.fc .fc-daygrid-event .fc-event-title,
.fc .fc-h-event .fc-event-title {
	padding: 0 4px;
	display: flex;
	align-items: center;
}
/* Days in the Month view drill into Day view when clicked. */
.fc .fc-daygrid-day {
	cursor: pointer;
}
.fc .fc-daygrid-day:hover .fc-daygrid-day-frame {
	background-color: rgba(38, 157, 240, 0.05);
}
.fc .fc-timegrid-divider {
	padding: 0 !important;
	height: 0 !important;
	border: none !important;
	border-bottom: 1px solid var(--cal-separator) !important;
}

/* Soften the now-indicator (default vivid red) and replace the default
   left-side triangle arrow with a small dot at the very left corner of
   the horizontal line itself. */
.fc .fc-timegrid-now-indicator-arrow {
	display: none !important;
}
.fc .fc-timegrid-now-indicator-line {
	border-color: #F55E57 !important;
	position: relative;
}
.fc .fc-timegrid-now-indicator-line::before {
	content: "";
	position: absolute;
	/* Keep the dot fully inside the day cell — the parent has overflow:hidden
	   so a negative left value would be clipped by the previous day. */
	left: 0;
	top: -4px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: #F55E57;
}

/* ==== Workflow Path Picker ============================================
   Reusable picker for selecting a dot-path into the workflow's variable
   bag. Layout: left rail (namespaces) + main panel (search + tree).
   In embedded mode a header bar carries Back · path · Select.
   In standalone (popup) mode a path row lives at the bottom.
   ====================================================================== */
.wf_pp_root {
	display: flex;
	flex-direction: column;
	gap: 8px;
	width: 100%;
	height: 100%;
}
.wf_pp_split {
	display: flex;
	flex: 1 1 auto;
	min-height: 0;
	border: 1px solid #d8d4cc;
	border-radius: 6px;
	overflow: hidden;
	background-color: #fff;
}
body.appbuilder-dark .wf_pp_split {
	border-color: #333;
	background-color: #2b2b2b;
}
.wf_pp_side {
	flex: 0 0 180px;
	overflow-y: auto;
	border-right: 1px solid #d8d4cc;
	background-color: #f6f3ee;
	padding: 6px 0;
}
body.appbuilder-dark .wf_pp_side {
	background-color: #1f1f1f;
	border-right-color: #333;
}
.wf_pp_ns {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 7px 12px;
	cursor: pointer;
	font: 12px OpenSans, sans-serif;
	color: #27251e;
	border-left: 3px solid transparent;
	user-select: none;
}
.wf_pp_ns:hover  { background-color: rgba(0, 0, 0, 0.04); }
body.appbuilder-dark .wf_pp_ns        { color: #d8d4cc; }
body.appbuilder-dark .wf_pp_ns:hover  { background-color: rgba(255, 255, 255, 0.06); }
.wf_pp_ns.active {
	background-color: rgba(74, 144, 226, 0.10);
	border-left-color: #4a90e2;
	font-weight: 600;
}
body.appbuilder-dark .wf_pp_ns.active {
	background-color: rgba(122, 177, 240, 0.16);
	border-left-color: #7AB1F0;
}
.wf_pp_ns .fa { width: 14px; text-align: center; opacity: 0.7; }

.wf_pp_main {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
}
.wf_pp_search {
	padding: 8px;
	border-bottom: 1px solid #d8d4cc;
}
body.appbuilder-dark .wf_pp_search { border-bottom-color: #333; }
.wf_pp_search input {
	width: 100%;
	padding: 6px 10px;
	border: 1px solid #d8d4cc;
	border-radius: 4px;
	background-color: #fff;
	color: inherit;
	font: 12px OpenSans, sans-serif;
	outline: none;
	box-sizing: border-box;
}
body.appbuilder-dark .wf_pp_search input {
	background-color: #1f1f1f;
	border-color: #333;
	color: #d8d4cc;
}

.wf_pp_tree {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 4px 0;
	font: 12px OpenSans, sans-serif;
	color: #27251e;
}
body.appbuilder-dark .wf_pp_tree { color: #d8d4cc; }
.wf_pp_node {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 12px;
	cursor: pointer;
	user-select: none;
}
.wf_pp_node:hover { background-color: rgba(0, 0, 0, 0.04); }
body.appbuilder-dark .wf_pp_node:hover { background-color: rgba(255, 255, 255, 0.06); }
.wf_pp_node.selected {
	background-color: rgba(74, 144, 226, 0.14);
}
body.appbuilder-dark .wf_pp_node.selected {
	background-color: rgba(122, 177, 240, 0.20);
}
.wf_pp_caret {
	width: 12px;
	text-align: center;
	font-size: 10px;
	opacity: 0.6;
	flex: 0 0 auto;
}
.wf_pp_caret.empty { visibility: hidden; }
.wf_pp_node_label { flex: 1 1 auto; }
.wf_pp_node_type  {
	flex: 0 0 auto;
	font-size: 11px;
	opacity: 0.65;
	font-style: italic;
}
.wf_pp_empty {
	padding: 16px;
	text-align: center;
	color: #888;
	font-size: 12px;
}

.wf_pp_path_row {
	display: flex;
	gap: 6px;
	align-items: center;
}
.wf_pp_path_row label {
	font: 12px OpenSans, sans-serif;
	color: #6a6660;
	flex: 0 0 auto;
}
.wf_pp_path_row input {
	flex: 1 1 auto;
	padding: 6px 10px;
	border: 1px solid #d8d4cc;
	border-radius: 4px;
	background-color: #fff;
	color: inherit;
	font: 12px monospace;
	outline: none;
	box-sizing: border-box;
}
body.appbuilder-dark .wf_pp_path_row input {
	background-color: #1f1f1f;
	border-color: #333;
	color: #d8d4cc;
}

/* Embedded-mode header path field — sits between Back and Select. */
.wf_pp_header_path {
	flex: 1 1 auto;
	min-width: 0;
	padding: 6px 10px;
	border: 1px solid #d8d4cc;
	border-radius: 4px;
	background-color: #fff;
	color: inherit;
	font: 12px monospace;
	outline: none;
	box-sizing: border-box;
}
body.appbuilder-dark .wf_pp_header_path {
	background-color: #1f1f1f;
	border-color: #333;
	color: #d8d4cc;
}

/* Picker header bar shown in embedded mode (panel-switch inside
   another popup): Back · path input · Select. */
.wf_pp_header {
	display: flex;
	align-items: center;
	gap: 8px;
	padding-bottom: 8px;
	border-bottom: 1px solid #d8d4cc;
	margin-bottom: 8px;
}
body.appbuilder-dark .wf_pp_header { border-bottom-color: #333; }

/* Inline picker button embedded over the right edge of the Data
   source input. JS positions it dynamically against the input's
   own offsetTop / offsetHeight / right edge — no DOM wrapping, so
   w2field's internal layout is left untouched. */
.wf_pp_inline_btn {
	position: absolute;
	width: 22px;
	height: 22px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #6a6660;
	cursor: pointer;
	border-radius: 3px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 12px;
	line-height: 1;
}
.wf_pp_inline_btn:hover { background: rgba(0, 0, 0, 0.08); color: #27251e; }
/* Dark mode — the project's theme class is body.appbuilder-dark
   (the previous [data-theme="dark"] selector never matched, which
   is why the helper buttons looked invisible against the dark
   panel background). */
body.appbuilder-dark .wf_pp_inline_btn        { color: #c8c8c8; }
body.appbuilder-dark .wf_pp_inline_btn:hover  { background: rgba(255, 255, 255, 0.18); color: #ffffff; }

/* "Pick" button injected next to the Data source field in the
   field-edit dialog. */
.wf_pp_pick_btn {
	margin-top: 4px;
	padding: 4px 10px;
	font: 11px OpenSans, sans-serif;
	border: 1px solid var(--bg-border, #d8d4cc);
	border-radius: 4px;
	background: var(--bg-page, #fff);
	color: inherit;
	cursor: pointer;
}
.wf_pp_pick_btn:hover { background: rgba(0, 0, 0, 0.04); }
[data-theme="dark"] .wf_pp_pick_btn        { background: #1f1f1f; border-color: #333; }
[data-theme="dark"] .wf_pp_pick_btn:hover  { background: #2a2a2a; }
.wf_pp_pick_btn .fa { margin-right: 4px; }

/* ==============================================================
 * Configurations panel
 * ============================================================== */
.configurations_panel {
	padding: 18px 24px;
	overflow-y: auto;
	height: 100%;
	box-sizing: border-box;
}
.configurations_header {
	display: flex;
	align-items: center;
	margin-bottom: 14px;
}
.configurations_title {
	flex: 1 1 auto;
	font-size: 18px;
	font-weight: 600;
}
.configurations_title i { margin-right: 8px; opacity: 0.8; }

.configurations_session {
	margin-bottom: 14px;
}
.configurations_session_card {
	background: #f5f7fa;
	border: 1px solid #d6dde6;
	border-radius: 6px;
	padding: 10px 12px;
	font-size: 12px;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
}
.configurations_session_card_active {
	background: #fff8e1;
	border-color: #f0d97c;
}
.configurations_session_hint {
	flex-basis: 100%;
	color: #777;
	font-size: 11px;
	margin-top: 4px;
}
.configurations_session_clear {
	margin-left: auto !important;
	padding: 3px 9px !important;
	font-size: 11px !important;
}

.configurations_list { display: flex; flex-direction: column; gap: 12px; }
.configurations_loading,
.configurations_empty {
	color: #888;
	font-size: 13px;
	text-align: center;
	padding: 30px 12px;
}
.configurations_empty i { font-size: 28px; opacity: 0.5; display: block; margin-bottom: 8px; }
.configurations_empty_sub { font-size: 11px; color: #999; margin-top: 4px; }

.configurations_card {
	background: #fff;
	border: 1px solid #e3e7ee;
	border-radius: 8px;
	padding: 12px 14px;
}
.configurations_card_head {
	display: flex;
	align-items: center;
	gap: 6px;
	flex-wrap: wrap;
}
.configurations_card_name { font-weight: 600; font-size: 14px; }
.configurations_card_spacer { flex: 1 1 auto; }
.configurations_card_desc {
	margin-top: 6px;
	font-size: 12px;
	color: #555;
	white-space: pre-wrap;
}
.configurations_card .w2ui-btn {
	padding: 3px 9px !important;
	font-size: 11px !important;
}

.configurations_badge {
	display: inline-block;
	padding: 2px 8px;
	border-radius: 10px;
	color: #fff;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
}
.configurations_badge_active  { background: #2e7d32; }
.configurations_badge_session { background: #1565c0; }

.configurations_versions { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }
.configurations_versions_empty {
	font-size: 11px;
	color: #999;
	font-style: italic;
	padding: 4px 0;
}
.configurations_version_row {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 12px;
	padding: 4px 8px;
	border: 1px solid #ecedf0;
	border-radius: 6px;
	background: #fafbfc;
}
.configurations_version_app  { font-weight: 600; }
.configurations_version_v    { color: #555; }
.configurations_version_name { color: #777; }
.configurations_version_db   { font-size: 11px; }
.configurations_version_spacer { flex: 1 1 auto; }
.configurations_status {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
	padding: 1px 6px;
	border-radius: 8px;
	color: #fff;
}
.configurations_status_published  { background: #2e7d32; }
.configurations_status_publishing { background: #f9a825; }
.configurations_status_failed     { background: #c62828; }
.configurations_status_retired    { background: #757575; }

/* version picker popup */
.configurations_pick_body { display: flex; flex-direction: column; gap: 4px; }
.configurations_pick_row {
	display: flex;
	gap: 8px;
	align-items: center;
	padding: 6px 8px;
	border: 1px solid #ecedf0;
	border-radius: 6px;
	cursor: pointer;
	font-size: 12px;
}
.configurations_pick_row:hover { background: #f0f4fa; }
.configurations_pick_app  { font-weight: 600; }
.configurations_pick_v    { color: #555; }
.configurations_pick_name { color: #777; }
.configurations_pick_db   { font-size: 11px; margin-left: auto; }

/* ==============================================================
 * Publish confirmation dialog
 * ============================================================== */
.publish_confirm {
	text-align: left;
	padding: 4px 6px 6px 6px;
	font-size: 13px;
	line-height: 1.45;
}
.publish_confirm_title {
	font-size: 15px;
	font-weight: 600;
	margin-bottom: 8px;
}
.publish_confirm_lead {
	color: #555;
	margin-bottom: 14px;
}
.publish_confirm_details {
	margin-top: 10px;
	border-top: 1px solid #e3e7ee;
	padding-top: 10px;
}
.publish_confirm_details > summary {
	cursor: pointer;
	font-size: 12px;
	color: #1565c0;
	user-select: none;
	outline: none;
}
.publish_confirm_details > summary::-webkit-details-marker { color: #1565c0; }
.publish_confirm_details[open] > summary { margin-bottom: 8px; }

.publish_confirm_table {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 6px 14px;
	font-size: 12px;
	margin-bottom: 8px;
}
.publish_confirm_row {
	display: contents;
}
.publish_confirm_row > span {
	color: #777;
}
.publish_confirm_row > code,
.publish_confirm_row > b {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 11.5px;
	background: #f3f5f8;
	padding: 1px 6px;
	border-radius: 4px;
	color: #303030;
	word-break: break-all;
}
.publish_confirm_row > b {
	background: transparent;
	padding: 0;
	font-family: inherit;
	font-size: 12px;
}
.publish_confirm_note {
	color: #888;
	font-size: 11px;
	font-style: italic;
}

body.appbuilder-dark .publish_confirm_lead   { color: var(--fg); }
body.appbuilder-dark .publish_confirm_details { border-top-color: var(--border); }
body.appbuilder-dark .publish_confirm_details > summary { color: #b8b8b8; }
body.appbuilder-dark .publish_confirm_details > summary::-webkit-details-marker { color: #b8b8b8; }
body.appbuilder-dark .publish_confirm_row > span,
body.appbuilder-dark .publish_confirm_note    { color: var(--fg-muted); }
body.appbuilder-dark .publish_confirm_row > code { background: #2a2a2a; color: var(--fg); }

/* ==============================================================
 * Runtime home panel
 * ============================================================== */
.runtime_home_panel {
	padding: 32px 32px 48px 32px;
	overflow-y: auto;
	height: 100%;
	box-sizing: border-box;
}
.runtime_home_hero {
	max-width: 720px;
	margin: 24px auto 32px auto;
	text-align: center;
}
.runtime_home_hero_title {
	font-size: 28px;
	font-weight: 600;
	color: #303030;
	margin-bottom: 10px;
}
.runtime_home_hero_sub {
	color: #777;
	font-size: 13px;
	line-height: 1.5;
}
.runtime_home_hero_sub_note { color: #999; font-style: italic; }

.runtime_home_apps {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
	gap: 14px;
	max-width: 1080px;
	margin: 0 auto;
}
.runtime_home_app_card {
	background: #fff;
	border: 1px solid #e3e7ee;
	border-radius: 10px;
	padding: 14px;
	display: flex;
	flex-direction: column;
	gap: 6px;
	transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.runtime_home_app_card:hover {
	box-shadow: 0 4px 14px rgba(0,0,0,0.08);
	transform: translateY(-1px);
}
.runtime_home_app_card_disabled {
	opacity: 0.55;
	pointer-events: auto;
}
.runtime_home_app_card_top {
	display: flex;
	align-items: center;
	gap: 8px;
}
.runtime_home_app_card_top i.fa-cube {
	color: #1565c0;
	font-size: 14px;
}
.runtime_home_app_name {
	font-weight: 600;
	font-size: 14px;
	color: #303030;
}
.runtime_home_app_v {
	color: #777;
	font-size: 12px;
}
.runtime_home_app_subtitle {
	color: #777;
	font-size: 12px;
}
.runtime_home_app_db {
	font-size: 11px;
	color: #999;
}
.runtime_home_app_db code {
	background: #f3f5f8;
	padding: 1px 5px;
	border-radius: 4px;
}
.runtime_home_app_cta {
	margin-top: 8px;
}
.runtime_home_app_cta .w2ui-btn {
	width: 100%;
	font-size: 12px !important;
}

.runtime_home_status {
	margin-left: auto;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
	padding: 1px 6px;
	border-radius: 8px;
	color: #fff;
}
.runtime_home_status_published  { background: #2e7d32; }
.runtime_home_status_publishing { background: #f9a825; }
.runtime_home_status_failed     { background: #c62828; }
.runtime_home_status_retired    { background: #757575; }

.runtime_home_empty {
	text-align: center;
	padding: 40px 12px;
	color: #888;
	font-size: 13px;
}
.runtime_home_empty i {
	font-size: 32px;
	opacity: 0.5;
	display: block;
	margin-bottom: 10px;
}
.runtime_home_empty_sub { font-size: 11px; color: #999; margin-top: 4px; }

body.appbuilder-dark .runtime_home_hero_title { color: var(--fg-strong); }
body.appbuilder-dark .runtime_home_hero_sub   { color: var(--fg-muted); }
body.appbuilder-dark .runtime_home_app_card   { background: var(--bg-elev); border-color: var(--border); }
body.appbuilder-dark .runtime_home_app_name   { color: var(--fg-strong); }
body.appbuilder-dark .runtime_home_app_db code { background: #2a2a2a; color: var(--fg); }

body.appbuilder-dark .configurations_session_card { background: var(--bg-elev); border-color: var(--border); }
body.appbuilder-dark .configurations_card         { background: var(--bg-elev); border-color: var(--border); }
body.appbuilder-dark .configurations_version_row  { background: var(--bg-elev); border-color: var(--border); }
body.appbuilder-dark .configurations_card_desc    { color: var(--fg); }


/* ==============================================================
 * Builder LLM admin tab (read-only Slice A)
 * Three stacked tables — Functions, Models, Credentials.
 * Reuses .step_header_block for the page header. Tables are
 * plain HTML; we mirror the spacing/typography conventions of
 * the rest of the builder rather than introducing w2grid here.
 * ============================================================== */
.builder-llm-panel {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    background-color: #FAF8F5;
    color: #27251E;
    font-family: OpenSans, sans-serif;
}
body.appbuilder-dark .builder-llm-panel { background-color: var(--bg); color: var(--fg); }

/* Locked top banner — title + scope + Refresh button.
   Background and border match the `step_header_block` used by
   the "STEP 8 OF 8" header on the Versions & Publish panel
   (warm light surface in light mode, var(--bg) in dark mode)
   so the LLM panel reads as part of the same visual family. */
.builder-llm-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 20px;
    background-color: #FAF8F5;
    border-bottom: 1px solid #EEECEA;
}
.builder-llm-header-title-wrap {
    flex: 1 1 auto;
    min-width: 0;
}
.builder-llm-header-title {
    font-size: 14px;
    font-weight: 600;
    color: #27251E;
    line-height: 1.2;
}
.builder-llm-header-intro {
    font-size: 11px;
    color: #808080;
    line-height: 1.4;
    margin-top: 2px;
    max-width: 900px;
}
.builder-llm-header code {
    font-family: Consolas, monospace;
    background: #ECEAE6;
    padding: 0 4px;
    border-radius: 2px;
    font-size: 10px;
    color: #27251E;
}

body.appbuilder-dark .builder-llm-header        { background-color: var(--bg); border-bottom-color: var(--border); }
body.appbuilder-dark .builder-llm-header-title  { color: var(--fg-strong); }
body.appbuilder-dark .builder-llm-header-intro  { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-header code   { background: var(--bg-elev); color: var(--fg); }

.builder-llm-content {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    padding: 14px 20px 24px;
}

.builder-llm-section {
    margin-bottom: 28px;
}
.builder-llm-section-title {
    font-size: 14px;
    font-weight: 600;
    color: #27251E;
    margin: 0 0 4px;
    letter-spacing: 0.02em;
}
.builder-llm-section-sub {
    font-size: 12px;
    color: #808080;
    margin-bottom: 10px;
    max-width: 760px;
    line-height: 1.5;
}
body.appbuilder-dark .builder-llm-section-title { color: var(--fg-strong); }
body.appbuilder-dark .builder-llm-section-sub   { color: var(--fg-muted); }

.builder-llm-table-wrap {
    background: #ffffff;
    border: 1px solid #E6E2DC;
    border-radius: 6px;
    overflow: hidden;
}
body.appbuilder-dark .builder-llm-table-wrap { background: var(--bg-panel); border-color: var(--border); }

.builder-llm-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.builder-llm-table th {
    text-align: left;
    background: #F4F2EE;
    color: #606060;
    font-weight: 600;
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 8px 12px;
    border-bottom: 1px solid #E6E2DC;
}
.builder-llm-table td {
    padding: 6px 12px;
    border-bottom: 1px solid #F1EEE8;
    vertical-align: middle;
    color: #27251E;
}
.builder-llm-table tr:last-child td { border-bottom: 0; }
.builder-llm-table tr:hover td { background: rgba(0,0,0,0.02); }
.builder-llm-table code {
    font-family: Consolas, monospace;
    background: #F4F2EE;
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 11px;
    color: #27251E;
}
.builder-llm-num { text-align: right; font-family: Consolas, monospace; }

body.appbuilder-dark .builder-llm-table th        { background: var(--bg-elev); color: var(--fg-muted); border-bottom-color: var(--border); }
body.appbuilder-dark .builder-llm-table td        { color: var(--fg); border-bottom-color: var(--border); }
body.appbuilder-dark .builder-llm-table tr:hover td { background: rgba(255,255,255,0.03); }
body.appbuilder-dark .builder-llm-table code      { background: var(--bg-elev); color: var(--fg); }

.builder-llm-muted        { color: #B0B0B0; }
.builder-llm-resolved     { color: #2E8B57; font-weight: 600; }
.builder-llm-error-inline { color: #C0392B; font-style: italic; }
.builder-llm-ok           { color: #2E8B57; font-weight: 600; }
.builder-llm-missing      { color: #C0392B; font-weight: 600; }
.builder-llm-loading      { padding: 16px; color: #808080; font-style: italic; }
.builder-llm-empty        { padding: 16px; color: #808080; }
.builder-llm-error        { padding: 16px; color: #C0392B; }

body.appbuilder-dark .builder-llm-muted        { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-resolved     { color: #34D399; }
body.appbuilder-dark .builder-llm-error-inline { color: #F87171; }
body.appbuilder-dark .builder-llm-ok           { color: #34D399; }
body.appbuilder-dark .builder-llm-missing      { color: #F87171; }
body.appbuilder-dark .builder-llm-loading      { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-empty        { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-error        { color: #F87171; }

/* ==============================================================
 * Builder LLM admin tab — Slice B (editing)
 * Modal + clickable rows + overridden-row indicator
 * ============================================================== */

/* Clickable rows in the Functions table */
.builder-llm-table-clickable tbody tr.builder-llm-row { cursor: pointer; }
.builder-llm-table-clickable tbody tr.builder-llm-row:hover td { background: rgba(38, 157, 240, 0.06); }
body.appbuilder-dark .builder-llm-table-clickable tbody tr.builder-llm-row:hover td { background: rgba(94, 183, 245, 0.10); }

/* Overridden row — soft left border in the accent color so you can
   scan down the table and immediately see which functions have an
   override set. */
.builder-llm-row-overridden td:first-child {
    box-shadow: inset 3px 0 0 0 #269DF0;
}
body.appbuilder-dark .builder-llm-row-overridden td:first-child {
    box-shadow: inset 3px 0 0 0 #5EB7F5;
}

.builder-llm-overridden-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 6px;
    font-size: 10px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    background: rgba(38, 157, 240, 0.14);
    color: #1F84C6;
    border-radius: 8px;
    font-weight: 600;
    vertical-align: middle;
}
body.appbuilder-dark .builder-llm-overridden-badge {
    background: rgba(94, 183, 245, 0.18);
    color: #5EB7F5;
}

/* Modal — backdrop + dialog box */
.builder-llm-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: OpenSans, sans-serif;
}
.builder-llm-modal {
    background: #ffffff;
    border: 1px solid #E6E2DC;
    border-radius: 8px;
    width: 520px;
    max-width: 90vw;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
    color: #27251E;
    display: flex;
    flex-direction: column;
}
body.appbuilder-dark .builder-llm-modal {
    background: var(--bg-panel);
    border-color: var(--border);
    color: var(--fg);
}

.builder-llm-modal-head {
    display: flex;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid #EEECEA;
}
.builder-llm-modal-title {
    flex: 1 1 auto;
    font-size: 14px;
    font-weight: 600;
}
.builder-llm-modal-title code {
    font-family: Consolas, monospace;
    background: #F4F2EE;
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 12px;
    color: #1F84C6;
}
.builder-llm-modal-close {
    background: transparent;
    border: 0;
    font-size: 22px;
    line-height: 1;
    color: #808080;
    cursor: pointer;
    padding: 0 4px;
}
.builder-llm-modal-close:hover { color: #27251E; }

body.appbuilder-dark .builder-llm-modal-head        { border-bottom-color: var(--border); }
body.appbuilder-dark .builder-llm-modal-title code  { background: var(--bg-elev); color: #5EB7F5; }
body.appbuilder-dark .builder-llm-modal-close       { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-modal-close:hover { color: var(--fg-strong); }

.builder-llm-modal-body {
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.builder-llm-field { display: flex; flex-direction: column; gap: 4px; }
.builder-llm-field label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: #606060;
}
.builder-llm-field select {
    font-family: OpenSans, sans-serif;
    font-size: 13px;
    padding: 6px 8px;
    border: 1px solid #E6E2DC;
    border-radius: 4px;
    background: #ffffff;
    color: #27251E;
}
.builder-llm-field-hint {
    font-size: 11px;
    color: #808080;
    line-height: 1.4;
}
body.appbuilder-dark .builder-llm-field label   { color: var(--fg-muted); }
body.appbuilder-dark .builder-llm-field select  { background: var(--bg-elev); border-color: var(--border); color: var(--fg); }
body.appbuilder-dark .builder-llm-field-hint    { color: var(--fg-muted); }

.builder-llm-modal-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 18px;
    border-top: 1px solid #EEECEA;
    background: #FAFAF8;
    border-bottom-left-radius: 8px;
    border-bottom-right-radius: 8px;
}
body.appbuilder-dark .builder-llm-modal-foot { background: var(--bg-alt); border-top-color: var(--border); }

/* Group-header row in the Models table — divides the catalog
   by provider (Anthropic / Gemini / OpenAI / Perplexity). Not
   clickable; no hover effect; visually anchored. */
.builder-llm-table tr.builder-llm-group-header td {
    background: #F4F2EE;
    color: #606060;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 6px 12px;
    border-top: 1px solid #E6E2DC;
    cursor: default;
    user-select: none;
}
.builder-llm-table tr.builder-llm-group-header:hover td { background: #F4F2EE; }
.builder-llm-table tr.builder-llm-group-header:first-child td { border-top: 0; }

body.appbuilder-dark .builder-llm-table tr.builder-llm-group-header td {
    background: var(--bg-elev);
    color: var(--fg-muted);
    border-top-color: var(--border);
}
body.appbuilder-dark .builder-llm-table tr.builder-llm-group-header:hover td {
    background: var(--bg-elev);
}

/* ----- Slice C — Test panel ----- */
.builder-llm-test {
    background: #ffffff;
    border: 1px solid #E6E2DC;
    border-radius: 6px;
    padding: 14px 16px;
    max-width: 880px;
}
body.appbuilder-dark .builder-llm-test {
    background: var(--bg-panel);
    border-color: var(--border);
}
.builder-llm-test-row {
    display: flex;
    align-items: flex-start;
    margin-bottom: 10px;
}
.builder-llm-test-label {
    flex: 0 0 130px;
    font-size: 12px;
    color: #606060;
    padding-top: 6px;
    font-weight: 600;
}
body.appbuilder-dark .builder-llm-test-label { color: var(--fg-muted); }
.builder-llm-test-pickhost {
    flex: 1 1 auto;
    min-width: 0;
    /* AppendPickButton renders a <button class=wf-pickbtn>; let it
       stretch to fill the row. */
    display: flex;
}
.builder-llm-test-pickhost .wf-pickbtn { flex: 1 1 auto; }
.builder-llm-test-textarea {
    flex: 1 1 auto;
    font-family: Consolas, monospace;
    font-size: 12px;
    line-height: 1.4;
    padding: 6px 8px;
    border: 1px solid #D6D2CC;
    border-radius: 4px;
    background: #ffffff;
    color: #27251E;
    box-sizing: border-box;
    resize: vertical;
}
body.appbuilder-dark .builder-llm-test-textarea {
    background: var(--bg-elev);
    color: var(--fg);
    border-color: var(--border);
}
.builder-llm-test-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 4px;
}
.builder-llm-test-status {
    font-size: 12px;
    color: #808080;
}
.builder-llm-test-status-running { color: #1976D2; }
.builder-llm-test-status-ok      { color: #2E7D32; }
.builder-llm-test-status-error   { color: #C62828; }
.builder-llm-test-result {
    margin-top: 12px;
}
.builder-llm-test-result:empty { display: none; }
.builder-llm-test-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    font-size: 11px;
    color: #606060;
    padding: 8px 10px;
    background: #F4F2EE;
    border-radius: 4px;
    margin-bottom: 8px;
}
body.appbuilder-dark .builder-llm-test-meta {
    background: var(--bg-elev);
    color: var(--fg-muted);
}
.builder-llm-test-meta code {
    font-family: Consolas, monospace;
    background: rgba(0,0,0,0.04);
    padding: 1px 5px;
    border-radius: 3px;
}
body.appbuilder-dark .builder-llm-test-meta code { background: rgba(255,255,255,0.06); }
.builder-llm-test-text {
    font-family: Consolas, monospace;
    font-size: 12px;
    line-height: 1.45;
    color: #27251E;
    background: #FAF8F5;
    border: 1px solid #E6E2DC;
    border-radius: 4px;
    padding: 10px 12px;
    margin: 0;
    white-space: pre-wrap;
    word-wrap: break-word;
    max-height: 360px;
    overflow-y: auto;
}
body.appbuilder-dark .builder-llm-test-text {
    background: var(--bg);
    color: var(--fg);
    border-color: var(--border);
}
.builder-llm-test-error {
    font-size: 12px;
    color: #C62828;
    padding: 8px 10px;
    background: #FFEBEE;
    border-radius: 4px;
    margin-bottom: 8px;
}
body.appbuilder-dark .builder-llm-test-error {
    background: rgba(198,40,40,0.15);
    color: #FF8A80;
}

/* ============================================================
   Synthetic Agent console (Builder_DirectorySyntheticAgent):
   left tab rail + swappable panel body inside a w2popup.
   ============================================================ */
/* Fill the w2popup body directly — a height:100% chain collapses
   because the popup body doesn't give a normal-flow child a definite
   height, leaving the layout host ~0px (blank panel). */
.synthagent_flex { position:absolute; inset:0; display:flex; flex-direction:row; box-sizing:border-box; }
/* Hosts the reused .builder-leftbar-home rail (same paradigm as the
   Directory / Admin / Tower Control leftbars) so the agent console
   doesn't introduce a new navigation style. */
.synthagent_railwrap {
	flex:0 0 190px; border-right:1px solid #e2e2e2; background:#F2F0EC;
	overflow-y:auto; padding:4px;
}
/* Picklist host (Builder_Workflow.AppendPickButton) — keep it from
   collapsing inside the flex server row / fields column. */
.synthagent_pick { display:inline-block; min-width:120px; }
.synthagent_srv_top .synthagent_pick { flex:0 0 90px; min-width:90px; }
.synthagent_fields .synthagent_pick { display:block; width:100%; margin-bottom:2px; }
.synthagent_body { flex:1 1 auto; min-width:0; overflow-y:auto; }
.synthagent_pane { padding:20px 24px; box-sizing:border-box; height:100%; display:flex; flex-direction:column; }

.synthagent_identity { display:flex; flex-direction:row; gap:24px; }
.synthagent_avatarcol { flex:0 0 150px; display:flex; flex-direction:column; align-items:center; gap:8px; }
.synthagent_avatarclear {
	border:0; background:none; color:#8a6cb1; cursor:pointer; font-size:12px; padding:2px 4px;
}
.synthagent_avatarclear:hover { text-decoration:underline; }

.synthagent_fields { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; }
.synthagent_fields_fill { height:100%; }
.synthagent_fields label { font-size:12px; font-weight:600; color:#555; margin:10px 0 4px; }
.synthagent_fields label:first-child { margin-top:0; }
.synthagent_fields input[type=text],
.synthagent_fields input[type=password],
.synthagent_fields textarea,
.synthagent_fields select {
	width:100%; box-sizing:border-box; padding:7px 9px; font-size:13px;
	border:1px solid #ccc; border-radius:4px; background:#fff; color:#1a1a1a;
}
.synthagent_fields textarea { resize:vertical; min-height:90px; }
#sa_descr { min-height:120px; }
.synthagent_fields_fill .synthagent_prompt { flex:1 1 auto; min-height:520px; resize:none; }
.synthagent_req { color:#C62828; }
.synthagent_help { font-size:11px; color:#888; margin:6px 0 0; font-weight:400; }
.synthagent_help code { background:#eee; padding:1px 4px; border-radius:3px; }

.synthagent_toolsbar { display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; }
.synthagent_check { font-size:12px; color:#444; display:inline-flex; align-items:center; gap:6px; }
.synthagent_servers { display:flex; flex-direction:column; gap:10px; margin-bottom:14px; }
.synthagent_srv { border:1px solid #ddd; border-radius:6px; padding:10px; background:#fbfbfb; display:flex; flex-direction:column; gap:7px; }
.synthagent_srv_top { display:flex; gap:8px; align-items:center; }
.synthagent_srv_top .sa_srv_name { flex:1 1 auto; }
.synthagent_srv input[type=text], .synthagent_srv input[type=password], .synthagent_srv select {
	padding:6px 8px; font-size:12px; border:1px solid #ccc; border-radius:4px; box-sizing:border-box;
}
.synthagent_srv .sa_srv_url { width:100%; }
.synthagent_srv_auth { display:flex; gap:8px; }
.synthagent_srv_auth select, .synthagent_srv_auth input { flex:1 1 auto; }
.synthagent_empty, .synthagent_placeholder {
	color:#999; font-size:13px; text-align:center; padding:30px 10px;
}
.synthagent_placeholder { display:flex; flex-direction:column; align-items:center; gap:10px; margin:auto; }
.synthagent_placeholder i { font-size:30px; color:#bbb; }
.synthagent_toollbl { font-size:12px; font-weight:600; color:#555; display:block; margin:4px 0 4px; }
.synthagent_allowed { width:100%; box-sizing:border-box; min-height:80px; padding:7px 9px;
	font-size:12px; font-family:monospace; border:1px solid #ccc; border-radius:4px; resize:vertical; }

body.appbuilder-dark .synthagent_railwrap { background:#1f1f1f; border-right-color:#333; }
body.appbuilder-dark .synthagent_check { color:#cfcfcf; }
body.appbuilder-dark .synthagent_fields label,
body.appbuilder-dark .synthagent_toollbl { color:#aab; }
body.appbuilder-dark .synthagent_fields input[type=text],
body.appbuilder-dark .synthagent_fields input[type=password],
body.appbuilder-dark .synthagent_fields textarea,
body.appbuilder-dark .synthagent_fields select,
body.appbuilder-dark .synthagent_allowed {
	background:#2a2a2a; color:#eee; border-color:#444;
}
body.appbuilder-dark .synthagent_srv { background:#242424; border-color:#3a3a3a; }
body.appbuilder-dark .synthagent_help code { background:#333; }

/* (stale fixed-height toollist rule removed — scrolling now lives on
   .synthagent_panelscroll; the list itself must grow freely) */
.synthagent_toolitem { font-size:12px; color:#444; padding:3px 6px; background:#f4f1ec; border-radius:3px; }
body.appbuilder-dark .synthagent_toolitem { background:#262626; color:#cfcfcf; }

/* Tools & MCP: two stacked, independently-scrolling sections */
.synthagent_toolspane { padding:14px 18px; gap:10px; }
.synthagent_section { display:flex; flex-direction:column; min-height:0; overflow-y:auto; }
.synthagent_toolspane .synthagent_section:first-child { flex:1 1 58%; }
.synthagent_section_tools { flex:1 1 42%; border-top:1px solid #e2e2e2; padding-top:8px; }
body.appbuilder-dark .synthagent_section_tools { border-top-color:#333; }

.synthagent_pulse { display:flex; gap:6px; margin:6px 0; }
.synthagent_pulse input { flex:1 1 auto; box-sizing:border-box; padding:6px 9px; font-size:13px; border:1px solid #ccc; border-radius:4px; }
.synthagent_pulse_results { display:flex; flex-direction:column; gap:4px; margin-bottom:8px; }
.synthagent_pulse_row, .synthagent_toolrow {
	display:flex; align-items:center; justify-content:space-between; gap:10px;
	padding:5px 8px; background:#f4f1ec; border-radius:4px;
}
.synthagent_toolmeta { display:flex; flex-direction:column; min-width:0; }
.synthagent_tooldesc { font-size:11px; color:#888; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.synthagent_toollist { display:flex; flex-direction:column; gap:4px; }
.synthagent_defpol { font-size:12px; color:#555; display:inline-flex; align-items:center; gap:6px; }
body.appbuilder-dark .synthagent_pulse input { background:#2a2a2a; color:#eee; border-color:#444; }
body.appbuilder-dark .synthagent_pulse_row,
body.appbuilder-dark .synthagent_toolrow { background:#242424; }
body.appbuilder-dark .synthagent_tooldesc { color:#9a9a9a; }
body.appbuilder-dark .synthagent_defpol { color:#cfcfcf; }

/* Tools & MCP — w2layout host (resizable horizontal split). */
#SynthAgentBody { position:relative; }
.synthagent_toolshost { width:100%; height:100%; }
#SynthAgentToolsHost .w2ui-panel-content { padding:0; overflow:hidden; position:absolute; inset:0; }
/* Absolute-fill the w2ui panel — height:100% alone fails because the
   panel-content wrapper isn't a definite-height block. */
.synthagent_panel { position:absolute; inset:0; display:flex; flex-direction:column; box-sizing:border-box; }
.synthagent_panelbar {
	flex:0 0 auto; padding:8px 12px; border-bottom:1px solid #e2e2e2;
	display:flex; flex-direction:column; gap:6px; background:#FAF8F5;
}
.synthagent_panelbar_row { flex-direction:row; align-items:center; justify-content:space-between; }
.synthagent_barrow { display:flex; gap:8px; }
.synthagent_panelscroll { flex:1 1 auto; min-height:0; overflow-y:auto; padding:8px 12px; }
body.appbuilder-dark .synthagent_panelbar { background:#222; border-bottom-color:#333; }

/* Tool-authorization state colouring on the picklist button */
.wf-pickbtn.sa_pol_allow   { border-color:#2e7d32; color:#2e7d32; background:rgba(46,125,50,0.08); }
.wf-pickbtn.sa_pol_deny    { border-color:#c62828; color:#c62828; background:rgba(198,40,40,0.08); }
.wf-pickbtn.sa_pol_default { color:#777; }
body.appbuilder-dark .wf-pickbtn.sa_pol_allow   { border-color:#66bb6a; color:#9ccc9e; background:rgba(102,187,106,0.14); }
body.appbuilder-dark .wf-pickbtn.sa_pol_deny    { border-color:#ef5350; color:#ef9a9a; background:rgba(239,83,80,0.14); }
body.appbuilder-dark .wf-pickbtn.sa_pol_default { color:#9a9a9a; }

/* Visible, grabbable splitter between the two Tools&MCP panels */
#SynthAgentToolsHost .w2ui-resizer { background:#e2e2e2; }
#SynthAgentToolsHost .w2ui-resizer:hover { background:#c9c9c9; }
body.appbuilder-dark #SynthAgentToolsHost .w2ui-resizer { background:#3a3a3a; }
body.appbuilder-dark #SynthAgentToolsHost .w2ui-resizer:hover { background:#4a4a4a; }
body.appbuilder-dark #SynthAgentToolsHost .w2ui-panel[type=main],
body.appbuilder-dark #SynthAgentToolsHost .w2ui-panel-main { border-top-color:#333 !important; }

/* Tool row: server-name chip + Test panel textareas */
.synthagent_toolsrv {
	font-size:10px; color:#fff; background:#8a6cb1; border-radius:3px;
	padding:1px 6px; align-self:flex-start; margin:1px 0 2px;
}
body.appbuilder-dark .synthagent_toolsrv { background:#5b4a85; }
/* Specificity must beat `.synthagent_fields textarea { min-height:90px }`
   (class+element), so qualify with element + extra class. */
.synthagent_fields textarea.synthagent_testio {
	width:100%; box-sizing:border-box; min-height:220px; resize:vertical;
	font-family:monospace; font-size:12px; padding:7px 9px;
	border:1px solid #ccc; border-radius:4px;
}
.synthagent_fields .synthagent_barrow { margin:14px 0 4px; }
#sa_test_out { background:#f7f7f5; }
body.appbuilder-dark .synthagent_testio { background:#2a2a2a; color:#eee; border-color:#444; }
body.appbuilder-dark #sa_test_out { background:#202020; }

/* ---------------------------------------------------------------
   Datarooms tab — per-app RAG corpora. Reuses .cp_cards_grid for
   the grid layout; everything below styles the dataroom-specific
   cards, pills, file-row, and detail header. Light + dark per the
   project rule that visual changes ship both themes together.
   --------------------------------------------------------------- */
.builder-datarooms-card {
	position: relative;
	background: #fff;
	border: 1px solid #e2e2e2;
	border-radius: 8px;
	padding: 14px 16px;
	display: flex;
	flex-direction: column;
	gap: 6px;
	min-height: 130px;
	transition: box-shadow 120ms ease, border-color 120ms ease;
}
.builder-datarooms-card:hover { border-color:#b9d7ff; box-shadow: 0 2px 10px rgba(33,84,166,0.08); }
.builder-datarooms-card-icon { color:#4a8fff; font-size:20px; }
.builder-datarooms-card-title { font-weight:600; font-size:14px; }
.builder-datarooms-card-desc { color:#666; font-size:12px; flex-grow:1; min-height:30px; }
.builder-datarooms-card-footer { display:flex; align-items:center; justify-content:space-between; margin-top:6px; }
.builder-datarooms-card-actions { display:flex; gap:10px; opacity:0; transition: opacity 100ms ease; }
.builder-datarooms-card:hover .builder-datarooms-card-actions { opacity:1; }
.builder-datarooms-card-actions i { color:#888; cursor:pointer; padding:4px; }
.builder-datarooms-card-actions i:hover { color:#2a6df0; }
.builder-datarooms-card-actions .builder-datarooms-card-delete:hover { color:#c44; }

.builder-datarooms-pill {
	display: inline-block;
	font-size: 11px;
	padding: 2px 8px;
	border-radius: 10px;
	font-weight: 600;
}
.builder-datarooms-pill-ready   { background:#e6f7ed; color:#0a7f3f; }
.builder-datarooms-pill-pending { background:#fff4d6; color:#946000; }
.builder-datarooms-pill-failed  { background:#fde2e2; color:#a82626; }
.builder-datarooms-pill-empty   { background:#eee;    color:#666; }

.builder-datarooms-file-row {
	display: grid;
	grid-template-columns: 1fr 180px 90px 30px;
	align-items: center;
	gap: 12px;
	padding: 10px 12px;
	border-bottom: 1px solid #eee;
}
.builder-datarooms-file-row:hover { background:#f7faff; }
.builder-datarooms-file-name { font-weight:500; }
.builder-datarooms-file-meta { color:#888; font-size:12px; }
.builder-datarooms-file-delete { color:#aaa; cursor:pointer; justify-self:center; }
.builder-datarooms-file-delete:hover { color:#c44; }

/* Dark mode overrides */
body.appbuilder-dark .builder-datarooms-root,
body.appbuilder-dark .builder-datarooms-detail { color:#ddd; }
body.appbuilder-dark .builder-datarooms-card {
	background:#262626; border-color:#3a3a3a;
}
body.appbuilder-dark .builder-datarooms-card:hover { border-color:#4a6fa5; box-shadow: 0 2px 10px rgba(0,0,0,0.4); }
body.appbuilder-dark .builder-datarooms-card-desc { color:#aaa; }
body.appbuilder-dark .builder-datarooms-card-actions i { color:#999; }
body.appbuilder-dark .builder-datarooms-pill-ready   { background:#1d3d2a; color:#7ed99c; }
body.appbuilder-dark .builder-datarooms-pill-pending { background:#3d3520; color:#e0c47a; }
body.appbuilder-dark .builder-datarooms-pill-failed  { background:#3d2020; color:#e87a7a; }
body.appbuilder-dark .builder-datarooms-pill-empty   { background:#333;    color:#aaa; }
body.appbuilder-dark .builder-datarooms-file-row { border-bottom-color:#333; }
body.appbuilder-dark .builder-datarooms-file-row:hover { background:#2a2f38; }
body.appbuilder-dark .builder-datarooms-file-meta { color:#888; }
body.appbuilder-dark .builder-datarooms-upload { border-color:#444; color:#aaa; }

/* Dataroom card swatch — centers a fa-icon inside the standard
   .applications_element_logo round mask. Light mode: soft blue
   wash with a blue glyph. Dark mode: solid blue swatch with a
   white glyph (inverted per user preference — better contrast
   against the darker card background). */
.dataroom_logo_swatch {
	display: flex;
	align-items: center;
	justify-content: center;
	background: #eef4ff;
	/* Default .applications_element_logo has overflow:hidden to clip
	   uploaded logo images to the round border-radius mask. Datarooms
	   use a centered fa-icon (no image), so we don't need the mask —
	   and the lock badge we anchor at (0,0) sits in the top-left
	   corner OUTSIDE the round area, which gets clipped if overflow
	   stays hidden. */
	overflow: visible;
}
.dataroom_logo_swatch > i {
	font-size: 20px;
	line-height: 1;
	color: #4a8fff;
}
body.appbuilder-dark .dataroom_logo_swatch {
	background: #4a8fff;
}
body.appbuilder-dark .dataroom_logo_swatch > i {
	color: #ffffff;
}

/* Dataroom card lock overlay — nudge 6px up and 6px left from the
   default .applications_element .user_card_lock_overlay position
   (6,6 → 0,0), so the badge sits in the top-left corner of the
   round swatch. The fa-database swatch sits flush against the disc,
   so the standard offset reads as too centered relative to other
   cards where the underlying image has its own padding. */
.applications_element .dataroom_logo_swatch .user_card_lock_overlay {
	top: 0;
	left: 0;
}

/* Dataroom "external rendering allowed" badge — a small rounded globe in
   the card's top-right corner. Mirrors .user_card_lock_overlay sizing;
   blue (matches the dataroom swatch) with a white globe = "may be sent to
   Claude's code-execution sandbox". */
.applications_element .dataroom_external_badge {
	position: absolute;
	top: 6px;
	right: 6px;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background: #4a8fff;
	color: #fff;
	font-size: 11px;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
	text-shadow: none;
	z-index: 3;
	pointer-events: auto;
}
body.appbuilder-dark .applications_element .dataroom_external_badge {
	background: #3b82f6;
	color: #ffffff;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

/* XLS viewer (legacy "excel:{json}" path in FilesClass.WebExcel).
   The SHEET CONTENT (cells + grid) stays workbook-defined regardless
   of the global theme — Excel cells carry their own fills + fonts and
   render on a white canvas. The surrounding chrome (xls_topbar with
   zoom controls, xls_tabs with the sheet-tab strip) is allowed to
   follow the global dark mode like every other builder surface.
   color-scheme:light on the sheet container makes the browser render
   its scrollbars in the light palette so they don't clash with the
   white canvas. */
/* Drop the 8px inset that ChapsV_AppROOMS.css puts on the container
   (left:8px; right:8px). That inset shows up as a visible gray
   margin around the white sheet and pushes the scrollbar away from
   the right edge — looks foreign next to the rest of the builder
   where panel scrollbars sit flush. !important because the ROOMS
   rule has same specificity (single class) so cascade order is
   load-dependent — being explicit avoids that fragility. */
.xls_sheet_container {
	left: 0 !important;
	right: 0 !important;
	/* top: flush against the 40px topbar (no gap).
	   bottom: 36px = 30px tabs height + 6px horizontal scrollbar
	   clearance. Anything tighter than +6 clips the bottom of the
	   horizontal scrollbar against the tabs strip. */
	top: 40px !important;
	bottom: 36px !important;
}

/* XLS scrollbars — pinned to the global light-mode look in BOTH
   themes. Deliberately NO `color-scheme: light` here: setting that on
   a child of `body.appbuilder-dark` triggers Chromium's hybrid OS
   scrollbar (with arrows). Just mirror the global builder rule
   verbatim and let Chromium's automatic "thin scrollbar → no arrows"
   behavior kick in. !important on every property to beat the global
   dark-mode override in w2ui.css (specificity 0,2,1). */
.xls_sheet_container::-webkit-scrollbar              { width: 6px !important; height: 6px !important; background: transparent !important; }
.xls_sheet_container::-webkit-scrollbar-track        { background: transparent !important; }
.xls_sheet_container::-webkit-scrollbar-track:hover  { background: #F0F0F0 !important; border-radius: 4px !important; }
.xls_sheet_container::-webkit-scrollbar-thumb        { background: #DBD9D4 !important; border-radius: 3px !important; }
.xls_sheet_container::-webkit-scrollbar-thumb:hover  { background: #0B99DF !important; }

/* Pin the sheet canvas (background + default text color) to the
   light-mode look in dark mode. The rule lives on the container ONLY:
   children inherit the default color and any cell that has its own
   workbook-defined color class (`.x21`, `.fN`, etc. emitted inline by
   the JS at sheet-render time) wins via cascade specificity. Targeting
   `.xls_sheet span` directly here would have higher specificity than
   the JS-emitted `.x21` classes and would clobber the workbook colors
   — which is exactly the bug we're avoiding. */
body.appbuilder-dark .xls_sheet_container {
	background: #fff !important;
	color: #000 !important;
}

/* ================================================================
 * UI Design mode — visual clues used while the user is rearranging
 * components inside a TEST session. All editing affordances share
 * the Claude-logo --ui-design-color (orange) so the same hue means
 * "you can change this" everywhere in the builder. Affordances are
 * gated on body.appbuilder-uidesign so they vanish the moment the
 * user flips the toggle back to test mode.
 * ================================================================ */

/* Insertion-point button — orange dashed border. Reused wherever a
   new visual slot can be opened (home leftbar, future tab strips,
   dashboard rows, …). Hidden outside UI design mode. */
/* div.insertion-point (not bare .insertion-point) so the selector
   specificity wins against `.builder-leftbar-home div` (0,1,1) and
   the dark-mode rule `body.appbuilder-dark .builder-leftbar-home div`
   (0,2,1) which both carry !important on color and would otherwise
   force the label back to the neutral leftbar color. */
div.insertion-point {
	display: none;
	box-sizing: border-box;
	border: 1px dashed var(--ui-design-color);
	border-radius: 6px;
	color: var(--ui-design-color) !important;   /* label text in Claude orange */
	background-color: transparent;
	font-family: OpenSans;
	font-size: 13px;
	font-weight: 600;
	text-align: center;
	cursor: pointer;
	user-select: none;
	/* asymmetric padding shifts the centered "+ Add Panel" pair 16px
	   to the left of the geometric center: (40 − 8) / 2 = 16px. */
	padding: 6px 40px 6px 8px;
	transition: background-color 0.15s ease, color 0.15s ease;
}
/* !important on background because the leftbar's own hover rule
   (.builder-leftbar-home div:hover in light, the dark-mode variant
   with !important in dark) would otherwise win on specificity. */
div.insertion-point:hover {
	background-color: rgba(217,119,87,0.15) !important;
}
body.appbuilder-dark div.insertion-point:hover {
	background-color: rgba(217,119,87,0.22) !important;
}
div.insertion-point > i.fa {
	margin-right: 2px;                          /* + and label nearly touching */
	color: var(--ui-design-color);
}
body.appbuilder-uidesign div.insertion-point {
	display: block;
}
/* Keep the orange label in dark mode AND on hover — the leftbar's
   own hover rule (body.appbuilder-dark .builder-leftbar-home div:hover)
   forces color to var(--fg-strong) with !important, so we override
   both states explicitly. */
body.appbuilder-dark div.insertion-point,
body.appbuilder-dark div.insertion-point:hover {
	color: var(--ui-design-color) !important;
}
body.appbuilder-dark div.insertion-point > i.fa {
	color: var(--ui-design-color) !important;
}

/* Variant: the home leftbar's Add Panel button. Tighter margins so
   it nests cleanly under My Calendar / pinned dashboards. */
.builder-leftbar-home .insertion-point-addpanel {
	margin: 6px 2px 4px 2px;
}

/* --------------------------------------------------------------
 * Generic design-mode pattern for EXISTING components (as opposed
 * to dedicated DESIGN buttons like .insertion-point which are
 * always visible):
 *
 *   - No persistent visual chrome on the component itself; the
 *     dashed orange outline appears only on :hover.
 *   - Inline edit commands (move, remove, settings …) sit in the
 *     upper-right corner of the component, absolutely positioned,
 *     also revealed on :hover. They are allowed to overlap the
 *     content text if it's too long — that's preferable to
 *     reserving permanent padding for affordances most users
 *     never need.
 *
 * Hook future component classes into the same pattern by
 * positioning them relative in design mode and dropping
 * .design-corner-handle / .design-corner-action children inside.
 * -------------------------------------------------------------- */

/* Position context for the absolutely-placed edit commands. Only
   apply in design mode so non-edit mode keeps the simple flow
   layout from the base leftbar rules. */
body.appbuilder-uidesign .builder-leftbar-home > div[data-panel] {
	position: relative;
}

/* Dashed orange outline only on hover (existing components don't
   carry permanent chrome — see comment above). */
body.appbuilder-uidesign .builder-leftbar-home > div[data-panel]:hover {
	outline: 1px dashed var(--ui-design-color);
	outline-offset: -2px;
}

/* Move handle — upper-right of the row, hidden until hover. The
   width and color matter only when revealed; the default rule
   keeps it out of flow at all times. */
.builder-leftbar-home-handle {
	display: none;
	position: absolute;
	top: 4px;
	right: 6px;
	color: var(--ui-design-color);
	cursor: grab;
	pointer-events: auto;
	font-size: 12px;
	line-height: 1;
}
body.appbuilder-uidesign .builder-leftbar-home > div[data-panel]:hover .builder-leftbar-home-handle {
	display: inline-block;
}

/* Per-row edit affordances for custom panels — pen (edit title /
   description) and x (remove). Both sit absolutely positioned to
   the upper-right of the row, hidden until hover. Order from right
   to left: ⠿ move (handle) at right:6, × remove at right:22, ✎ edit
   at right:38. */
.builder-leftbar-home-remove,
.builder-leftbar-home-edit {
	display: none;
	position: absolute;
	top: 4px;
	color: var(--ui-design-color);
	cursor: pointer;
	opacity: 0.75;
	font-size: 12px;
	line-height: 1;
}
.builder-leftbar-home-remove        { right: 22px; }
.builder-leftbar-home-edit          { right: 38px; }
.builder-leftbar-home-remove:hover,
.builder-leftbar-home-edit:hover    { opacity: 1; }
body.appbuilder-uidesign .builder-leftbar-home > div[data-panel][data-custom='1']:hover .builder-leftbar-home-remove,
body.appbuilder-uidesign .builder-leftbar-home > div[data-panel][data-custom='1']:hover .builder-leftbar-home-edit {
	display: inline-block;
}

/* Reorderable built-in leftbar items keep their normal hover
   background (gray in light, var(--bg-hover) in dark). Only the
   .insertion-point "Add Panel" button uses the orange hover —
   that's the affordance that signals "click to add", not the
   existing rows. */

/* DnD feedback. The placeholder is a real DOM node inserted at the
   live drop position so the user can see exactly where the row will
   land; the dragged source is dimmed but kept in place so its
   absence isn't disorienting. */
/* Source row hidden during drag so only the placeholder marks the
   landing slot — no visual duplication with the drag-image ghost.
   The class is added in setTimeout(0) inside dragstart so the
   browser's drag-image snapshot captures the visible row first. */
.builder-leftbar-home-dragging {
	display: none !important;
}
.builder-leftbar-home-placeholder {
	box-sizing: border-box;
	margin: 2px;
	border: 1px dashed var(--ui-design-color);
	border-radius: 4px;
	background-color: rgba(217,119,87,0.15);
}

/* Default custom-panel content shell. No padding — the inner
   w2layout fills the whole tab content area edge-to-edge. */
.builder_custompanel_container {
	width: 100%;
	height: 100%;
	overflow: hidden;
	box-sizing: border-box;
	padding: 0;
	font-family: OpenSans;
}
.builder_custompanel_dummy {
	max-width: 720px;
	margin: 40px auto;
	border: 1px dashed var(--ui-design-color);
	border-radius: 8px;
	padding: 32px;
	text-align: center;
	background-color: rgba(217,119,87,0.04);
}
.builder_custompanel_dummy_title {
	font-size: 18px;
	font-weight: 600;
	color: var(--ui-design-color);
	margin-bottom: 8px;
}
.builder_custompanel_dummy_desc {
	font-size: 14px;
	color: #4a4a4a;
	margin-bottom: 12px;
	white-space: pre-wrap;
}
body.appbuilder-dark .builder_custompanel_dummy_desc { color: #d0d0d0; }
.builder_custompanel_dummy_body {
	font-size: 14px;
	color: #6b6b6b;
}
body.appbuilder-dark .builder_custompanel_dummy_body { color: #c8c8c8; }
body.appbuilder-dark .builder_custompanel_dummy        { background-color: rgba(217,119,87,0.10); }

/* ================================================================
 * Builder_BaseCustomPanel — visual chrome for the inner w2layout
 * shell (top / left / right / main subpanels), the design-mode
 * toolbar, and the default block rectangles.
 * ================================================================ */
.custompanel_shell { position: relative; width: 100%; height: 100%; }
.custompanel_layout_host {
	position: absolute;
	inset: 0;
}

/* Edge chips — small "+" pills, one per DISABLED optional subpanel.
   Hidden by default; revealed when the user hovers the shell in
   design mode. Click adds that subpanel. Keeps the surface clean
   when the user isn't actively configuring. */
.custompanel_chips {
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 9999;
}
.custompanel_chip { z-index: 9999; }
/* Phantom-resizer strips along each edge where a subpanel could be
   added. Mimics the orange-dashed look of the real w2layout resizer
   (used between enabled panels) so the user reads it as "drag this
   to bring in a panel from this edge". Click anywhere on the strip
   enables that subpanel.

   IDLE  : thin (4px) faintly orange dashed bar.
   HOVER : grows to 8px, brighter, plus a centered + glyph appears.
   Hidden entirely outside design mode. */
/* Phantom-resizer strips along each edge where a subpanel could be
   added. Same orange dashed look as the real w2layout resizer
   between enabled panels — "click this strip to bring a panel in
   from this edge". Solid 12px strip, always visible in design mode
   (5px / 0.10 opacity was below the threshold of perception on
   dark backgrounds — confirmed by user).
   Idle:  12px, dashed border, faint background, a centered + glyph.
   Hover: 18px, brighter, + becomes bigger. */
/* Solid Claude-orange chip with a white + glyph — paints OVER the
   panel border (z-index 9999, non-transparent background) so it
   reads as a clickable affordance rather than blending into the
   layout. */
.custompanel_chip {
	position: absolute;
	pointer-events: auto;
	cursor: pointer;
	display: none;
	background-color: var(--ui-design-color);
	color: white;
	font-size: 11px;
	font-weight: 700;
	line-height: 1;
	text-align: center;
	transition: filter 0.12s ease;
	z-index: 9999;
	box-sizing: border-box;
	box-shadow: 0 1px 3px rgba(0,0,0,0.18);
}
body.appbuilder-uidesign .custompanel_chip {
	display: flex;
	align-items: center;
	justify-content: center;
}

/* Drawer-style handles — fixed-size, centered on each edge. Far
   less intrusive than full-edge strips while still clearly orange
   "+ add a panel here" affordances. Same size in idle and hover —
   only the background brightens on hover. */
/* Drawer-style chips sit flush against each edge — fully inside
   the shell so the parent .builder_custompanel_container's
   overflow:hidden doesn't clip them in half. The solid Claude-
   orange background + shadow already make them read as sitting
   "on top of" the boundary even without negative offsets. */
.custompanel_chip_top {
	top: 0;
	left: 50%;
	transform: translateX(-50%);
	width: 56px;
	height: 14px;
	border-bottom-left-radius: 7px;
	border-bottom-right-radius: 7px;
}
.custompanel_chip_left,
.custompanel_chip_right {
	top: 50%;
	transform: translateY(-50%);
	width: 14px;
	height: 56px;
}
.custompanel_chip_left {
	left: 0;
	border-top-right-radius: 7px;
	border-bottom-right-radius: 7px;
}
.custompanel_chip_right {
	right: 0;
	border-top-left-radius: 7px;
	border-bottom-left-radius: 7px;
}
.custompanel_chip:hover { filter: brightness(1.10); }
.custompanel_chip > i.fa { font-size: 11px; }

/* w2layout resizer styling.
     TEST mode: thin neutral divider line — matches the panel
     borders we use on entry forms.
     DESIGN mode: solid Claude-orange (resizer is ~5px so a stripe
     pattern wasn't visible) — also the visual cue that the
     boundary is draggable. */
/* Panel-level borders intentionally removed — the separator is
   painted on the resizer element below (see .w2ui-resizer::before
   rules), which sits in the natural gap between panels and isn't
   covered by anything. */
/* Diagnostic proved background-color is being clobbered by an
   inline style on .w2ui-resizer (probably w2ui itself), so even
   `!important` loses. Use box-shadow inset — w2ui doesn't touch
   it and a single 100px spread fills the whole resizer regardless
   of its width / height / orientation. Works for top, left, AND
   right resizers without any per-orientation overrides. */
/* Default state: nothing painted on the resizer itself — the
   adjacent .custompanel_subpanel's dashed orange outline already
   marks the boundary, so an additional inset edge would just
   produce two parallel solid lines bracketing the dashes.
   Hover (also stays during drag, since the cursor remains on the
   resizer): fills the entire resizer with the Claude-orange. */
body.appbuilder-uidesign .custompanel_layout_host .w2ui-resizer:hover {
	box-shadow: inset 0 0 0 100px var(--ui-design-color) !important;
}

/* Floating size badge — shown while the user is dragging a w2ui
   resizer inside a custom panel; hides on mouseup. */
.custompanel_resize_badge {
	position: fixed;
	display: none;
	z-index: 10000;
	padding: 4px 8px;
	border-radius: 4px;
	background-color: var(--ui-design-color);
	color: white;
	font-family: OpenSans;
	font-size: 12px;
	pointer-events: none;
	box-shadow: 0 1px 4px rgba(0,0,0,0.30);
}
.custompanel_resize_badge.visible { display: block; }

/* Per-subpanel mini toolbar — top-right of every enabled subpanel
   in design mode. Label / type pill / close ×. Same visual
   language as everywhere else (Claude orange, dashed border on the
   type pill, no chrome on labels). */
/* Type chip — INSIDE the panel at top-left. Always visible while
   in design mode (no `:hover` gate). The hover gate caused two
   problems: (1) cursor exiting the panel onto the popup menu hid
   the chip → w2menu lost its anchor → menu jumped to (0,0); (2)
   the chip flickered when crossing the panel border. Always-on
   visibility is fine — the chip only paints in design mode at
   all, and it's small (single orange pill at the corner). */
.custompanel_subpanel_bar {
	display: none;
	position: absolute;
	top: 4px;
	left: 4px;
	z-index: 200;
	gap: 6px;
	align-items: center;
	padding: 0;
	font-family: OpenSans;
	font-size: 11px;
	line-height: 1;
}
body.appbuilder-uidesign .custompanel_subpanel_bar {
	display: inline-flex;
}

/* Remove × — top-right INSIDE the panel (same place every other
   "remove" affordance lives in this codebase). Shown only on
   panel hover in design mode, and emitted by JS only when the
   subpanel is empty (so closing it can't happen by accident
   while there are still blocks). */
.custompanel_subpanel_closex {
	display: none;
	position: absolute;
	top: 4px;
	right: 6px;
	z-index: 200;
	width: 18px;
	height: 18px;
	line-height: 18px;
	text-align: center;
	font-size: 12px;
	color: white;
	background: var(--ui-design-color);
	border-radius: 4px;
	cursor: pointer;
	box-shadow: 0 1px 3px rgba(0,0,0,0.20);
}
.custompanel_subpanel_closex:hover { filter: brightness(1.08); }
body.appbuilder-uidesign .custompanel_layout_host .w2ui-panel:hover > .custompanel_subpanel_closex {
	display: inline-block;
}
.custompanel_subpanel_bar_label {
	color: var(--ui-design-color);
	font-weight: 600;
	user-select: none;
}
/* Type chip — solid Claude-orange pill that opens a w2menu with
   the three layout-type choices on click. Full border, full
   background, white label. No tooltip (the menu communicates the
   purpose by opening below the chip). */
.custompanel_subpanel_bar_type {
	color: white;
	background-color: var(--ui-design-color);
	border: 1px solid var(--ui-design-color);
	border-radius: 4px;
	padding: 3px 8px;
	cursor: pointer;
	user-select: none;
}
.custompanel_subpanel_bar_type:hover { filter: brightness(1.08); }
.custompanel_subpanel_bar_close {
	color: var(--ui-design-color);
	cursor: pointer;
	padding: 2px 4px;
	font-size: 12px;
}
.custompanel_subpanel_bar_close:hover { opacity: 1; }

/* Subpanels — w2layout's panel content owns layout sizing, we
   just style the inner container. */
.custompanel_subpanel {
	box-sizing: border-box;
	position: relative;             /* anchor for absolute toolbar / Add-Block button */
	width:  100%;
	height: 100%;
	overflow: auto;
	padding: 0;
}
/* Separator painted on the subpanel container itself (inside the
   w2ui panel content area) — guaranteed visible regardless of
   where w2layout decides to place its resizer element. Border is
   on the side of the subpanel facing main, so each visible edge
   gets exactly one line (no doubling, no gaps from resizer
   positioning, no missing right separator).

   TEST  mode: solid neutral gray.
   DESIGN mode: dashed Claude-orange (the user already established
   this is the right visual for design boundaries). */
.custompanel_subpanel[data-subpanel='top']    { border-bottom: 1px solid #d0d0d0; }
.custompanel_subpanel[data-subpanel='left']   { border-right:  1px solid #d0d0d0; }
.custompanel_subpanel[data-subpanel='right']  { border-left:   1px solid #d0d0d0; }
body.appbuilder-uidesign .custompanel_subpanel[data-subpanel='top']    { border-bottom: 1px dashed #D97757 !important; }
body.appbuilder-uidesign .custompanel_subpanel[data-subpanel='left']   { border-right:  1px dashed #D97757 !important; }
body.appbuilder-uidesign .custompanel_subpanel[data-subpanel='right']  { border-left:   1px dashed #D97757 !important; }
body.appbuilder-dark .custompanel_subpanel[data-subpanel='top']    { border-bottom-color: #3a3a3a; }
body.appbuilder-dark .custompanel_subpanel[data-subpanel='left']   { border-right-color:  #3a3a3a; }
body.appbuilder-dark .custompanel_subpanel[data-subpanel='right']  { border-left-color:   #3a3a3a; }

/* Default block rectangle — placeholder for any future BlockClass
   subtype. Solid border in test mode, dashed orange in design. */
.custompanel_block {
	box-sizing: border-box;
	border: 1px solid #d0d0d0;
	background-color: #fafafa;
	border-radius: 4px;
	overflow: hidden;
}
/* Block class-specific widget mounts here. Fills the block. */
.custompanel_block_content {
	position: absolute;
	inset: 0;
	overflow: hidden;
}

/* Chart block — reuses Builder_Dashboard internally for rendering
   + the Edit Widget popup, but the block IS the container.
   We keep the dashboard's per-widget header (title, edit/delete
   handles) so the chart matches the look used inside a real
   dashboard. We strip the OUTER dashboard chrome (w2layout
   toolbar, chat / preview panels, gridstack padding & extra
   height) and force the single component to fill the block.
   Block-level resize handles drive block.w / block.h.

   w2ui's panel element only has class="w2ui-panel" — the panel
   type (top/main/right/…) is encoded in the id, hence the
   attribute-suffix selectors instead of class selectors. */
.custompanel_block_content [id$='_panel_top'],
.custompanel_block_content [id$='_panel_preview'],
.custompanel_block_content [id$='_panel_right'] {
	display: none !important;
}
.custompanel_block_content [id$='_panel_main'] {
	top: 0 !important; bottom: 0 !important;
	left: 0 !important; right:  0 !important;
	overflow: hidden !important;
}
/* Same chrome strip the chat-inline chart use applies (see
   .builder-thread-chart-host rules), adapted to our container.
   Removes the 12px gridstack padding + min-height/auto-height
   that produced the bottom black bar, and clamps overflow so the
   side scrollbar ("elevator") never appears. */
.custompanel_block_content .builder-dashboard-components {
	overflow: hidden !important;
	padding: 0 !important;
	height: 100% !important;
}
.custompanel_block_content .builder-dashboard-components,
.custompanel_block_content .builder-dashboard-surface {
	width:  100% !important;
	height: 100% !important;
	margin: 0 !important;
	padding: 0 !important;
	min-height: 0 !important;
}
.custompanel_block_content .builder-dashboard-widget {
	position: absolute !important;
	inset: 0 !important;
	width:  100% !important;
	height: 100% !important;
	transform: none !important;
	top:    0 !important;
	left:   0 !important;
}
.custompanel_block_content .builder-dashboard-component {
	width: 100%;
	height: 100%;
	/* Include the 1px border in the height — without `border-box`
	   the component is 2px taller than its parent (1px top + 1px
	   bottom border on default content-box), overflows the grid-
	   stack-item-content by 2px and triggers a vertical scrollbar. */
	box-sizing: border-box !important;
}
/* Body inherits the dashboard's natural flex:1 from
   .builder-dashboard-component-body (column flex layout: header
   at top, body fills remaining). Overriding to absolute/inset:0
   here would make the body overlap the header AND prevent it
   from inheriting the component's full computed height — which
   produced both the bottom black band and ECharts being told a
   too-small height at init time. */
.custompanel_block_content .builder-dashboard-chart-host {
	width:  100%;
	height: 100%;
}
/* No edit affordances in read-only custom-panel embeds. */
.custompanel_block_content .builder-dashboard-rz {
	display: none !important;
}

/* "New entry" block — fills the block area; w2form owns the
   internal layout (page on top + actions bar at the bottom),
   which is what makes its .w2ui-page scroller behave (same
   pattern as Builder_Object.BulkUpdateHTML). */
.custompanel_newentry_form {
	position: absolute;
	inset: 0;
	overflow: hidden;
}
.custompanel_newentry_form > .w2ui-form {
	width:  100%;
	height: 100%;
}
/* Dark-mode header styling (matches the Bulk Edit topbar tone
   so the form's optional title doesn't render as a white stripe
   on a dark page). */
body.appbuilder-dark .custompanel_newentry_form .w2ui-form-header {
	background-color: var(--bg) !important;
	color: var(--fg-strong) !important;
	border-bottom-color: var(--border) !important;
}
body.appbuilder-dark .custompanel_block {
	border-color: #3a3a3a;
	background-color: #1f1f1f;
}
/* In design mode the orange dashed treatment is HOVER-only — at
   rest blocks look the same as in test mode so the surface stays
   clean. Hover reveals the orange dashed border + tinted fill +
   move cursor. */
body.appbuilder-uidesign .custompanel_block:hover {
	border: 1px dashed var(--ui-design-color);
	background-color: rgba(217,119,87,0.10);
	cursor: move;
}
body.appbuilder-dark.appbuilder-uidesign .custompanel_block:hover {
	border-color: var(--ui-design-color);
	background-color: rgba(217,119,87,0.18);
}
.custompanel_block_remove {
	display: none;
	position: absolute;
	top: 2px;
	right: 4px;
	color: var(--ui-design-color);
	cursor: pointer;
	font-size: 12px;
	line-height: 1;
	z-index: 1000;
}
body.appbuilder-uidesign .custompanel_block:hover .custompanel_block_remove {
	display: inline-block;
}

/* Edit pen — block-class-specific settings popup. Sits to the
   left of the × in the upper-right; same hover visibility rule
   so both reveal together in design mode. */
.custompanel_block_edit {
	display: none;
	position: absolute;
	top: 2px;
	right: 22px;
	color: var(--ui-design-color);
	cursor: pointer;
	font-size: 12px;
	line-height: 1;
	z-index: 1000;
}
body.appbuilder-uidesign .custompanel_block:hover .custompanel_block_edit {
	display: inline-block;
}

/* Block resize handles. Three variants:
   .custompanel_block_resize_r  — right edge (width drag, ew-resize)
   .custompanel_block_resize_b  — bottom edge (height drag, ns-resize)
   .custompanel_block_resize_br — bottom-right corner (both, nwse-resize)
   Hidden outside design mode and outside the block's hover state. */
.custompanel_block_resize {
	display: none;
	position: absolute;
	background: var(--ui-design-color);
	opacity: 0.40;
	z-index: 1000;
}
body.appbuilder-uidesign .custompanel_block:hover .custompanel_block_resize {
	display: block;
}
.custompanel_block_resize:hover { opacity: 0.85; }

.custompanel_block_resize_r {
	right:  0;
	top:    6px;
	bottom: 6px;
	width:  4px;
	cursor: ew-resize;
}
.custompanel_block_resize_b {
	bottom: 0;
	left:   6px;
	right:  6px;
	height: 4px;
	cursor: ns-resize;
}
.custompanel_block_resize_br {
	right:  0;
	bottom: 0;
	width:  10px;
	height: 10px;
	cursor: nwse-resize;
	border-radius: 0 0 4px 0;
}

/* DnD reorder feedback in stack mode. Source is REMOVED from flow
   (display:none) so the remaining blocks collapse and the
   placeholder phantom takes the open slot — matches the home
   leftbar reorder behavior; visibility:hidden left a fixed gap
   that broke the visual. */
.custompanel_block_dragging {
	display: none !important;
}
.custompanel_block_placeholder {
	box-sizing: border-box;
	border: 1px dashed var(--ui-design-color);
	background-color: rgba(217,119,87,0.15);
	border-radius: 4px;
}

/* "Add Block" insertion-point inside each subpanel — smaller than
   the leftbar variant since it sits inside a working canvas.
   No external margin: the container's `padding: 6px + gap: 6px`
   already gives it the same gutter as blocks, so the button
   left-aligns with whatever block(s) sit above it. */
.insertion-point.insertion-point-block {
	margin: 0;
	padding: 6px 12px;
	min-width: 120px;
	display: none;
}
body.appbuilder-uidesign .insertion-point.insertion-point-block {
	display: inline-flex;
	align-items: center;
	justify-content: center;
}
/* In the top horizontal-stack panel, vertically center the button
   in the row (blocks take the full row height; without this the
   button anchored to flex-start would float at the top edge). */
.custompanel_subpanel[data-subpanel='top'] .insertion-point.insertion-point-block {
	align-self: center;
}
.insertion-point-block-label {
	margin-left: 6px;
	color: var(--ui-design-color);
	font-weight: 600;
	font-size: 12px;
}
/* In an absolute subpanel the insertion-point should anchor to the
   bottom-left so it doesn't overlap floating blocks. */
body.appbuilder-uidesign .custompanel_subpanel_absolute .insertion-point.insertion-point-block {
	position: absolute;
	bottom: 8px;
	left:   8px;
	margin: 0;
}

/* ================================================================
 * Main sidebar — design-mode affordances on the middle gallery.
 * Same pattern as the home leftbar (dashed outline on hover, edit
 * commands absolute-positioned in the corner, only visible in UI
 * design mode), adapted for the narrow 48px sidebar column.
 * ================================================================ */
body.appbuilder-uidesign #galleryTrack > .leftbar_item {
	position: relative;
}
/* Orange dashed border on hover in design mode. We swap the
   reserved 1px transparent border for an orange dashed one so the
   layout doesn't shift, and bump specificity + !important so it
   beats the leftbar_item:hover rule (which sets border-color and
   background). Outline isn't used because the gallery container
   has overflow:hidden and would clip it. */
body.appbuilder-uidesign #galleryTrack > .leftbar_item:hover {
	border-color: var(--ui-design-color) !important;
	border-style: dashed !important;
	background-color: rgba(217,119,87,0.10) !important;
	color: inherit !important;
}

/* Edit pen + remove × pills. Both anchored to the upper-right
   corner of the item (matches the home-leftbar pattern of "edit
   commands cluster on the right"), no background — just the orange
   glyph — so the row stays clean. Pen is further from the edge,
   × is right at the edge. */
/* EXPANDED state: items become full-width rows (see
   #mySidebar.sidebar-expanded .leftbar_item), so we mirror the
   home-leftbar pattern exactly — handle (⠿) at right:6, remove (×)
   at right:22, edit (✎) at right:38, top:4, 12px Claude-orange
   glyphs, no background. Shown on hover in design mode.

   COLLAPSED state: items are 36×36 inside a 48px column. There's
   no room for these icons in the row, and the gallery's
   overflow:hidden would clip anything we'd render outside. The
   inline icons are kept hidden in this state; the same actions are
   surfaced by a body-level flyout (see .leftbar_action_flyout
   below + Builder_ShowSidebarActionFlyout in JS). */
.leftbar_item_handle,
.leftbar_item_remove,
.leftbar_item_edit {
	display: none;
	position: absolute;
	top: 4px;
	font-size: 12px;
	line-height: 1;
	color: var(--ui-design-color);
	cursor: pointer;
	z-index: 2;
	background: transparent;
	opacity: 0.85;
}
.leftbar_item_handle        { right: 6px;  cursor: grab; }
.leftbar_item_remove        { right: 22px; }
.leftbar_item_edit          { right: 38px; }
.leftbar_item_handle:hover,
.leftbar_item_remove:hover,
.leftbar_item_edit:hover    { opacity: 1; }

/* The base `.leftbar_item i { padding: 4px }` rule would balloon
   these glyphs out of their wrappers. Zero the inherited padding
   so they render cleanly at 12px. */
.leftbar_item_remove > i.fa,
.leftbar_item_edit   > i.fa,
.leftbar_item_handle > i.fa {
	padding: 0 !important;
}

body.appbuilder-uidesign #mySidebar.sidebar-expanded #galleryTrack > .leftbar_item:hover .leftbar_item_handle,
body.appbuilder-uidesign #mySidebar.sidebar-expanded #galleryTrack > .leftbar_item:hover .leftbar_item_remove,
body.appbuilder-uidesign #mySidebar.sidebar-expanded #galleryTrack > .leftbar_item:hover .leftbar_item_edit {
	display: inline-block;
}

/* Body-level flyout used in COLLAPSED design mode — positioned to
   the right of the hovered item by JS via getBoundingClientRect,
   same pattern as .leftbar_tooltip. Hidden by default; .visible
   toggles a flex layout. The same DOM node is reused across items
   — JS rewires its data-key and toggles `.no-edit` when the item
   isn't a custom panel. */
.leftbar_action_flyout {
	position: fixed;
	transform: translateY(-50%);
	display: none;
	z-index: 1000;
	padding: 5px 8px;
	border-radius: 6px;
	background-color: rgba(255,255,255,0.96);
	box-shadow: 0 2px 6px rgba(0,0,0,0.18);
	border: 1px solid rgba(217,119,87,0.30);
	gap: 12px;
	align-items: center;
	font-size: 13px;
	line-height: 1;
}
.leftbar_action_flyout.visible {
	display: flex;
}
.leftbar_action_flyout > span {
	color: var(--ui-design-color);
	cursor: pointer;
	opacity: 0.85;
}
.leftbar_action_flyout > span:hover { opacity: 1; }
.leftbar_action_flyout > .leftbar_action_flyout_handle { cursor: grab; }
.leftbar_action_flyout.no-edit > .leftbar_action_flyout_edit { display: none; }

body.appbuilder-dark .leftbar_action_flyout {
	background-color: rgba(40,40,40,0.96);
	border-color: rgba(217,119,87,0.45);
}

/* DnD feedback in the sidebar gallery — same placeholder concept
   as the home leftbar so the user gets a consistent "phantom slot"
   landing cue. */
.leftbar_item_dragging { display: none !important; }
/* Match the .leftbar_item box exactly so swapping item ↔ placeholder
   never changes the column's vertical layout. The earlier 4px
   vertical margin (vs item's 10px) was responsible for the
   "everything shifts up when I start dragging the first item" bug:
   the placeholder took up 12px less Y than the item it replaced. */
.leftbar_item_placeholder {
	box-sizing: border-box;
	width: 36px;
	height: 36px;
	margin: 10px 6px;
	border: 1px dashed var(--ui-design-color);
	border-radius: 4px;
	background-color: rgba(217,119,87,0.15);
}
#mySidebar.sidebar-expanded .leftbar_item_placeholder {
	width: calc(100% - 12px);
}

/* Add Panel insertion-point in the gallery — narrower than the
   home-leftbar variant since the column is 48px wide. Visible only
   in UI design mode (via .insertion-point's body-class gate). */
.insertion-point.insertion-point-sidebar-addpanel {
	margin: 6px 6px;
	padding: 6px 0;
	text-align: center;
	display: none;                       /* base .insertion-point already hides */
	overflow: hidden;
	white-space: nowrap;
}
body.appbuilder-uidesign .insertion-point.insertion-point-sidebar-addpanel {
	display: block;
}
.insertion-point.insertion-point-sidebar-addpanel > i.fa {
	margin: 0;
	font-size: 14px;
}
/* Label appears only when the sidebar is in its expanded state.
   #mySidebar carries the .sidebar-expanded class (see
   Builder_SetSidebarExpanded), so this rule scopes the label
   to that state. */
.insertion-point.insertion-point-sidebar-addpanel .insertion-point-sidebar-label {
	display: none;
	margin-left: 6px;
	font-family: OpenSans;
	font-size: 13px;
	font-weight: 600;
	color: var(--ui-design-color);
}
#mySidebar.sidebar-expanded .insertion-point.insertion-point-sidebar-addpanel .insertion-point-sidebar-label {
	display: inline-block;
}

/* ============================================================
   Demo Database Populator — Admin ▸ Tables ▸ Demo Data (4th tab).
   Kept self-contained under .demo_panel so removing the panel
   later is a single grep. Both light and dark modes (per the
   feedback_ui_conventions memory).
   ============================================================ */
.demo_panel {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	font-family: OpenSans;
	background: #fafafa;
	color: #222;
	box-sizing: border-box;
}
.demo_toolbar {
	padding: 10px 12px;
	border-bottom: 1px solid #e2e2e2;
	background: #fff;
	flex-shrink: 0;
}
.demo_toolbar_row {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
}
.demo_lbl {
	font-size: 12px;
	color: #555;
	font-weight: 600;
}
.demo_globalprompt {
	flex: 1 1 260px;
	min-width: 200px;
	padding: 5px 8px;
	border: 1px solid #ccc;
	border-radius: 4px;
	font-family: OpenSans;
	font-size: 12px;
	background: #fff;
	color: #222;
}
.demo_generate_btn {
	padding: 6px 14px;
	background: #3c6e8f;
	color: #fff;
	border: 0;
	border-radius: 4px;
	font-family: OpenSans;
	font-size: 12px;
	font-weight: 600;
	cursor: pointer;
}
.demo_generate_btn:hover:not(:disabled) { background: #2f5972; }
.demo_generate_btn:disabled            { background: #9fb6c2; cursor: not-allowed; }

.demo_progress_banner {
	margin-top: 8px;
	padding: 6px 10px;
	background: #f2f7fb;
	border: 1px solid #c9dceb;
	border-radius: 4px;
	font-size: 11px;
}
.demo_progress_bar {
	width: 100%;
	height: 4px;
	background: #dfe7ee;
	border-radius: 2px;
	overflow: hidden;
	margin-bottom: 3px;
}
.demo_progress_bar span {
	display: block;
	height: 100%;
	background: #3c6e8f;
	transition: width 0.3s ease-out;
}
.demo_progress_text { color: #445; }

.demo_body {
	flex: 1 1 auto;
	display: flex;
	overflow: hidden;
}
.demo_leftpanel {
	flex: 1 1 65%;
	overflow: auto;
	padding: 10px 12px;
	border-right: 1px solid #e2e2e2;
	background: #fff;
}
.demo_rightpanel {
	flex: 1 1 35%;
	max-width: 420px;
	overflow-y: auto;
	padding: 10px 12px;
	background: #fafafa;
}
.demo_tables_grid {
	width: 100%;
	border-collapse: collapse;
	font-size: 12px;
}
.demo_tables_grid th {
	text-align: left;
	padding: 6px 8px;
	background: #f4f4f4;
	border-bottom: 1px solid #e2e2e2;
	color: #555;
	font-weight: 600;
	position: sticky; top: 0;
}
.demo_tables_grid td {
	padding: 6px 8px;
	border-bottom: 1px solid #f0f0f0;
	vertical-align: middle;
}
.demo_col_check { width: 30px; }
.demo_col_type  { width: 70px; }
.demo_col_name  { width: 30%; }
.demo_col_count { width: 90px; }
.demo_col_prompt { min-width: 200px; }
.demo_tables_grid input[type="number"] {
	width: 80px;
	padding: 3px 6px;
	border: 1px solid #ccc;
	border-radius: 3px;
	font-family: OpenSans;
	font-size: 12px;
	background: #fff;
	color: #222;
}
.demo_tables_grid input[type="text"] {
	width: 100%;
	padding: 3px 6px;
	border: 1px solid #ccc;
	border-radius: 3px;
	font-family: OpenSans;
	font-size: 12px;
	background: #fff;
	color: #222;
	box-sizing: border-box;
}
.demo_type_badge {
	display: inline-block;
	padding: 2px 6px;
	border-radius: 3px;
	font-size: 10px;
	font-weight: 600;
	color: #fff;
}
.demo_type_base  { background: #3c6e8f; }
.demo_type_joint { background: #6f6f6f; }
.demo_tbl_name  { font-weight: 600; color: #333; }
.demo_tbl_label { font-size: 11px; color: #888; }

.demo_runs_head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 8px;
}
.demo_runs_head h4 { margin: 0; font-size: 13px; color: #444; }
.demo_runs_refresh {
	background: transparent;
	border: 0;
	color: #666;
	cursor: pointer;
	font-size: 13px;
}
.demo_runs_loading, .demo_runs_empty { color: #888; font-size: 12px; padding: 8px; }
.demo_runs_error   { color: #b00; font-size: 12px; padding: 8px; }

.demo_run_card {
	background: #fff;
	border: 1px solid #e2e2e2;
	border-radius: 6px;
	padding: 8px 10px;
	margin-bottom: 8px;
	font-size: 11px;
	color: #333;
}
.demo_run_head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 4px;
}
.demo_run_when { font-weight: 600; color: #333; }
.demo_run_status_pill {
	display: inline-block;
	padding: 2px 6px;
	border-radius: 10px;
	font-size: 10px;
	font-weight: 600;
	background: #eee;
	color: #555;
}
.demo_run_status_completed .demo_run_status_pill              { background: #d3ebd8; color: #206b30; }
.demo_run_status_completed_with_errors .demo_run_status_pill  { background: #f5e6c5; color: #8a5b0f; }
.demo_run_status_failed .demo_run_status_pill                 { background: #f0c5c5; color: #8a1616; }
.demo_run_status_running .demo_run_status_pill                { background: #d1e3f0; color: #24567a; }
.demo_run_status_scaffold .demo_run_status_pill               { background: #eee; color: #666; }

.demo_run_meta {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	color: #666;
	margin-bottom: 4px;
}
.demo_run_meta b { color: #333; }
.demo_run_prompt { font-style: italic; color: #555; margin-bottom: 4px; }
.demo_run_pertable {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 4px;
}
.demo_run_pertable > div {
	background: #f4f4f4;
	padding: 2px 6px;
	border-radius: 3px;
	font-size: 10px;
}
.demo_run_pertable > div span { color: #666; margin-right: 4px; }
.demo_run_pertable > div b    { color: #333; }
.demo_run_flags     { margin-bottom: 4px; }
.demo_run_warn      { color: #8a5b0f; font-size: 10px; }
.demo_run_error     { color: #8a1616; font-size: 10px; }
.demo_run_actions   { text-align: right; }
.demo_run_delete {
	background: transparent;
	border: 1px solid #d0a0a0;
	color: #8a1616;
	padding: 3px 8px;
	border-radius: 3px;
	font-size: 11px;
	cursor: pointer;
	font-family: OpenSans;
}
.demo_run_delete:hover:not(:disabled) { background: #fbeaea; }
.demo_run_delete:disabled            { opacity: 0.5; cursor: not-allowed; }

/* ---- Dark theme ---- */
body.appbuilder-dark .demo_panel                             { background: #1e2124; color: #ddd; }
body.appbuilder-dark .demo_toolbar                           { background: #2a2d31; border-bottom-color: #3a3d41; }
body.appbuilder-dark .demo_lbl                               { color: #ccc; }
body.appbuilder-dark .demo_globalprompt                      { background: #2a2d31; color: #ddd; border-color: #444; }
body.appbuilder-dark .demo_generate_btn                      { background: #4a89b0; color: #fff; }
body.appbuilder-dark .demo_generate_btn:hover:not(:disabled) { background: #3c6e8f; }
body.appbuilder-dark .demo_generate_btn:disabled             { background: #4a5865; }
body.appbuilder-dark .demo_progress_banner                   { background: #24333f; border-color: #3d5468; color: #dfe8ef; }
body.appbuilder-dark .demo_progress_bar                      { background: #3a3d41; }
body.appbuilder-dark .demo_progress_bar span                 { background: #4a89b0; }
body.appbuilder-dark .demo_progress_text                     { color: #cde0ec; }
body.appbuilder-dark .demo_leftpanel                         { background: #2a2d31; border-right-color: #3a3d41; }
body.appbuilder-dark .demo_rightpanel                        { background: #1e2124; }
body.appbuilder-dark .demo_tables_grid th                    { background: #333438; border-bottom-color: #3a3d41; color: #ccc; }
body.appbuilder-dark .demo_tables_grid td                    { border-bottom-color: #34383c; }
body.appbuilder-dark .demo_tables_grid input                 { background: #333438; color: #ddd; border-color: #444; }
body.appbuilder-dark .demo_tbl_name                          { color: #eee; }
body.appbuilder-dark .demo_tbl_label                         { color: #999; }
body.appbuilder-dark .demo_runs_head h4                      { color: #ddd; }
body.appbuilder-dark .demo_runs_refresh                      { color: #aaa; }
body.appbuilder-dark .demo_runs_loading                      { color: #a0a0a0; }
body.appbuilder-dark .demo_runs_empty                        { color: #a0a0a0; }
body.appbuilder-dark .demo_runs_error                        { color: #ff9494; }
body.appbuilder-dark .demo_run_card                          { background: #2a2d31; border-color: #3a3d41; color: #ddd; }
body.appbuilder-dark .demo_run_when                          { color: #eee; }
body.appbuilder-dark .demo_run_status_pill                   { background: #3a3d41; color: #ccc; }
body.appbuilder-dark .demo_run_status_completed .demo_run_status_pill             { background: #244e30; color: #b6e4c1; }
body.appbuilder-dark .demo_run_status_completed_with_errors .demo_run_status_pill { background: #5e4515; color: #f0d38e; }
body.appbuilder-dark .demo_run_status_failed .demo_run_status_pill                { background: #5e2020; color: #f0a3a3; }
body.appbuilder-dark .demo_run_status_running .demo_run_status_pill               { background: #24567a; color: #d0e5f2; }
body.appbuilder-dark .demo_run_status_scaffold .demo_run_status_pill              { background: #3a3d41; color: #bbb; }
body.appbuilder-dark .demo_run_meta                          { color: #a0a0a0; }
body.appbuilder-dark .demo_run_meta b                        { color: #eee; }
body.appbuilder-dark .demo_run_prompt                        { color: #bbb; }
body.appbuilder-dark .demo_run_pertable > div                { background: #34383c; }
body.appbuilder-dark .demo_run_pertable > div span           { color: #a0a0a0; }
body.appbuilder-dark .demo_run_pertable > div b              { color: #eee; }
body.appbuilder-dark .demo_run_warn                          { color: #f0d38e; }
body.appbuilder-dark .demo_run_error                         { color: #f0a3a3; }
body.appbuilder-dark .demo_run_delete                        { background: transparent; border-color: #7a4040; color: #f0a3a3; }
body.appbuilder-dark .demo_run_delete:hover:not(:disabled)   { background: #3a2828; }

/* ---- Trade Script editor (BuilderPackage: trade-script) -------
   Shell reuses .workflow_designer_layout / .workflow_designer_top
   (same top-bar + save-status treatment as the workflow designer),
   plus the DB-console's bg-page → bg-block → bg-block nesting so
   the CodeMirror host sits inside a padded, rounded panel like
   the SQL Query editor. */
/* Was flex:1, which made the title absorb all slack and pushed the chips to
   the far right, against the Execute button. The CHIPS take the slack instead,
   so title / language / classification stay adjacent as one identity block. */
.tradescript_editor_title    { flex:0 0 auto; font-family:'Open Sans', sans-serif; font-size:15px; font-weight:600; color:#333; margin-left:8px; }
/* Margins so the PINE pill is not wedged against the title on one side and
   the classification chips on the other — it is a separate fact about the
   script and needs the space to read as one. */
.tradescript_editor_lang     { font-family:'Open Sans', sans-serif; font-size:11px; text-transform:uppercase; letter-spacing:0.05em; padding:2px 8px; margin:0 10px; border-radius:10px; background:#eef2f7; color:#4a6b8a; flex:0 0 auto; }
/* Execute button — mirrors the DB console's Execute affordance. */
.tradescript_editor_execute  { margin-left:6px; }
.tradescript_editor_execute .fa { margin-right:2px; }
/* Compile: the cheap, frequent check. Deliberately the plain button so
   Execute stays visibly the primary action. */
.tradescript_editor_compile  { margin-left:6px; }
.tradescript_editor_compile .fa { margin-right:2px; }

/* ---- chat pane (Editor tab: chat | code+results) --------------- */
.tradescript_editor_split { flex:1 1 auto; min-height:0; display:flex; }
/* Code column takes the slack; the assistant is a fixed-width sidebar whose
   basis the splitter drives directly. */
.tradescript_editor_split > div:first-child { flex:1 1 auto; min-width:0; }

/* Hidden by default and revealed by `.visible`, matching the workflow
   designer's properties panel — display:none rather than width:0 so the pane
   leaves the flex flow entirely and cannot claim a sliver of space. */
.tradescript_chat_pane {
	display:none; flex:0 0 340px; min-width:0; flex-direction:column;
	border-left:1px solid #e2e2e2; background:#fcfcfd;
	font-family:'Open Sans', sans-serif;
}
.tradescript_chat_pane.visible { display:flex; }
body.appbuilder-dark .tradescript_chat_pane { border-left-color:#3f4348; background:#212326; }

/* Drag handle. 5px is the smallest band that stays comfortably grabbable;
   col-resize is the cursor users already expect from the workflow splitter. */
.tradescript_chat_splitter {
	display:none; flex:0 0 5px; cursor:col-resize; background:#eceff4;
}
.tradescript_chat_splitter.visible { display:block; }
.tradescript_chat_splitter:hover   { background:var(--scr-accent, #0a66c2); opacity:0.35; }
body.appbuilder-dark .tradescript_chat_splitter { background:#2c2f33; }

/* .tradescript_chat_toggle has NO rules of its own on purpose.
   Everything — colour, padding, radius, hover, .active, light and dark — comes
   from the shared .workflow_designer_props_toggle / .ontology_designer_props_toggle
   group it was joined onto, so the three toggles cannot drift apart.
   A margin-left was removed from here: .workflow_designer_top_actions already
   sets gap:6px, so it was spacing this one control twice as far from its
   neighbour as the workflow toggle sits from its own. */

/* "N input(s)" affordance on the compile summary.
   Sits on the GREEN success banner, so it inherits that banner's text colour
   rather than the accent blue — blue on green failed contrast in light mode
   and was close to unreadable in dark. Underlined instead, so it still reads
   as something you can click. */
.tradescript_compile_inputs {
	margin-left:auto; cursor:pointer; font-size:11px; white-space:nowrap;
	color:inherit; opacity:0.85; text-decoration:underline;
	text-underline-offset:2px;
}
.tradescript_compile_inputs:hover { opacity:1; }

.tradescript_chat_head {
	flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
	padding:8px 10px; border-bottom:1px solid #eceff4;
	font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#6b7280;
}
.tradescript_chat_votes i { cursor:pointer; margin-left:8px; color:#9aa0a8; font-size:13px; }
.tradescript_chat_votes i:hover { color:var(--scr-accent, #0a66c2); }
.tradescript_chat_host { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
body.appbuilder-dark .tradescript_chat_head { border-bottom-color:#34383d; color:#aab2bb; }

/* This stylesheet has NO global font rule — each panel root declares it and its
   children inherit (see .pl_data_panel). A container that declares none leaves
   everything inside it on the browser's serif default, which is how Times New
   Roman turned up here. Both roots below are the ones this screen renders into. */
.bt_panel,
.tradescript_tabbody[data-tabbody='backtests'] { font-family: OpenSans, sans-serif; }

/* ---- a strategy's Backtests tab -----------------------------------------
   The strategy owns its backtests, so this is a list of what it has been put
   through: newest first, status and DSR at a glance, one click to the results. */
.ts_bt_head {
	display: flex; align-items: center; gap: 10px;
	padding: 12px 14px; border-bottom: 1px solid var(--border, #eceff4);
}
.ts_bt_title  { font-weight: 600; }
.ts_bt_list   { padding: 6px 0; overflow: auto; }
.ts_bt_row {
	display: flex; align-items: center; gap: 10px;
	padding: 8px 14px; cursor: pointer; font-size: 12px;
	border-bottom: 1px solid var(--border-soft, #f3f5f7);
}
.ts_bt_row:hover { background: var(--hover, #f5f7fa); }
/* The row's menu button: quiet until hovered, like a card's kebab. Right-click on the
   row opens the same menu. */
.ts_bt_menu {
	flex: 0 0 auto; border: 0; background: transparent; color: #9aa0a8; cursor: pointer;
	padding: 2px 6px; font-size: 13px; line-height: 1; border-radius: 4px;
}
.ts_bt_menu:hover { color: #333; background: #e8ebef; }
body.appbuilder-dark .ts_bt_menu { color: #7d848c; }
body.appbuilder-dark .ts_bt_menu:hover { color: #eee; background: #33373b; }
.ts_bt_name  { font-weight: 600; }
.ts_bt_meta  { color: var(--fg-muted, #808080); }
.ts_bt_st {
	min-width: 62px; text-align: center; padding: 1px 6px; border-radius: 9px;
	font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
	border: 1px solid var(--border, #e3e6ea); color: var(--fg-muted, #808080);
}
.ts_bt_st.is-ok  { color: #2e7d43; border-color: rgba(46,125,67,.35); }
.ts_bt_st.is-bad { color: #d2453a; border-color: rgba(210,69,58,.35); }
.ts_bt_st.is-run { color: var(--scr-accent, #0a66c2); border-color: var(--scr-accent, #0a66c2); }
.ts_bt_dsr {
	font-variant-numeric: tabular-nums; font-weight: 600; cursor: help;
	color: var(--scr-accent, #0a66c2);
}
.ts_bt_empty   { padding: 28px 14px; color: var(--fg-muted, #808080); text-align: center; }
.ts_bt_hint    { font-size: 11px; margin-top: 6px; max-width: 560px; margin-inline: auto; }
.ts_bt_pending { padding: 24px 14px; color: var(--fg-muted, #808080); }

body.appbuilder-dark .ts_bt_head { border-bottom-color: #34383d; }
body.appbuilder-dark .ts_bt_row  { border-bottom-color: #2a2d31; }
body.appbuilder-dark .ts_bt_row:hover { background: #26292d; }
body.appbuilder-dark .ts_bt_st   { border-color: #34383d; }
body.appbuilder-dark .ts_bt_st.is-ok { color: #6fbf85; border-color: rgba(111,191,133,.35); }

/* ---- validated-backtest progress ----------------------------------------
   A validation is one long job with no member rows to fill in, so this is the
   only sign of life the detail pane has while it works. */
.bt_vrun { padding: 14px 16px; }
.bt_vrun_h { display: flex; align-items: baseline; gap: 8px; }
.bt_vrun_t { font-weight: 600; }
.bt_vrun_p { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--fg-muted, #808080); }
.bt_vrun_hint { font-size: 11px; color: var(--fg-muted, #808080); margin-top: 2px; }

/* The symbol checklist. A validation reports one counter, so this is derived:
   everything before the counter is done, the named one is running, the rest wait. */
.bt_vsyms { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 12px; }
.bt_vsym {
	display: inline-flex; align-items: center; gap: 5px;
	padding: 2px 8px; border-radius: 10px; font-size: 11px;
	border: 1px solid var(--border, #e3e6ea); color: var(--fg-muted, #808080);
}
.bt_vsym.is-done { color: #2e7d43; border-color: rgba(46, 125, 67, .35); }
.bt_vsym.is-run  { color: var(--scr-accent, #0a66c2); border-color: var(--scr-accent, #0a66c2); font-weight: 600; }
body.appbuilder-dark .bt_vsym      { border-color: #34383d; }
body.appbuilder-dark .bt_vsym.is-done { color: #6fbf85; border-color: rgba(111, 191, 133, .35); }

/* Terminal states — one clear line and the action that follows from it. */
.bt_vstate { padding: 18px 16px; max-width: 620px; }
.bt_vstate_h { font-weight: 600; font-size: 13px; }
.bt_vstate_b { margin-top: 4px; font-size: 12px; color: var(--fg-muted, #808080); }
/* A validation that finished but is not the whole answer — a symbol with no
   ingested history, say. Amber, not red: the run is real, it is just
   incomplete, and the message says what to ingest and to run it again. */
.bt_vstate_warn {
	margin-top: 6px; padding: 6px 9px; border-radius: 5px;
	background: #fdf3e3; border: 1px solid #f0dcb8; color: #7a5c14;
	font-size: 12px; line-height: 1.45;
}
body.appbuilder-dark .bt_vstate_warn { background:#3a3226; border-color:#5a4a2a; color:#e0c284; }
.bt_vstate_a { margin-top: 12px; }
.bt_vstate.is-err .bt_vstate_h { color: #d2453a; }
.bt_vstate.is-ok  .bt_vstate_h { color: #2e7d43; }
.bt_vstate.is-queued .bt_vstate_h { color: #b28704; }
body.appbuilder-dark .bt_vstate.is-ok .bt_vstate_h { color: #6fbf85; }
body.appbuilder-dark .bt_vstate.is-queued .bt_vstate_h { color: #d4b452; }

.bt_progress_head { font-weight: 600; }
.bt_progress_bar {
	height: 4px; margin: 6px 0 4px;
	background: var(--border, #e3e6ea); border-radius: 2px; overflow: hidden;
}
.bt_progress_bar > div {
	height: 100%; background: var(--scr-accent, #0a66c2);
	transition: width .3s ease-in-out;
}
.bt_progress_hint { font-size: 11px; color: var(--fg-muted, #808080); }
body.appbuilder-dark .bt_progress_bar { background: #34383d; }

/* ---- toggle rows in a w2form (Backtest Properties) -----------------------
   A switch reads as "[switch] what it does", so the caption sits BESIDE it
   rather than floating above as a normal field's label does. w2ui emits the
   switch as an <input> plus its own visual <div>, then appends html.text after
   them — none of which agrees on a baseline, which is why vertical-align alone
   left the caption sitting low and adrift.

   Laying the row out as a flex line fixes both the alignment and the gap in one
   go: `align-items:center` centres the caption against the switch whatever the
   switch's height, and `gap` replaces the accidental whitespace that was pushing
   it too far right. Selected through :has() on our own data-bt-toggle marker, so
   it cannot reach any other form's toggles. (:has() is already relied on
   elsewhere in this sheet.) */
/* gap:0 deliberately. A row gap here fights the label's own pull-back margin —
   6px of gap against -8px of margin nets 2px, which is why an "8px left" nudge
   looked like nothing moved at all. The switch already brings its own trailing
   space, so the spacing is set in ONE place: the label's margin. */
.w2ui-field:has(input[data-bt-toggle]) > div {
	display: flex;
	align-items: center;
	gap: 0;
}

.bt_togglelabel {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	font-size: 12px;
	white-space: nowrap;
	margin-left: -8px;
}

/* ---- field help glyph placement -----------------------------------------
   The required marker is drawn as `label::after { content:"*" }`, so it is by
   definition the LAST thing in the label and nothing written inside the label
   can follow it. Making the label a flex line turns that pseudo-element into a
   flex item, and ordering the tip after it puts the glyph where it belongs:
   "Depth * ?" rather than "Depth ? *".

   Scoped through :has(.bt_fieldtip) so it only reaches labels that actually
   carry a tip — every other w2ui label in the app is untouched. */
.w2ui-field > label:has(.bt_fieldtip) {
	/* An app-wide rule sets `content:"*"` on the LABEL ELEMENT of a required field
	   (not on a pseudo-element). Setting `content` on a real element REPLACES its
	   children with the generated content: they stay in the DOM but are never
	   rendered, so they have no box and cannot be hovered — which is precisely why
	   the tip on the required Depth field was inert while every other one worked.
	   Restoring `normal` puts the label's own children back on screen; the asterisk
	   is unaffected because it comes from the separate `label::after` rule. */
	content: normal !important;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	/* The label sat directly on top of its input, so the tip glyph read as part of
	   the field rather than as part of the caption. */
	margin-bottom: 2px;
}
.w2ui-field > label:has(.bt_fieldtip) .bt_fieldtip { order: 2; }

/* Per-answer vote bar — the thumbs sit under the reply that prompted them, as
   they do in a thread, rather than in the panel header where they had no
   well-defined subject. Quiet until the answer is hovered: supervision should be
   available at a glance, not competing with the answer for attention. */
.tradescript_msg_votes {
	display:flex; gap:2px; margin-top:4px; opacity:0; transition:opacity .12s ease-in-out;
}
.builder-thread-body-answer:hover .tradescript_msg_votes,
.tradescript_msg_votes:focus-within { opacity:1; }

/* Journal line — a statement of fact about the script, not something the
   assistant said, so it is deliberately quieter than a reply bubble. */
.ts-journal {
	margin:4px 8px; padding:5px 8px; border-radius:4px;
	background:#f2f4f7; color:#5f6673; font-size:11px; line-height:1.45;
}
.ts-journal.is-warning { background:#fff4e0; color:#8a5a00; }
body.appbuilder-dark .ts-journal            { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .ts-journal.is-warning { background:#4a3a1c; color:#f0d38e; }

.ts-proposal {
	margin:8px; padding:10px; border-radius:6px;
	border:1px solid #cfe0f3; background:#f4f9ff; font-size:12px; color:#33475b;
}
.ts-proposal-title   { font-weight:600; margin-bottom:6px; }
.ts-proposal ul      { margin:0 0 6px; padding-left:18px; line-height:1.6; }
.ts-proposal-note    { font-size:10.5px; color:#6b7280; margin-bottom:8px; }
.ts-proposal-actions { display:flex; gap:6px; }
body.appbuilder-dark .ts-proposal      { border-color:#31465e; background:#1e2a36; color:#c6d2df; }
body.appbuilder-dark .ts-proposal-note { color:#9aa4b0; }

/* ---- run pane (bar + results | inputs) ------------------------ */
/* Everything that decides what a run DOES now sits with its output: the bar
   carries Execute + data selection, the body puts results beside the script's
   input parameters. */
.tradescript_runpane { width:100%; height:100%; display:flex; flex-direction:column; min-height:0; }
.tradescript_runbar {
	flex:0 0 auto; display:flex; align-items:center; gap:6px;
	padding:6px 8px; border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.tradescript_runbar_spacer { flex:1 1 auto; }
/* One height for every control in the bar.
   The ticker box and the pick buttons had different vertical padding (4px vs
   6px), so they sat 4px apart. Pinning the height here rather than harmonising
   two paddings means a future change to either base rule cannot re-open the
   gap. `align-items:center` on the bar then centres anything that opts out. */
.tradescript_runbar > input,
.tradescript_runbar > button,
.tradescript_runbar .wf-pickbtn {
	height:30px; box-sizing:border-box;
}
.tradescript_runbar .tradescript_pick_host { display:inline-flex; align-items:stretch; }
.tradescript_runbody { flex:1 1 auto; min-height:0; display:flex; }
/* The results pane must be allowed to shrink — min-width:0 on a flex child is
   what stops a wide chart or table from forcing the inputs panel off-screen. */
.tradescript_runbody > .tradescript_results { flex:1 1 auto; min-width:0; }
body.appbuilder-dark .tradescript_runbar { border-bottom-color:#3f4348; background:#26282b; }

.tradescript_inputs_toggle.is-active { background:#e8eef6; border-color:#9bb6d0; }
body.appbuilder-dark .tradescript_inputs_toggle.is-active { background:#33405020; border-color:#4a6b8a; }

.tradescript_inputs_panel {
	flex:0 0 300px; min-width:0; display:flex; flex-direction:column;
	border-left:1px solid #e2e2e2; background:#fcfcfd;
	font-family:'Open Sans', sans-serif;
}
body.appbuilder-dark .tradescript_inputs_panel { border-left-color:#3f4348; background:#212326; }

.tradescript_inputs_head {
	flex:0 0 auto; display:flex; align-items:center; justify-content:space-between; gap:8px;
	padding:8px 10px; border-bottom:1px solid #eceff4;
	font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#6b7280;
}
.tradescript_inputs_resetall { font-size:10px; text-transform:none; letter-spacing:0; }
.tradescript_inputs_list  { flex:1 1 auto; min-height:0; overflow:auto; padding:6px 10px; }
.tradescript_inputs_foot  { flex:0 0 auto; padding:8px 10px; border-top:1px solid #eceff4; }
.tradescript_inputs_apply { width:100%; }
.tradescript_inputs_empty { padding:14px 10px; font-size:11.5px; line-height:1.5; color:#9aa0a8; }
body.appbuilder-dark .tradescript_inputs_head { border-bottom-color:#34383d; color:#aab2bb; }
body.appbuilder-dark .tradescript_inputs_foot { border-top-color:#34383d; }
body.appbuilder-dark .tradescript_inputs_empty { color:#7d848c; }

.tradescript_inputs_group {
	margin:10px 0 4px; font-size:10px; text-transform:uppercase; letter-spacing:0.05em; color:#9aa0a8;
}
.tradescript_input_row   { padding:6px 0; border-bottom:1px solid #f2f3f5; }
.tradescript_input_row:last-child { border-bottom:0; }
/* A changed input is marked on the row, not just the value — the author needs
   to see at a glance which parameters are no longer the script's own. */
.tradescript_input_row.is-changed { border-left:2px solid var(--scr-accent, #0a66c2); margin-left:-10px; padding-left:8px; }
/* Fixed line-height rather than letting the font decide: with a 26px field
   under it, a label whose height drifts with its glyphs made the rows sit at
   visibly different pitches down the panel. */
.tradescript_input_label {
	display:flex; align-items:center; gap:4px;
	font-size:11.5px; line-height:16px; color:#4b5563; margin-bottom:4px;
}
.tradescript_input_reset {
	border:0; background:transparent; cursor:pointer; padding:0 2px;
	color:#9aa0a8; font-size:10px; line-height:1;
}
.tradescript_input_reset:hover { color:var(--scr-accent, #0a66c2); }
.tradescript_input_editor { display:flex; align-items:center; gap:6px; }
/* The editors are plain w2ui inputs (number fields with the browser's own
   stepper, text fields alike) — the one field pattern the app has, so this
   panel does not carry a look of its own. Only the flex sizing and the
   panel's smaller type are set here; height, padding, border, focus and the
   dark palette all come from w2ui and the global input rules. */
.tradescript_input_editor > input.w2ui-input {
	flex:1 1 auto; min-width:0; box-sizing:border-box;
	font-family:'Open Sans', sans-serif; font-size:11.5px;
}
/* The bool editor: a bare checkbox, sized like the other panel checkboxes. */
.tradescript_input_field[type='checkbox'] { flex:0 0 auto; width:14px; height:14px; margin:0; }
.tradescript_input_bounds { flex:0 0 auto; font-size:10px; color:#9aa0a8; white-space:nowrap; }
body.appbuilder-dark .tradescript_inputs_group { color:#7d848c; }
body.appbuilder-dark .tradescript_input_row    { border-bottom-color:#2c2f33; }
body.appbuilder-dark .tradescript_input_label  { color:#c6d2df; }
body.appbuilder-dark .tradescript_input_field  { background:#1f2124; border-color:#3f4348; color:#e6e6e6; color-scheme:dark; }
body.appbuilder-dark .tradescript_input_bounds { color:#7d848c; }

/* ---- editor tabs (Editor / Versions / Runs) ------------------- */
/* The tab strip is the editor's primary structure; the code+results split
   lives inside the Editor tab. Bodies are toggled by display, so the hidden
   ones drop out of the flex flow and the visible one takes the height. */
.tradescript_tabbar {
	flex:0 0 auto; height:32px;
	border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.tradescript_tabbody { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; position:relative; }
/* The Status tab hosts the graduation panel, which paints its own .pl_data_panel
   background. That panel is only as tall as its content, so the tab body showed a
   SECOND, different dark below it - two backgrounds down one screen. Giving the body
   the same colour makes the seam invisible however short the content is. */
.tradescript_tabbody[data-tabbody='status'] { background:#f7f8fa; overflow:auto; }
.tradescript_tabbody[data-tabbody='status'] > div { flex:0 0 auto; }
body.appbuilder-dark .tradescript_tabbody[data-tabbody='status'] { background:#1f2126; }
body.appbuilder-dark .tradescript_tabbar { border-bottom-color:#3f4348; background:#26282b; }

/* Placeholder for tabs whose content is not built yet. Explicit rather than
   blank — an empty panel reads as a failure to load. */
.tradescript_tab_placeholder {
	flex:1 1 auto; display:flex; flex-direction:column;
	align-items:center; justify-content:center; gap:6px;
	font-family:'Open Sans', sans-serif; color:#9aa0a8; text-align:center; padding:24px;
}
.tradescript_tab_placeholder .fa { font-size:28px; opacity:0.45; }
.tradescript_tab_placeholder_title { font-size:14px; font-weight:600; color:#6b7280; }
.tradescript_tab_placeholder p { margin:0; max-width:420px; font-size:12px; line-height:1.5; }
body.appbuilder-dark .tradescript_tab_placeholder       { color:#7d848c; }
body.appbuilder-dark .tradescript_tab_placeholder_title { color:#aab2bb; }

/* ---- runs ------------------------------------------------------ */
.tradescript_runs { flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
                    font-family:'Open Sans', sans-serif; }
.tradescript_runs_bar {
	flex:0 0 auto; display:flex; align-items:center; gap:10px;
	padding:10px 14px; border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.tradescript_runs_hint  { font-size:11px; color:#9aa0a8; }
/* The list fills the tab: a run's result is no longer drawn underneath (its trades
   are downloaded as a workbook from the row), so there is nothing to split. */
.tradescript_runs_list  { flex:1 1 auto; min-height:0; overflow:auto; padding:6px 14px 14px; }
.tradescript_runs_empty { padding:24px 4px; text-align:center; font-size:12px; color:#9aa0a8; }
body.appbuilder-dark .tradescript_runs_bar   { border-bottom-color:#3f4348; background:#26282b; }
body.appbuilder-dark .tradescript_runs_hint,
body.appbuilder-dark .tradescript_runs_empty { color:#7d848c; }

.tradescript_run_row {
	display:flex; align-items:flex-start; gap:10px;
	padding:9px 0; border-bottom:1px solid #eceff4;
}
.tradescript_run_row:last-child { border-bottom:0; }
/* Success/failure as a dot rather than a coloured row: a failed run is still
   a normal entry in the log, not an alarm. */
.tradescript_run_dot {
	flex:0 0 7px; width:7px; height:7px; margin-top:5px;
	border-radius:50%; background:#00a152;
}
.tradescript_run_row.is-failed .tradescript_run_dot { background:#d32f2f; }
.tradescript_run_main    { flex:1 1 auto; min-width:0; }
.tradescript_run_top     { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.tradescript_run_src     { font-size:12.5px; font-weight:600; color:#333; }
/* Revision marker — the answer to "did the code change between these runs?" */
.tradescript_run_rev {
	font-size:10px; padding:1px 6px; border-radius:9px;
	background:#f0ecf7; color:#5d4a8a; cursor:default;
}
/* Backtest membership marker. Same pill shape as the revision marker but the
   blue the batch tag already used for "this belongs to a bigger run" — it says
   the row is owned elsewhere, which is also why the row offers Open-the-backtest
   instead of Delete. */
.tradescript_run_bt {
	font-size:10px; padding:1px 6px; border-radius:9px;
	background:#e8f1fb; color:#1a5c9c; cursor:default;
}
.tradescript_run_inputs  { font-size:10px; color:#6b7280; cursor:default; }
.tradescript_run_metrics { font-size:11.5px; color:#4b5563; margin-top:3px; }
.tradescript_run_err     { color:#b3261e; }
.tradescript_run_meta    { font-size:10.5px; color:#9aa0a8; margin-top:3px; }
body.appbuilder-dark .tradescript_run_row     { border-bottom-color:#2c2f33; }
body.appbuilder-dark .tradescript_run_src     { color:#eee; }
body.appbuilder-dark .tradescript_run_rev     { background:#3a3350; color:#c0aee8; }
body.appbuilder-dark .tradescript_run_bt      { background:#1d3348; color:#8ec2ee; }
body.appbuilder-dark .tradescript_run_inputs,
body.appbuilder-dark .tradescript_run_metrics { color:#aab2bb; }
body.appbuilder-dark .tradescript_run_err     { color:#ef9a9a; }
body.appbuilder-dark .tradescript_run_meta    { color:#7d848c; }

/* ---- batches --------------------------------------------------- */
/* A batch row is a RUN row with a different marker, deliberately: it sits in
   the same list and answers the same question ("what happened, and when"),
   so it inherits the run row's layout rather than restating it. */
.tradescript_batch_dot {
	width:auto; height:auto; flex:0 0 auto; margin-top:2px;
	border-radius:0; background:none; color:#6b7280; font-size:11px;
}
.tradescript_batch_tag {
	font-size:10px; padding:1px 6px; border-radius:9px;
	background:#e8f1fb; color:#1a5c9c; cursor:default;
}
/* Spread around the average. Dimmer than the average itself — it qualifies
   that number rather than competing with it. */
.tradescript_batch_range { color:#9aa0a8; }
.tradescript_batch_back  { flex:0 0 auto; }
.tradescript_batch_back .fa { margin-right:2px; }
.tradescript_batch_prog {
	font-size:11px; color:var(--scr-accent, #0a66c2); white-space:nowrap;
}
.tradescript_batch_prog.is-done { color:#9aa0a8; }
body.appbuilder-dark .tradescript_batch_dot   { color:#8b939c; }
body.appbuilder-dark .tradescript_batch_tag   { background:#1e3550; color:#8fc2f0; }
body.appbuilder-dark .tradescript_batch_range,
body.appbuilder-dark .tradescript_batch_prog.is-done { color:#7d848c; }

/* ---- versions -------------------------------------------------- */
.tradescript_editor_saveversion { margin-left:6px; }
.tradescript_editor_saveversion .fa { margin-right:2px; }
.tradescript_editor_autopilot { margin-left:6px; }
.tradescript_editor_autopilot .fa { margin-right:2px; }
/* Stage + desk outcome right of the classification chips; the block is a link to the
   Status tab, which is where the stage is explained. Chips reuse the grid's palette. */
/* Right after the classification chips, not pushed to the actions: this block takes the
   header's slack (the chips host no longer grows - see .tradescript_editor_chips). */
.tradescript_editor_status {
	flex:1 1 auto; min-width:0; display:inline-flex; align-items:center; gap:4px;
	margin-left:4px; cursor:pointer;
}
.tradescript_editor_status:hover .ts_chip { filter:brightness(0.94); }
/* Stage chip: the type/category chip's size, shape and font, in the colours the Scripts
   grid gives the stage (the --stage-bg / --stage-fg pair the .stage-* slug sets on the
   element). Scoped under the host so it outranks the generic .ts_chip rule, which is
   later in this sheet and was flattening both chips to the default grey-blue. */
.tradescript_editor_status .ts_chip_stage { font-weight:600; text-transform:uppercase; letter-spacing:.04em; background:var(--stage-bg, #eef2f7); color:var(--stage-fg, #4a6b8a); }
/* Desk outcome chip: the grid's Night Desk column colours (.rs_chip.is-*), same body. */
.tradescript_editor_status .ts_chip_desk { font-weight:600; }
.tradescript_editor_status .ts_chip_desk.is-live      { background:#e6f4ec; color:#116b3a; }
.tradescript_editor_status .ts_chip_desk.is-draft     { background:#eceff4; color:#6b7280; }
.tradescript_editor_status .ts_chip_desk.is-paper     { background:#fdf3e3; color:#9a6a10; }
.tradescript_editor_status .ts_chip_desk.is-neg       { background:#fbeaea; color:#b3261e; }
.tradescript_editor_status .ts_chip_desk.is-lifecycle { background:transparent; color:#41506b; box-shadow:inset 0 0 0 1px #d5dae1; }
body.appbuilder-dark .tradescript_editor_status .ts_chip_stage { background:var(--stage-bg, #3f4348); color:var(--stage-fg, #c6d2df); }
body.appbuilder-dark .tradescript_editor_status .ts_chip_desk.is-live      { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .tradescript_editor_status .ts_chip_desk.is-draft     { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .tradescript_editor_status .ts_chip_desk.is-paper     { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .tradescript_editor_status .ts_chip_desk.is-neg       { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .tradescript_editor_status .ts_chip_desk.is-lifecycle { background:transparent; color:#a8bdd4; box-shadow:inset 0 0 0 1px #4a4f57; }
body.appbuilder-dark .tradescript_editor_status:hover .ts_chip { filter:brightness(1.15); }
/* Portfolios tab: the graduation rail's page rhythm and font, without the rail. */
.ts_pf_wrap { min-height:100%; }
.ts_pf_wrap .ts_div_host { margin-top:2px; }

.tradescript_versions { flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
                        font-family:'Open Sans', sans-serif; }
.tradescript_versions_bar {
	flex:0 0 auto; display:flex; align-items:center; gap:10px;
	padding:10px 14px; border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.tradescript_versions_hint  { font-size:11px; color:#9aa0a8; }
.tradescript_versions_list  { flex:1 1 auto; min-height:0; overflow:auto; padding:6px 14px 14px; }
.tradescript_versions_empty { padding:24px 4px; text-align:center; font-size:12px; color:#9aa0a8; }
body.appbuilder-dark .tradescript_versions_bar   { border-bottom-color:#3f4348; background:#26282b; }
body.appbuilder-dark .tradescript_versions_hint,
body.appbuilder-dark .tradescript_versions_empty { color:#7d848c; }

.tradescript_version_row {
	display:flex; align-items:flex-start; gap:12px;
	padding:10px 0; border-bottom:1px solid #eceff4;
}
.tradescript_version_row:last-child { border-bottom:0; }
/* The number is the handle people use to talk about a version ("go back to
   v3"), so it is the most prominent thing in the row. */
.tradescript_version_num {
	flex:0 0 44px; font-size:13px; font-weight:600; color:var(--scr-accent, #0a66c2);
	padding-top:1px;
}
.tradescript_version_main  { flex:1 1 auto; min-width:0; }
.tradescript_version_label { font-size:13px; font-weight:600; color:#333; }
.tradescript_version_desc  { font-size:11.5px; color:#6b7280; margin-top:2px; line-height:1.45; }
.tradescript_version_meta  { font-size:10.5px; color:#9aa0a8; margin-top:4px; }
.tradescript_version_actions { flex:0 0 auto; display:flex; gap:6px; }
body.appbuilder-dark .tradescript_version_row   { border-bottom-color:#2c2f33; }
body.appbuilder-dark .tradescript_version_label { color:#eee; }
body.appbuilder-dark .tradescript_version_desc  { color:#aab2bb; }
body.appbuilder-dark .tradescript_version_meta  { color:#7d848c; }

/* ---- one history: saved versions + amendments ------------------------ */
/* The trial count sits above the timeline because it is the denominator for
   every result in it — see _PaintLineageBar. */
.ts_lineage_bar {
	flex:0 0 auto; display:flex; align-items:center; gap:8px; flex-wrap:wrap;
	padding:8px 14px; border-bottom:1px solid #e6e8ea; background:#fafbfc;
	font-family:OpenSans, sans-serif; font-size:11.5px;
}
.ts_lin_k    { color:#6b7280; }
.ts_lin_v    { font-weight:700; font-size:13px; color:#333; }
.ts_lin_hint { color:#9aa0a8; }
.ts_lin_warn { color:#a8620a; font-weight:600; }
body.appbuilder-dark .ts_lineage_bar { border-bottom-color:#3f4348; background:#26282b; }
body.appbuilder-dark .ts_lin_k       { color:#aab2bb; }
body.appbuilder-dark .ts_lin_v       { color:#eee; }
body.appbuilder-dark .ts_lin_hint    { color:#7d848c; }
body.appbuilder-dark .ts_lin_warn    { color:#e0a34a; }

/* An amendment row is a version row with a state colour down its left edge,
   so the two kinds read as one list rather than two designs. */
.ts_amend { border-left:0; }   /* the state colour is on the icon, not on a rail glued to it (2026-09-21) */
.ts_amend_ico.is-ok   { color:#0f9d76; }
.ts_amend_ico.is-bad  { color:#b3261e; }
.ts_amend_ico.is-warn { color:#c98a12; }
.ts_amend_ico     { color:#9aa0a8; font-size:14px; }
.ts_amend_state {
	font-size:10px; text-transform:uppercase; letter-spacing:.04em;
	padding:1px 6px; border-radius:9px; background:#eef0f2; color:#6b7280;
}
.ts_amend_best {
	font-size:10px; text-transform:uppercase; letter-spacing:.04em;
	padding:1px 6px; border-radius:9px; background:#0f9d76; color:#fff;
}
.ts_amend_delta  { font-size:11.5px; margin-top:3px; display:flex; gap:8px; align-items:baseline; }
.ts_amend_trials { color:#9aa0a8; font-size:10.5px; }
body.appbuilder-dark .ts_amend_ico    { color:#7d848c; }
body.appbuilder-dark .ts_amend_state  { background:#33373b; color:#aab2bb; }
body.appbuilder-dark .ts_amend_trials { color:#7d848c; }

/* ---- Instrument rows: the per-symbol report, one line each ------------ */
/* The trades pane is gone, so the list is the full width and each row carries
   its own KPIs. The label under each figure is what makes six numbers on a line
   readable instead of a row of anonymous digits. */
.bt_runs.is-full { flex:1 1 auto; min-height:0; overflow:auto; }

/* The breakdown is a table now, with the same vocabulary as Sample windows:
   symbol left, figures right, one header row naming them. */
.bt_instr_t tbody th   { white-space:nowrap; }
.bt_instr_r.is-failed th,
.bt_instr_r.is-failed td { opacity:.65; }
.bt_instr_note { text-align:left !important; color:#9aa0a8; font-style:italic; }
.bt_instr_x    { width:1%; padding-right:0 !important; }
body.appbuilder-dark .bt_instr_note { color:#7d848c; }

.bt_run_dl {
	flex:0 0 auto; margin-left:10px; border:1px solid #d7dbdf; border-radius:4px;
	background:transparent; color:#6b7280; cursor:pointer; padding:2px 7px; font-size:11px;
}
.bt_run_dl:hover { background:#eef0f2; color:#333; }
body.appbuilder-dark .bt_run_kpi i  { color:#7d848c; }
body.appbuilder-dark .bt_run_dl     { border-color:#3f4348; color:#aab2bb; }
body.appbuilder-dark .bt_run_dl:hover { background:#33373b; color:#eee; }

/* ONE scroll region, below the fixed header. The head, the parameters and the
   KPI band stay put; the report and the instrument breakdown share this. An
   earlier version gave the breakdown its own max-height and a drag handle,
   which solved the wrong problem — the sections do not each need a viewport,
   the body does, and a scrollbar inside a scrollbar is worse than a long page.
   min-height:0 is what actually lets a flex child scroll rather than stretch. */
.bt_detail_body { flex:1 1 auto; min-height:0; overflow:auto; }

/* Things that navigate say so. A cell that opens a panel and looks like text is
   a cell nobody clicks. */
.bt_link { color:#0175ff; cursor:pointer; text-decoration:none; }
.bt_link:hover { text-decoration:underline; }
body.appbuilder-dark .bt_link { color:#4aa8ff; }

/* The card's second line: what turns an expectancy into something weighable. */
.bt_card_kpis {
	display:flex; flex-wrap:wrap; gap:12px; margin:4px 0 0;
	font-size:11px; font-variant-numeric:tabular-nums; color:#333;
}
.bt_card_kpis i { font-style:normal; font-size:9.5px; color:#9aa0a8;
                  text-transform:uppercase; letter-spacing:.03em; margin-left:3px; }
body.appbuilder-dark .bt_card_kpis   { color:#dfe3e7; }
body.appbuilder-dark .bt_card_kpis i { color:#7d848c; }

/* ---- Strategy ▸ Backtests tab: the verdict on each row ---------------- */
.ts_bt_kpi {
	display:inline-flex; align-items:baseline; gap:4px; margin-left:14px;
	font-size:11.5px; font-variant-numeric:tabular-nums; white-space:nowrap;
}
.ts_bt_kpi i { font-style:normal; font-size:9.5px; color:#9aa0a8;
               text-transform:uppercase; letter-spacing:.03em; }
body.appbuilder-dark .ts_bt_kpi i { color:#7d848c; }

/* ---- "The read": the arithmetic, stated ------------------------------- */
.bt_read      { margin:0; padding:0 0 0 18px; font-size:12px; line-height:1.6; color:#333; }
.bt_read li   { margin:2px 0; }
.bt_read li::marker { color:#9aa0a8; }
.bt_read_ok   { color:#0b7d5e; }
.bt_read_warn { color:#a8620a; }
.bt_read_bad  { color:#8f1d17; }
body.appbuilder-dark .bt_read      { color:#dfe3e7; }
body.appbuilder-dark .bt_read_ok   { color:#5ed3a8; }
body.appbuilder-dark .bt_read_warn { color:#e0a34a; }
body.appbuilder-dark .bt_read_bad  { color:#f0857c; }

/* The verdict banner. ABANDON is the one thing the diagnosis must not let the
   reader skim past, so it gets the visual weight of an error, not of prose. */
.bt_diag_verdict {
	display:inline-block; font-weight:700; font-size:12px; letter-spacing:.02em;
	padding:6px 12px; border-radius:5px; margin:0 0 10px;
}
.bt_diag_verdict.is-abandon { background:#fbe6e4; color:#8f1d17; }
.bt_diag_verdict.is-iterate { background:#e3f4ee; color:#0b7d5e; }
body.appbuilder-dark .bt_diag_verdict.is-abandon { background:#3a1e1c; color:#f0857c; }
body.appbuilder-dark .bt_diag_verdict.is-iterate { background:#173a30; color:#5ed3a8; }

/* A result the editor has moved past. */
.bt_note.is-stale { background:#fdf1dc; color:#a8620a; }
body.appbuilder-dark .bt_note.is-stale { background:#3a2f17; color:#e0a34a; }

/* ---- The model's reading ---------------------------------------------- */
/* Visually quieter than "The read" above it: that block is arithmetic and this
   one is an opinion, and the screen should not present them as equals. */
.bt_diag_text  { font-size:12px; line-height:1.65; color:#333; white-space:normal; }
.bt_diag_text p { margin:0 0 8px; }
.bt_diag_empty { font-size:11.5px; color:#9aa0a8; font-style:italic; padding:2px 0 6px; }
.bt_diag_act   { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:8px; }
.bt_diag_hint  { font-size:11px; color:#9aa0a8; }
body.appbuilder-dark .bt_diag_text  { color:#dfe3e7; }
body.appbuilder-dark .bt_diag_empty,
body.appbuilder-dark .bt_diag_hint  { color:#7d848c; }

/* ---- Insights, hosted as a section on the backtest -------------------- */
/* The panel is reused whole, so its standalone chrome is suppressed rather
   than branched in JS: .pl_wrap/.pl_head is shared by eight PineLab panels,
   which makes a code anchor there ambiguous, while these selectors are exact
   and trivially reversible. The section header already names it, and the
   validation is the one on screen rather than something to type. */
.bt_insights_host .pl_head   { display:none; }
.bt_insights_host #id_pli_vid { display:none; }
.bt_insights_host .pl_wrap   { padding:0; }

/* ---- The validation report, inline on the backtest -------------------- */
/* It used to be a button to the Leaderboard. The question "is this backtest any
   good" is asked here, so it is answered here. */
.bt_report { flex:0 0 auto; padding:0 14px 8px; font-family:OpenSans, sans-serif; }
.bt_rep    { border:1px solid #e6e8ea; border-radius:6px; margin-top:8px; background:#fafbfc; }
/* The browser's own disclosure marker, as the History section in a strategy's Status tab
   uses (.pl_more). This used to hide it (list-style:none + ::-webkit-details-marker) and
   draw \25B8 / \25BE instead - glyphs noticeably smaller than the native triangle, which
   is what made these sections look cramped beside it. */
.bt_rep > summary {
	cursor:pointer; padding:7px 10px; font-size:12px; font-weight:700; color:#333;
	user-select:none; outline:none;
}
.bt_rep_b  { padding:2px 10px 10px; overflow-x:auto; }

.bt_rep_t  { width:100%; border-collapse:collapse; font-size:11.5px; }
.bt_rep_t th, .bt_rep_t td { padding:4px 8px; text-align:right; white-space:nowrap; }
.bt_rep_t thead th { color:#9aa0a8; font-weight:600; border-bottom:1px solid #e6e8ea; }
.bt_rep_t tbody th { text-align:left; color:#333; font-weight:600; }
.bt_rep_t tbody tr + tr td, .bt_rep_t tbody tr + tr th { border-top:1px solid #eef0f2; }

.bt_rep_row { display:flex; flex-wrap:wrap; gap:14px; font-size:11.5px; color:#6b7280; padding:4px 0; }
.bt_rep_row b { color:#333; }

body.appbuilder-dark .bt_rep            { border-color:#3f4348; background:#26282b; }
body.appbuilder-dark .bt_rep > summary  { color:#eee; }
body.appbuilder-dark .bt_rep_t thead th { color:#7d848c; border-bottom-color:#3f4348; }
body.appbuilder-dark .bt_rep_t tbody th { color:#eee; }
body.appbuilder-dark .bt_rep_t tbody tr + tr td,
body.appbuilder-dark .bt_rep_t tbody tr + tr th { border-top-color:#2c2f33; }
body.appbuilder-dark .bt_rep_row        { color:#aab2bb; }
body.appbuilder-dark .bt_rep_row b      { color:#eee; }

/* ---- The verdict, before the working ---------------------------------- */
/* Not a section: a conclusion behind a disclosure triangle is a conclusion
   that gets missed. The left edge carries the state, so the answer is legible
   from the corner of the eye before a word is read. */
.bt_verdict {
	margin-top:8px; padding:11px 13px; border:1px solid #e6e8ea; border-radius:6px;
	background:#fafbfc; border-left:4px solid #9aa0a8;
}
.bt_verdict.is-ok   { border-left-color:#0b7d5e; }
.bt_verdict.is-warn { border-left-color:#a8620a; }
.bt_verdict.is-bad  { border-left-color:#8f1d17; }
.bt_verdict_top { display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.bt_verdict_tag {
	font-size:10px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
	padding:2px 8px; border-radius:10px; background:#eceff4; color:#6b7280; white-space:nowrap;
}
.bt_verdict.is-ok   .bt_verdict_tag { background:#e3f4ee; color:#0b7d5e; }
.bt_verdict.is-warn .bt_verdict_tag { background:#fdf1dc; color:#a8620a; }
.bt_verdict.is-bad  .bt_verdict_tag { background:#fbe6e4; color:#8f1d17; }
.bt_verdict_h { font-size:13.5px; font-weight:700; color:#333; }
.bt_verdict_b { font-size:12px; line-height:1.6; color:#6b7280; margin-top:5px; }

/* The four figures the verdict rests on. A grid rather than the KPI band's flex
   row so they wrap into a block on a narrow panel instead of scrolling away. */
.bt_vkpis {
	display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
	gap:10px 18px; margin-top:10px;
}
.bt_vk_l { font-size:10px; text-transform:uppercase; letter-spacing:.04em; color:#9aa0a8; }
.bt_vk_v { font-size:16px; font-weight:600; color:#333; margin-top:1px; }
.bt_vk_v.is-ok  { color:#0b7d5e; }
.bt_vk_v.is-warn{ color:#a8620a; }
.bt_vk_v.is-bad { color:#8f1d17; }
.bt_vk_h { font-size:10.5px; color:#9aa0a8; margin-top:1px; }

body.appbuilder-dark .bt_verdict     { border-color:#3f4348; background:#26282b; }
body.appbuilder-dark .bt_verdict_h   { color:#eee; }
body.appbuilder-dark .bt_verdict_b   { color:#aab2bb; }
body.appbuilder-dark .bt_verdict_tag { background:#33363a; color:#aab2bb; }
body.appbuilder-dark .bt_verdict.is-ok   .bt_verdict_tag { background:#173a30; color:#5ed3a8; }
body.appbuilder-dark .bt_verdict.is-warn .bt_verdict_tag { background:#3a2f17; color:#e0a34a; }
body.appbuilder-dark .bt_verdict.is-bad  .bt_verdict_tag { background:#3a1e1c; color:#f0857c; }
body.appbuilder-dark .bt_verdict.is-ok   { border-left-color:#5ed3a8; }
body.appbuilder-dark .bt_verdict.is-warn { border-left-color:#e0a34a; }
body.appbuilder-dark .bt_verdict.is-bad  { border-left-color:#f0857c; }
body.appbuilder-dark .bt_vk_l, body.appbuilder-dark .bt_vk_h { color:#7d848c; }
body.appbuilder-dark .bt_vk_v        { color:#eee; }
body.appbuilder-dark .bt_vk_v.is-ok  { color:#5ed3a8; }
body.appbuilder-dark .bt_vk_v.is-warn{ color:#e0a34a; }
body.appbuilder-dark .bt_vk_v.is-bad { color:#f0857c; }

/* ---- A section header that answers its own question -------------------- */
/* The chip FLOATS rather than the summary becoming a flex row: any display
   other than list-item removes the browser's disclosure triangle, which these
   sections were deliberately switched back to. */
.bt_rep_q   { font-weight:700; }
.bt_rep_sub {
	font-weight:400; font-size:10.5px; color:#9aa0a8; margin-left:8px;
	text-transform:uppercase; letter-spacing:.04em;
}
.bt_rep_ans {
	float:right; margin-left:10px; font-size:10.5px; font-weight:600;
	padding:1px 8px; border-radius:10px; background:#eceff4; color:#6b7280;
	white-space:nowrap;
}
.bt_rep_ans.is-ok  { background:#e3f4ee; color:#0b7d5e; }
.bt_rep_ans.is-warn{ background:#fdf1dc; color:#a8620a; }
.bt_rep_ans.is-bad { background:#fbe6e4; color:#8f1d17; }
body.appbuilder-dark .bt_rep_sub  { color:#7d848c; }
body.appbuilder-dark .bt_rep_ans  { background:#33363a; color:#aab2bb; }
body.appbuilder-dark .bt_rep_ans.is-ok  { background:#173a30; color:#5ed3a8; }
body.appbuilder-dark .bt_rep_ans.is-warn{ background:#3a2f17; color:#e0a34a; }
body.appbuilder-dark .bt_rep_ans.is-bad { background:#3a1e1c; color:#f0857c; }

/* ---- The teaching block ------------------------------------------------ */
/* Static prose, in the three-part shape Builder_MetricHelp uses. Quieter than
   the data it explains: it is there to be found, not to compete. */
.bt_teach {
	margin-top:10px; padding:8px 10px; border-radius:5px; background:#f1f4f8;
	font-size:11px; line-height:1.6; color:#6b7280;
}
.bt_teach_r + .bt_teach_r { margin-top:5px; }
.bt_teach_r b { color:#333; font-weight:600; }
.bt_teach_r b::after { content:" \2014"; }
.bt_teach_r.is-caveat b { color:#a8620a; }
body.appbuilder-dark .bt_teach          { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .bt_teach_r b      { color:#eee; }
body.appbuilder-dark .bt_teach_r.is-caveat b { color:#e0a34a; }

/* The Leaderboard's Robustness card, reused inside a report section the way the
   equity card is. It brings its own card chrome, which nested inside .bt_rep
   would be a box drawn inside a box; its header stays, as a sub-heading that
   carries the seed and layer count. */
.bt_rep_b > .pl_card {
	background:none; border:0; border-radius:0; padding:0; margin:0 0 4px;
}
.bt_rep_b > .pl_card > .pl_card_h { margin-bottom:6px; }

/* ---- One gap between sections, everywhere ------------------------------ */
/* The report and the per-instrument breakdown are two .bt_report wrappers, so
   the gap between them was the first one's bottom padding PLUS the next
   section's top margin - twice the gap that separates any other pair. The
   trailing padding belongs to the last wrapper only. */
.bt_report:not(:last-child) { padding-bottom:0; }
/* Anything dropped straight into a wrapper alongside the sections - the verdict
   block, and any borrowed card - keeps the same rhythm as a section does. */
.bt_report > .pl_card { margin:8px 0 0; }

/* ---- A section that has nothing to measure ----------------------------- */
/* Printing arithmetic identities as though they were findings teaches the
   reader to distrust the whole row. Saying what it WOULD measure keeps the
   section educational when it cannot be informative. */
.bt_standdown {
	padding:8px 10px; border-radius:5px; background:#f1f4f8;
	border-left:3px solid #c9d1da; font-size:11.5px; line-height:1.6;
}
.bt_standdown_h { font-weight:600; color:#333; }
.bt_standdown_b { color:#6b7280; margin-top:3px; }
body.appbuilder-dark .bt_standdown   { background:#2c2f33; border-left-color:#4a4f55; }
body.appbuilder-dark .bt_standdown_h { color:#eee; }
body.appbuilder-dark .bt_standdown_b { color:#aab2bb; }

/* ---- Scripts card: the strategy's research standing ------------------- */
/* The Leaderboard, folded onto the card. Deliberately not sortable — see
   _StandingHTML. */
.ts_standing { display:flex; align-items:center; flex-wrap:wrap; gap:6px 8px; margin:4px 0 0; font-size:10.5px; }
.ts_dsr {
	font-weight:700; padding:1px 6px; border-radius:9px;
	background:#eef0f2; color:#6b7280; cursor:help;
}
.ts_dsr.is-ok   { background:#e3f4ee; color:#0b7d5e; }
.ts_dsr.is-warn { background:#fdf1dc; color:#a8620a; }
.ts_dsr.is-bad  { background:#fbe6e4; color:#8f1d17; }
/* ---- Graduation stage palette -------------------------------------------
   ONE definition per stage, exposed as custom properties, so the chip on a
   strategy card and the left edge of that strategy's pipeline card cannot
   drift apart: the colour belongs to the STAGE, not to the screen drawing it.
   --stage is the solid (borders), --stage-bg/--stage-fg the chip pair.
   Ordered as the pipeline runs: grey while unproven, blue once validated,
   violet past the holdout, amber while trading on paper, green graduated,
   red retired. */
/* Draft had no entry, so its chip rendered as bare text beside coloured ones. */
.stage-draft         { --stage:#b8bec8; --stage-bg:#f1f3f6; --stage-fg:#6b7280; }
.stage-testing       { --stage:#8a90a0; --stage-bg:#eceff3; --stage-fg:#5c6470; }
.stage-validated     { --stage:#1a5c9c; --stage-bg:#e6eff8; --stage-fg:#16537f; }
.stage-holdoutpassed { --stage:#7a3fa8; --stage-bg:#f0e8f8; --stage-fg:#66358c; }
.stage-papertrading  { --stage:#c9822b; --stage-bg:#fdf1dc; --stage-fg:#a8620a; }
.stage-graduated     { --stage:#2f7d4f; --stage-bg:#e3f4ee; --stage-fg:#0b7d5e; }
.stage-retired       { --stage:#b3261e; --stage-bg:#fbe6e4; --stage-fg:#8f1d17; }
body.appbuilder-dark .stage-draft         { --stage-bg:#2b2f35; --stage-fg:#9aa3ad; }
body.appbuilder-dark .stage-testing       { --stage-bg:#33373b; --stage-fg:#aab2bb; }
body.appbuilder-dark .stage-validated     { --stage-bg:#1c2c3d; --stage-fg:#7fb2e8; }
body.appbuilder-dark .stage-holdoutpassed { --stage-bg:#2b2038; --stage-fg:#c3a0e0; }
body.appbuilder-dark .stage-papertrading  { --stage-bg:#3a2f17; --stage-fg:#e0a34a; }
body.appbuilder-dark .stage-graduated     { --stage-bg:#173a30; --stage-fg:#5ed3a8; }
body.appbuilder-dark .stage-retired       { --stage-bg:#3a1e1c; --stage-fg:#f0857c; }

/* The chip. Falls back to the old flat treatment for a stage with no colour. */
.ts_stage  { text-transform:uppercase; letter-spacing:.04em; font-weight:600;
             background:var(--stage-bg, transparent); color:var(--stage-fg, #6b7280);
             padding:1px 6px; border-radius:9px; }
.ts_trials { color:#9aa0a8; }
body.appbuilder-dark .ts_dsr        { background:#33373b; color:#aab2bb; }
body.appbuilder-dark .ts_dsr.is-ok  { background:#173a30; color:#5ed3a8; }
body.appbuilder-dark .ts_dsr.is-warn{ background:#3a2f17; color:#e0a34a; }
body.appbuilder-dark .ts_dsr.is-bad { background:#3a1e1c; color:#f0857c; }
body.appbuilder-dark .ts_stage      { color:var(--stage-fg, #aab2bb); }
body.appbuilder-dark .ts_trials     { color:#7d848c; }

/* ---- Status tab: which portfolios trade this strategy ----------------- */
.ts_pf_card {
	margin:12px 14px 18px; padding:10px 12px; border:1px solid #e6e8ea; border-radius:6px;
	background:#fafbfc; font-family:OpenSans, sans-serif;
}
.ts_pf_h     { font-size:12px; font-weight:700; color:#333; margin-bottom:6px; }
.ts_pf_row   { display:flex; align-items:center; gap:8px; padding:4px 0; font-size:12px; color:#333; }
.ts_pf_n     { font-weight:600; }
/* The portfolio name is a link to that portfolio - styled as one so it reads as clickable
   rather than being a live target nobody would think to press. */
.ts_pf_link  { color:#1a5c9c; text-decoration:none; cursor:pointer; }
.ts_pf_link:hover { text-decoration:underline; }
body.appbuilder-dark .ts_pf_link { color:#7fb2e8; }
.ts_pf_s     { font-size:10px; text-transform:uppercase; letter-spacing:.04em;
               padding:1px 6px; border-radius:9px; background:#eef0f2; color:#6b7280; }
.ts_pf_off   { font-size:10px; color:#a8620a; }
.ts_pf_empty { font-size:11.5px; color:#9aa0a8; padding:4px 0; }
.ts_pf_act   { margin-top:8px; }
body.appbuilder-dark .ts_pf_card  { border-color:#3f4348; background:#26282b; }
body.appbuilder-dark .ts_pf_h     { color:#eee; }
body.appbuilder-dark .ts_pf_row   { color:#dfe3e7; }
body.appbuilder-dark .ts_pf_s     { background:#33373b; color:#aab2bb; }
body.appbuilder-dark .ts_pf_off   { color:#e0a34a; }
body.appbuilder-dark .ts_pf_empty { color:#7d848c; }

.tradescript_version_preview { height:100%; overflow:auto; padding:14px 16px; box-sizing:border-box; }
.tradescript_version_preview p   { margin:0 0 10px; font-size:12px; color:#6b7280; }
.tradescript_version_preview pre {
	margin:0; padding:12px; border-radius:4px; background:#f7f8fa; border:1px solid #eceff4;
	font-family:Consolas, Monaco, monospace; font-size:12px; line-height:1.5;
	white-space:pre; overflow:auto; color:#333;
}
body.appbuilder-dark .tradescript_version_preview p   { color:#aab2bb; }
body.appbuilder-dark .tradescript_version_preview pre { background:#1f2124; border-color:#3f4348; color:#e6e6e6; }

/* ---- classification chips ------------------------------------ */
/* Shared by the list cards and the editor header, so the two cannot drift.
   The header host absorbs the top bar's slack (the title no longer does),
   keeping title / language / chips together as one identity block. */
.tradescript_editor_chips {
	flex:0 1 auto; min-width:0; display:flex; flex-wrap:nowrap; overflow:hidden;
	align-items:center; gap:4px; cursor:pointer;
}
/* ---- Trade-script card rhythm -------------------------------------------
   The blocks (name, description, chips, standing, provenance) each carried
   their own margin - 4px, 4px, 4px, then an !important 8px - so the gaps
   stepped unevenly down the card and it read as a pile rather than a list.
   One flex column with a single gap makes the spacing identical whichever
   blocks a given script actually has, which is the real source of the
   inconsistency: no two scripts have the same set. */
.ts_card .applications_element_text { display:flex; flex-direction:column; gap:5px; }
.ts_card .applications_element_text > p,
.ts_card .ts_chiprow,
.ts_card .ts_standing { margin:0 !important; }
/* The provenance line is the footer: pushed to the bottom of the gap scale so
   it separates from the content it describes without a rule. */
.ts_card .applications_element_meta { margin-top:2px !important; }
.ts_card .applications_element_text > span.ts_pick_name { line-height:1.35; }
/* Two lines, not three. The text box is a fixed 156px with overflow:hidden, and a script
   card carries more below the description than an app card does (chips, DSR/stage/trials,
   provenance) - the third line was the one pushing the chip row into the clip. */
.ts_card .applications_element_desc { -webkit-line-clamp:2 !important; line-clamp:2 !important; }
/* Wrapped chip rows need their own row-gap, and the chips need a hair of vertical padding:
   a 1px clip is invisible on a filled chip but takes the whole bottom stroke off an
   outlined tag, which is why only the tags looked cut off. */
.ts_card .ts_chiprow { row-gap:5px; align-items:center; }
.ts_card .ts_chip    { line-height:1.5; padding:2px 8px; }

.ts_chiprow { margin:4px 0 0 0; display:flex; flex-wrap:wrap; gap:4px; }

.ts_chip {
	display:inline-flex; align-items:center; flex:0 0 auto;
	font-family:'Open Sans', sans-serif; font-size:10.5px; line-height:1.6;
	padding:1px 8px; border-radius:10px; white-space:nowrap;
	background:#eef2f7; color:#4a6b8a;
}
/* Type is the one chip that carries meaning at a glance — it decides whether a
   script can be backtested — so it is the only one that gets weight + colour.
   The colour itself comes from the _strategy / _indicator variants below. */
.ts_chip_type      { font-weight:600; }
.ts_chip_strategy  { background:#e3f3e8; color:#1d7a41; }
.ts_chip_indicator { background:#e9edf5; color:#4a5b7a; }
.ts_chip_cat       { background:#f0ecf7; color:#5d4a8a; }
/* Tags are OUTLINED where type and category are solid. Three solid pastel chips in a
   row all read as the same kind of thing; the one-glance question is "what IS this
   script" (type + category) versus "what is it about" (tags), and fill vs outline says
   that without a legend. Each chip also names its kind in its tooltip. */
.ts_chip_tag       { background:transparent; color:#5f6673; box-shadow:inset 0 0 0 1px #d8dce2; }
.ts_chip_more      { background:transparent; color:#8a8f98; padding-left:2px; }
/* Empty state: an unclassified script still needs somewhere to click. */
.ts_chip_empty     { background:transparent; color:#9aa0a8; border:1px dashed #cfd4da; }
.tradescript_editor_chips:hover .ts_chip_empty { color:#4a6b8a; border-color:#9bb6d0; }

body.appbuilder-dark .ts_chip           { background:#3f4348; color:#c6d2df; }
body.appbuilder-dark .ts_chip_strategy  { background:#1f4430; color:#7fd8a3; }
body.appbuilder-dark .ts_chip_indicator { background:#2f3644; color:#a9b8d0; }
body.appbuilder-dark .ts_chip_cat       { background:#3a3350; color:#c0aee8; }
body.appbuilder-dark .ts_chip_tag       { background:transparent; color:#adb5bd;
                                          box-shadow:inset 0 0 0 1px #4a4f56; }
body.appbuilder-dark .ts_chip_more      { background:transparent; color:#8a8f98; }
body.appbuilder-dark .ts_chip_empty     { background:transparent; color:#7d848c; border-color:#4a4f56; }
body.appbuilder-dark .tradescript_editor_chips:hover .ts_chip_empty { color:#c6d2df; border-color:#6b7480; }

/* Live description under the Category picker in the Properties dialog. The
   category names are not self-explanatory and the descriptions are too long
   for dropdown rows, so the selected one is spelled out here. */
.ts_cat_help {
	margin:-6px 0 10px 0; padding:0 0 0 2px;
	font-family:'Open Sans', sans-serif; font-size:11px; line-height:1.45; color:#6b7280;
}
body.appbuilder-dark .ts_cat_help { color:#9aa4b0; }

/* Group label on tag dropdown rows — 84 tags need the family visible. */
.ts_tagdrop_group {
	display:inline-block; min-width:88px; margin-right:8px;
	font-size:10px; text-transform:uppercase; letter-spacing:0.04em; color:#9aa0a8;
}
body.appbuilder-dark .ts_tagdrop_group { color:#7d848c; }

/* Compile succeeded — the green counterpart of tradescript_results_error. */
.tradescript_compile_ok {
	display:flex; align-items:center; gap:6px;
	color:#1d7a41; background:#eef7f1; border:1px solid #c6e3d1;
	border-radius:4px; padding:8px 10px;
}
body.appbuilder-dark .tradescript_compile_ok { color:#7fd8a3; background:#1c3a28; border-color:#2c5a3f; }

.ts_typemismatch { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ts_typefix      { flex:0 0 auto; }

/* Data-source controls in the editor top bar: symbol + timeframe +
   range. Blank symbol = fixture bars, so the placeholder says so. */
.tradescript_symbol_input {
	width:150px; box-sizing:border-box; padding:4px 8px;
	font: 12px "Fira Code", Menlo, Consolas, monospace;
	border:1px solid #d8d6d2; border-radius:4px;
	background:#fff; color:#27251E; outline:none;
}
.tradescript_symbol_input::placeholder { font-family:OpenSans, sans-serif; font-style:italic; color:#999; }
.tradescript_symbol_input:focus        { border-color:#2F9EEE; box-shadow:0 0 0 1px #2F9EEE inset; }
.tradescript_pick_host                 { display:inline-flex; }
.tradescript_pick_host .wf-pickbtn     { min-width:104px; }
body.appbuilder-dark .tradescript_symbol_input {
	background:#1a1a1a; border-color:#3a3a3a; color:#e6e6e6;
}
body.appbuilder-dark .tradescript_symbol_input::placeholder { color:#7a8290; }

/* Results panel below the editor. Placeholder-styled by default;
   the empty-state class dims + italicises to signal "no run yet". */
.tradescript_results {
	width:100%; height:100%;
	overflow:auto; box-sizing:border-box; padding:12px;
	font-family:OpenSans, sans-serif; font-size:13px; color:#333;
	background:#FAF8F5;
}
.tradescript_results_empty  { color:#888; font-style:italic; }
/* Chart-first layout. The results pane drops its padding and scrolling
   so the chart can own the box; a bar of run metadata sits above it at
   its natural height and the chart takes the rest. No own resize handle
   — the panel splitter is what sizes the chart, and a second resizer on
   the same axis just fights it. */
.tradescript_results.tradescript_results_haschart { padding:0; overflow:hidden; }
.tradescript_chart_wrap     { width:100%; height:100%; display:flex; flex-direction:column; }
.tradescript_chart_bar      { flex:0 0 auto; display:flex; align-items:center; gap:6px;
	padding:6px 12px; border-bottom:1px solid #e2e2e2; background:#fafafa; }
.tradescript_chart_title    { flex:1; font:11px OpenSans, sans-serif; color:#4a6b8a;
	white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.tradescript_chart_host     { flex:1 1 auto; min-height:0; width:100%; overflow:hidden; }
/* (.tradescript_details_pane was the Metrics panel's whole-panel scroller. It
   now uses the same fixed-head shell as Trades — see .ts_trades_pane below —
   and nothing else referenced the class, so it is gone rather than left
   sitting in the sheet as a second way to build the same panel.) */

/* Chart / Details toggle — segmented pair, right-anchored in the bar. */
/* Stale-data marker — the run used cached bars because the source was
   unreachable. Amber rather than red: the result is usable, just not
   current. */
.tradescript_chart_stale    { flex:0 0 auto; cursor:help; font:11px OpenSans, sans-serif;
	color:#8a5a00; background:#fff4e0; border-radius:10px; padding:2px 8px; }
.tradescript_results_warn   { color:#8a5a00; background:#fff4e0; border:1px solid #e5d9b6;
	border-radius:4px; padding:8px 10px; font-size:12px; }
body.appbuilder-dark .tradescript_chart_stale  { color:#f0d38e; background:#4a3a1c; }
body.appbuilder-dark .tradescript_results_warn { color:#f0d38e; background:#4a3a1c; border-color:#6b5426; }
/* The editor's own title bar. Same visual weight as the chart bar in Test, so
   the two tabs read as siblings rather than as two different screens. */
.tradescript_editbar {
	flex:0 0 auto; display:flex; align-items:center; gap:6px;
	padding:6px 12px; border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.tradescript_editbar_title  { font: 600 11px OpenSans, sans-serif; text-transform:uppercase;
	letter-spacing:0.05em; color:#4a6b8a; }
.tradescript_editbar_spacer { flex:1 1 auto; }
/* The toggle came from the global top bar, where the surrounding rule gave it
   its box. Restated here so it keeps the same size beside Compile. */
.tradescript_editbar .tradescript_chat_toggle { margin-left:2px; }
body.appbuilder-dark .tradescript_editbar { background:#34383c; border-bottom-color:#3f4348; }
body.appbuilder-dark .tradescript_editbar_title { color:#a9c5e0; }

/* No layout rules needed for the two tab bodies: .tradescript_tabbody is already
   a flex column with min-height:0, and .tradescript_editor_split already claims
   flex:1 — so inserting the bar above the split just works. */

/* ---- Metrics panel ------------------------------------------------------
   Stacked sections, each with its own head. More are coming, so the section is
   the unit: nothing here assumes how many there are or what order they sit in. */
.ts_metrics       { display:flex; flex-direction:column; gap:26px; }
.ts_msec          { display:flex; flex-direction:column; gap:8px; }
.ts_msec_h        { display:flex; align-items:center; gap:6px;
	font: 600 13px OpenSans, sans-serif; color:#222; }
.ts_msec_sub      { font: 600 11px OpenSans, sans-serif; text-transform:uppercase;
	letter-spacing:0.05em; color:#4a6b8a; margin-top:6px; }
.ts_msec_hint     { color:#9a9a9a; font-size:11px; cursor:help; }
body.appbuilder-dark .ts_msec_h   { color:#e6e6e6; }
body.appbuilder-dark .ts_msec_sub { color:#a9c5e0; }
/* A ruled divider between stacked sections — the gap alone read as one long list. */
.ts_msec + .ts_msec { border-top:1px solid #e3e3e3; padding-top:26px; }
body.appbuilder-dark .ts_msec + .ts_msec { border-top-color:#2c2c33; }

/* GRID, not flex-wrap. Flex sized each row independently — the last row had
   four items where the first had ten, so every column moved between rows and
   nothing lined up. auto-fill + 1fr gives every tile the SAME width, so row two
   sits under row one. A KPI strip whose columns shift cannot be read at a
   glance, which is the only way it is read. */
.ts_tiles     { display:grid; grid-template-columns:repeat(auto-fill, minmax(172px, 1fr));
	row-gap:14px; column-gap:8px; }
.ts_tile      { min-width:0; display:flex; flex-direction:column; gap:3px; }
.ts_tile_k    { font:11px OpenSans, sans-serif; color:#8a8a8a; white-space:nowrap;
	overflow:hidden; text-overflow:ellipsis; }
.ts_tile_v    { font: 600 15px OpenSans, sans-serif; color:#222;
	font-variant-numeric:tabular-nums; white-space:nowrap;
	overflow:hidden; text-overflow:ellipsis; }
.ts_tile_v.ts_pos { color:#2E7D32; }
.ts_tile_v.ts_neg { color:#C0392B; }
/* The secondary figure rides on the primary's baseline — a percentage beside an
   amount is the same fact twice, not a second fact on its own line. */
.ts_tile_sub  { margin-left:6px; font: 400 11px OpenSans, sans-serif; color:#8a8a8a; }
body.appbuilder-dark .ts_tile_v { color:#e6e6e6; }
body.appbuilder-dark .ts_tile_v.ts_pos { color:#66BB6A; }
body.appbuilder-dark .ts_tile_v.ts_neg { color:#EF6B5B; }

/* Charts get a definite height: ECharts measures its host at init, and a host
   sized only by its content is zero pixels tall at that moment. */
.ts_mchart      { width:100%; height:220px; }
.ts_mchart_tall { height:400px; }
/* No negative margin pulling a chart up under its header — that was a hack, and
   it breaks the moment a section title wraps to two lines. The gap belongs to
   .ts_msec's own row spacing. */
/* Four categories stretched across a wide panel put a bar every 400px and read
   as four unrelated numbers. Capped so the cascade stays a cascade. */
.ts_mchart_narrow { max-width:800px; }
/* Pull the toolbox charts up under their header: the chart reserves a top band for the
   top-right buttons and axis label, which otherwise sits as dead space below the header.
   Overlapping it with the header row (title left, buttons right) reclaims ~20px. */
.ts_mchart_tall, .ts_mchart_narrow { margin-top:-20px; }
/* Diagnostics: a heuristic read of the result — one row per finding, dot coloured by severity. */
.ts_diag     { display:flex; flex-direction:column; gap:11px; }
.ts_diag_row { display:flex; gap:10px; align-items:flex-start; font-size:12px; line-height:1.45; }
.ts_diag_dot { flex:0 0 8px; width:8px; height:8px; border-radius:50%; margin-top:4px; }
.ts_diag_tip { color:#6b7280; margin-top:1px; }
body.appbuilder-dark .ts_diag_tip { color:#9aa0ac; }
.ts_diag_deep      { margin-top:4px; }
.ts_diag_deepcard  { background:#f2effb; border:1px solid #e6def5; border-radius:6px; padding:10px 12px; }
.ts_diag_deepbody  { font-size:12px; line-height:1.6; }
.ts_diag_deepbody p { margin:0 0 8px; }
.ts_diag_deepbody p:last-child { margin-bottom:0; }
.ts_diag_deepact   { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:8px; }
.ts_diag_deephint  { font-size:11px; color:#9aa0a8; }
.ts_diag_pending   { font-size:12px; color:#8a9099; }
body.appbuilder-dark .ts_diag_deepcard { background:#241e36; border-color:#3a3155; }
body.appbuilder-dark .ts_diag_deephint,
body.appbuilder-dark .ts_diag_pending  { color:#9aa0ac; }

/* Compile output: a strip, not a panel. Scrolls when a stack trace needs it. */
.tradescript_compile_pane { height:100%; overflow:auto; padding:8px 12px; font-size:12px; }

/* Headline stats in the bar — the outcome of Apply, before you pick a view.
   Sits between the title (which ellipsises) and the tabs, and never shrinks:
   these four numbers are the point of the bar. */
.ts_stats      { flex:0 0 auto; display:inline-flex; gap:12px; align-items:center;
	margin-right:10px; font:11px OpenSans, sans-serif; white-space:nowrap; }
.ts_stat_k     { color:#8a8a8a; margin-right:4px; }
.ts_stat_v     { font-weight:600; font-variant-numeric:tabular-nums; color:#333; }
.ts_stat.ts_pos   .ts_stat_v { color:#2E7D32; }
.ts_stat.ts_neg   .ts_stat_v { color:#C0392B; }
.ts_stat.ts_stale .ts_stat_v { color:#8a5a00; }
.ts_stat.ts_stale .ts_stat_k { color:#8a5a00; }
body.appbuilder-dark .ts_stat_v { color:#e6e6e6; }
body.appbuilder-dark .ts_stat_k { color:#9a9a9a; }
body.appbuilder-dark .ts_stat.ts_pos   .ts_stat_v { color:#66BB6A; }
body.appbuilder-dark .ts_stat.ts_neg   .ts_stat_v { color:#EF6B5B; }
body.appbuilder-dark .ts_stat.ts_stale .ts_stat_v,
body.appbuilder-dark .ts_stat.ts_stale .ts_stat_k { color:#f0d38e; }

/* Fixed head over a scrolling body — the Test tab's shell.
   Trades uses it (title + sort + download over the rows) and so does Metrics
   (title over the stacked sections). ONE set of rules with grouped selectors
   rather than a second copy under different names: the two panes are siblings
   in the same tab strip and the moment their heads are declared separately
   they start drifting apart by a pixel or two. */
.ts_trades_pane,
.ts_metrics_pane   { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
.ts_trades_head,
.ts_metrics_head   { flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
	gap:10px; padding:8px 12px 6px; }
.ts_trades_title,
.ts_metrics_title  { font: 600 11px OpenSans, sans-serif; text-transform:uppercase;
	letter-spacing:0.05em; color:#4a6b8a; }
.ts_trades_act     { flex:0 0 auto; display:inline-flex; gap:6px; align-items:center; }
.ts_trades_scroll,
.ts_metrics_scroll { flex:1 1 auto; min-height:0; overflow:auto; padding:0 12px 12px; }

/* STICKY HEADER — the two things that made it twitch.
   1. `border-collapse: collapse` gives the borders to the TABLE, not the cells,
      so a sticky th carries no border of its own and the first row slides a
      pixel under it on every scroll reversal. Separate borders + a box-shadow
      rule keeps the line attached to the header that owns it.
   2. The shared table style sets `margin-top:2px`. The header therefore began
      2px below the scroll origin and jumped exactly that far the moment it
      stuck — the up-and-down flicker when scrolling around the top. */
.ts_trades_scroll .tradescript_results_table {
	border-collapse:separate; border-spacing:0; margin-top:0;
}
.ts_trades_scroll .tradescript_results_table td { border-bottom:1px solid #ececec; }
.ts_trades_scroll .tradescript_results_table thead th {
	position:sticky; top:0; z-index:1; background:#fff; border-bottom:0;
	box-shadow:inset 0 -1px 0 #ececec;
}
body.appbuilder-dark .ts_trades_title { color:#a9c5e0; }
body.appbuilder-dark .ts_trades_scroll .tradescript_results_table td { border-bottom-color:#3f4348; }
body.appbuilder-dark .ts_trades_scroll .tradescript_results_table thead th {
	background:#2a2b2f; box-shadow:inset 0 -1px 0 #3f4348;
}

/* Long and short are opposite bets — every other number on the row means the
   reverse depending on which it was, so the side is a badge, not a word. */
.ts_side { display:inline-block; min-width:44px; text-align:center;
	font: 600 10px OpenSans, sans-serif; text-transform:uppercase; letter-spacing:0.04em;
	padding:1px 6px; border-radius:3px; background:#eceff1; color:#666; }
.ts_side.is-long  { background:#e3f4ea; color:#2E7D32; }
.ts_side.is-short { background:#fbe6e4; color:#C0392B; }
body.appbuilder-dark .ts_side           { background:#3a3d42; color:#a0a0a0; }
body.appbuilder-dark .ts_side.is-long   { background:#173a2a; color:#66BB6A; }
body.appbuilder-dark .ts_side.is-short  { background:#3a1e1c; color:#EF6B5B; }

/* Timestamps: tabular so the columns line up by place, and never wrapped —
   a date broken across two lines doubles the row height for nothing. */
.ts_when { font-variant-numeric:tabular-nums; white-space:nowrap; color:#666; font-size:11px; }
body.appbuilder-dark .ts_when { color:#9a9a9a; }

/* Commission is always a deduction, never a result — muted so it reads as the
   cost line it is and does not compete with the green/red of the PnL beside it. */
.ts_fee { color:#8a8a8a; }
body.appbuilder-dark .ts_fee { color:#8a8a8a; }

.tradescript_view_tabs      { flex:0 0 auto; display:inline-flex; }
.tradescript_view_tab {
	border:1px solid #d8d6d2; background:#fff; color:#666;
	font:11px OpenSans, sans-serif; padding:3px 10px; cursor:pointer;
}
.tradescript_view_tab:first-child { border-radius:4px 0 0 4px; }
.tradescript_view_tab:last-child  { border-radius:0 4px 4px 0; }
/* Collapse the shared edge on EVERY seam, not just the last one. With two tabs
   `:last-child` happened to cover the only seam there was; a third tab made the
   middle join draw two 1px borders side by side. */
.tradescript_view_tab + .tradescript_view_tab { border-left:0; }
.tradescript_view_tab:hover       { background:#f2f0ec; }
.tradescript_view_tab.is-active   { background:#2F9EEE; border-color:#2F9EEE; color:#fff; }
.tradescript_view_tab .fa         { font-size:10px; }
body.appbuilder-dark .tradescript_chart_bar   { background:#34383c; border-bottom-color:#3f4348; }
body.appbuilder-dark .tradescript_chart_title { color:#a9c5e0; }
body.appbuilder-dark .tradescript_view_tab            { background:#2a2b2f; border-color:#3f4348; color:#a0a0a0; }
body.appbuilder-dark .tradescript_view_tab:hover      { background:#34383c; }
body.appbuilder-dark .tradescript_view_tab.is-active  { background:#2F9EEE; border-color:#2F9EEE; color:#fff; }
.tradescript_results_tick   { margin-top:3px; }
.tradescript_results_tick code { background:#eef2f7; padding:1px 4px; border-radius:3px;
	font: 11px "Fira Code", Menlo, Consolas, monospace; color:#333; }
body.appbuilder-dark .tradescript_results_tick code { background:#3f4348; color:#e6e6e6; }
.tradescript_results_pending{ color:#4a6b8a; margin-bottom:8px; }
.tradescript_results_hint   { background:#fafafa; border:1px solid #ececec; border-radius:3px;
	padding:6px 8px; margin:0; font: 12px "Fira Code", Menlo, Consolas, monospace;
	white-space:pre-wrap; word-break:break-word; color:#666; }
.tradescript_results_section { margin-bottom:14px; }
.tradescript_results_label   { font: 600 11px OpenSans, sans-serif; text-transform:uppercase;
	letter-spacing:0.05em; color:#4a6b8a; margin-bottom:4px; }
.tradescript_results_kv      { font-size:13px; color:#333; }
.tradescript_results_kv_key  { font-weight:600; text-transform:capitalize; }
.tradescript_results_kv_val  { color:#666; }
.tradescript_results_muted   { color:#888; font-size:11px; }
.tradescript_results_range   { color:#4a6b8a; font: 11px "Fira Code", Menlo, Consolas, monospace; }
.tradescript_results_list    { margin:0; padding-left:18px; font-size:13px; color:#333; }
.tradescript_results_list li { line-height:1.6; }
.tradescript_results_list code { background:#eef2f7; padding:1px 4px; border-radius:3px;
	font: 11px "Fira Code", Menlo, Consolas, monospace; color:#333; }
.tradescript_results_table   { width:100%; border-collapse:collapse; margin-top:2px; font-size:12px; }
.tradescript_results_table th,
.tradescript_results_table td { padding:4px 8px; border-bottom:1px solid #ececec; text-align:left; }
.tradescript_results_table th { font-weight:600; color:#4a6b8a; }
/* Numeric columns right-align and tabular-figure so amounts stack cleanly by
   place value — the trades table is mostly money and reads as a ledger. */
.tradescript_results_table th.num,
.tradescript_results_table td.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.tradescript_trades_table td[data-tooltip] { cursor:help; }
.tradescript_results_pos     { color:#2E7D32; }
.tradescript_results_neg     { color:#C0392B; }
.tradescript_results_pnl     { display:flex; gap:24px; padding-top:8px;
	border-top:1px solid #ececec; font-size:13px; color:#333; }
.tradescript_results_error   { background:#fce8e6; border:1px solid #f5b6ae; border-radius:3px;
	padding:8px 10px; }
.tradescript_results_error_title { font-weight:600; color:#C0392B; margin-bottom:4px; }
.tradescript_results_error pre { margin:0; font: 12px "Fira Code", Menlo, Consolas, monospace;
	white-space:pre-wrap; word-break:break-word; color:#7a1e14; }
.tradescript_results_goto    { color:#C0392B !important; margin-top:6px !important; margin-left:0 !important; }
/* Offending line in the editor, from PineException.Line. */
.tradescript_cm_error_line   { background: rgba(192, 57, 43, 0.13); }
body.appbuilder-dark .tradescript_cm_error_line { background: rgba(239, 154, 154, 0.14); }
body.appbuilder-dark .tradescript_results_goto  { color:#EF9A9A !important; }
body.appbuilder-dark .tradescript_results_label { color:#a9c5e0; }
body.appbuilder-dark .tradescript_results_kv    { color:#e6e6e6; }
body.appbuilder-dark .tradescript_results_kv_val{ color:#a0a0a0; }
body.appbuilder-dark .tradescript_results_muted { color:#7a8290; }
body.appbuilder-dark .tradescript_results_range { color:#a9c5e0; }
body.appbuilder-dark .tradescript_results_list  { color:#e6e6e6; }
body.appbuilder-dark .tradescript_results_list code { background:#3f4348; color:#e6e6e6; }
body.appbuilder-dark .tradescript_results_table th { color:#a9c5e0; }
body.appbuilder-dark .tradescript_results_table th,
body.appbuilder-dark .tradescript_results_table td { border-bottom-color:#3f4348; }
body.appbuilder-dark .tradescript_results_pos   { color:#81C784; }
body.appbuilder-dark .tradescript_results_neg   { color:#EF9A9A; }
body.appbuilder-dark .tradescript_results_pnl   { border-top-color:#3f4348; color:#e6e6e6; }
body.appbuilder-dark .tradescript_results_error { background:#4b2626; border-color:#7a4040; }
body.appbuilder-dark .tradescript_results_error_title { color:#EF9A9A; }
body.appbuilder-dark .tradescript_results_error pre   { color:#f2c6c1; }
body.appbuilder-dark .tradescript_results         { background:#282c30; color:#e6e6e6; }
body.appbuilder-dark .tradescript_results_empty   { color:#a0a0a0; }
body.appbuilder-dark .tradescript_results_pending { color:#a9c5e0; }
body.appbuilder-dark .tradescript_results_hint    { background:#24262b; border-color:#3a3b40; color:#a0a0a0; }
/* The editor body is the CONTENT of a w2layout panel, not a flex child —
   the panel gives it a box and it has to fill it, or CodeMirror measures
   zero height and the editor collapses to a couple of lines. */
.tradescript_editor_body        { width:100%; height:100%; padding:12px; box-sizing:border-box; overflow:hidden; }
.tradescript_editor_body_middle { width:100%; height:100%; padding:8px; border-radius:12px; box-sizing:border-box; overflow:hidden; }
.tradescript_editor_body_inner  { width:100%; height:100%; border-radius:12px; overflow:hidden; position:relative; display:flex; }
.tradescript_editor_body_inner .CodeMirror { flex:1; width:100%; height:100%; font-family: Menlo, Consolas, 'Courier New', monospace; font-size:13px; line-height:1.5; }
/* Minimap down the RIGHT edge. The container is already a flex row and CodeMirror is
   `flex:1` (basis 0, so its width:100% does not fight this), which means a fixed basis
   here is all it takes for the code area to claim the rest. min-width:0 lets CM shrink
   below its content width instead of pushing the canvas off. */
.ts_minimap { flex:0 0 62px; width:62px; height:100%; display:block; cursor:pointer;
              background:#fbfbfc; border-left:1px solid #e6e8ea; }
.tradescript_editor_body_inner .CodeMirror { min-width:0; }
body.appbuilder-dark .ts_minimap { background:#22252b; border-left-color:#33373d; }
.tradescript-editor          { flex:1; width:100%; box-sizing:border-box; border:0; padding:16px; resize:none; font-family: Menlo, Consolas, 'Courier New', monospace; font-size:13px; line-height:1.5; background:#ffffff; color:#222; outline:none; }
.tradescript-editor:focus    { background:#fdfdfa; }

body.appbuilder-dark .tradescript_editor_title   { color:#eee; }
body.appbuilder-dark .tradescript_editor_lang    { background:#3f4348; color:#c6d2df; }
body.appbuilder-dark .tradescript-editor         { background:#1f2124; color:#e6e6e6; }
body.appbuilder-dark .tradescript-editor:focus   { background:#22262a; }
/* CodeMirror dark-mode colors are set together with the SQL
   editor higher up (search "DB console SQL editor + Trade Script")
   — do NOT redeclare them here; a later-in-file duplicate would
   silently drift the two editors apart on the next design change. */

/* ============================================================
   Screener — TradingView-style instrument screener contributed by
   the trade-script package as a left-nav entry.

   Local tokens follow the --cp-* model used by the Cover Page: one
   light set here, remapped onto the global vars under
   body.appbuilder-dark, so a colour is stated once per theme rather
   than duplicated across every rule.
   ============================================================ */
.screener-standalone-panel {
	--scr-border:   #e2e2e2;
	--scr-bg:       #ffffff;
	--scr-bg-soft:  #fafafa;
	--scr-fg:       #27251E;
	--scr-fg-muted: #808080;
	--scr-accent:   #2F9EEE;
	font-family: OpenSans, sans-serif;
}
body.appbuilder-dark .screener-standalone-panel {
	--scr-border:   var(--border, #3a3a3a);
	--scr-bg:       var(--bg-panel, #2b2b2b);
	--scr-bg-soft:  var(--bg-alt, #222222);
	--scr-fg:       var(--fg, #e6e6e6);
	--scr-fg-muted: var(--fg-muted, #a0a0a0);
}

/* ---- backtests panel ----------------------------------------- */
/* Card extras. The card frame, grid and hover all come from
   .applications_element — only what a backtest card says that a script card
   does not is defined here. The status chip is absolutely positioned like the
   Published tag it sits in place of. */
/* Title row: the name clips with an ellipsis; the (?) help stays whole beside
   it. Right padding reserves the corner the status chip is pinned to, so the
   name never runs UNDER the chip. */
.bt_card_title {
	display:flex; align-items:center; gap:5px;
	padding-right:62px; line-height:20px;
}
.bt_card_name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Two-line clamp on the card (the shared desc class clamps to three): a
   backtest card also carries a facts line and a return figure, so it has less
   room than a script card. */
.bt_card_desc { -webkit-line-clamp: 2 !important; margin-top:3px; font-size:11.5px; }
.bt_help {
	font-weight:400; color:#9aa0a8; cursor:help; font-size:12px; margin-left:4px;
}
.bt_help:hover { color:var(--scr-accent, #0a66c2); }

.bt_card_facts {
	margin:4px 0 0; font-size:11px; color:#6b7280;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.bt_card_perf   { margin:6px 0 0; font-size:14px; font-weight:600; font-family:'Open Sans', sans-serif; }
.bt_card_perf_k { font-size:10.5px; font-weight:400; color:#9aa0a8; }

/* font-family stated: the chip sits directly under .applications_element, not
   inside the OpenSans text container, so without this it fell back to the UA
   serif default. */
.bt_chip {
	position:absolute; top:10px; right:10px;
	font-family:'Open Sans', sans-serif;
	font-size:10px; padding:1px 7px; border-radius:9px; white-space:nowrap;
}
/* Inside the detail header the chip is part of the flow, not pinned to a
   card corner. */
.bt_detail_head .bt_chip { position:static; }
.bt_gridchip .bt_chip    { position:static; display:inline-block; }
.bt_chip.is-draft   { background:#eceff4; color:#6b7280; }
.bt_chip.is-running { background:#e8f1fb; color:#1a5c9c; }
.bt_chip.is-done    { background:#e6f4ec; color:#116b3a; }
.bt_chip.is-failed  { background:#fbeaea; color:#b3261e; }

/* ---- Portfolio cards (Builder_Portfolios) --------------------------------
   Same card anatomy as the backtest cards — badge, chip, title, facts, headline
   figure — so the two directories read as one family. */
.pf_card_title {
	display:flex; align-items:center; gap:5px;
	padding-right:76px; line-height:20px;
}
.pf_card_name  { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf_card_desc  { -webkit-line-clamp: 2 !important; margin-top:3px; font-size:11.5px; }
.pf_card_chips { margin:3px 0 0; min-height:0; }
.pf_card_facts {
	margin:4px 0 0; font-size:11px; color:#6b7280;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.pf_card_perf   { margin:6px 0 0; font-size:14px; font-weight:600; font-family:'Open Sans', sans-serif; }
.pf_card_cap    { color:#27251E; }
.pf_card_perf_k { font-size:10.5px; font-weight:400; color:#9aa0a8; }

/* Status chip pinned to the card corner. font-family stated for the same reason
   as .bt_chip: it sits outside the OpenSans text container. */
/* A small status pill. APPEARANCE only — it used to carry
   `position:absolute; top:10px; right:10px`, which is a PLACEMENT, and every
   consumer that wanted the pill in normal flow had to opt back out: the news
   chip did, the panel header did, and the intent table's Approved/Rejected chip
   did not — so it flew to the corner of the Intent queue card and left the
   Status column looking empty. The card corner now opts IN instead. */
/* `.rs_chip` (the research package's chips) shares this GEOMETRY rather than
   restating it. The two families sit in the same rows — a theme card's stage
   chip beside a portfolio-style control — and a row of two chip heights is
   exactly the raggedness the padding note below had to fix once already. Only
   the COLOURS are separate, deliberately: a research stage and a runtime status
   must never be confusable at a glance. */
.pf_chip,
.rs_chip {
	/* inline-FLEX, not inline-block: the chip holds a dot and a label, and only
	   flex centres a 7px icon against 10px text reliably. `gap` spaces them, so
	   the markup carries no &nbsp; to knock the label off-centre.
	   `vertical-align:middle` centres the chip itself against neighbouring text
	   where it is not already inside a flex row. */
	display:inline-flex; align-items:center; gap:5px; vertical-align:middle;
	font-family:'Open Sans', sans-serif;
	/* Padding + line-height give it the height of the line it sits on; at
	   1px/1.0 it read as a sliver against a 17px title. */
	font-size:10px; line-height:1.5; padding:3px 9px;
	border-radius:10px; white-space:nowrap;
}
/* The one placement that wants pinning: the badge on a directory card. */
.applications_element > .pf_chip { position:absolute; top:10px; right:10px; }
.pf_chip.is-draft   { background:#eceff4; color:#6b7280; }
.pf_chip.is-armed   { background:#fdf3e3; color:#9a6a10; }
.pf_chip.is-running { background:#e6f4ec; color:#116b3a; }
.pf_chip.is-paused  { background:#eceff4; color:#6b7280; }
.pf_chip.is-stopped { background:#fbeaea; color:#b3261e; }
.pf_chip.is-protective { background:#eaf1fd; color:#1c53b8; }
/* ERROR is not just another stopped: it broke rather than being turned off, so
   it carries a border and heavier weight to read as an alert at a glance, not a
   quiet grey-red like stopped. */
.pf_chip.is-error   { background:#fdE7E5; color:#a01a12; border:1px solid #eaa9a2; font-weight:700; }
/* A painted box, not the fa-circle glyph it used to be — see the note at the
   markup. Explicit width/height rather than font-size, so the circle has a real
   geometric centre for `transform` to scale about (a glyph does not) and no
   text rasterisation to redo mid-animation. */
.pf_chip_live {
	flex:0 0 auto; width:8px; height:8px; border-radius:50%;
	background:currentColor;
	/* Promote to its own layer: without it the browser is free to re-rasterise
	   the circle at each scale step, which is the same stepped, trembly growth
	   the glyph had. */
	will-change:transform;
}

/* A LIVE portfolio breathes. "Running" as static text is indistinguishable
   from "Running" left over on a page that stopped polling ten minutes ago —
   the whole point of the state is that something is happening right now, and
   motion is the only way to say that without another number to read.

   THREE things move together, because at 8px any one of them alone is too
   small to notice from across a directory: the dot inflates and deflates, it
   swings between a deep and a bright green, and a halo blooms around it.
   The AMOUNT took two corrections in both directions — opacity alone was
   invisible, then scale 0.68→1.5 with a hard colour swing was a throb you
   could not look away from. The setting below is the third try and the point
   is the ratio, not the mechanism: peak is about 1.4x the trough rather than
   2.2x, and the two greens are a shade apart rather than a contrast. It has
   to be findable in peripheral vision without becoming the loudest thing on a
   screen full of numbers that actually matter.

   TRANSFORM, not width/font-size. The dot is a flex item between the chip's
   padding and its label; anything that changes its LAYOUT box would shove the
   text sideways twice a second. A transform is painted, not laid out, so the
   chip stays perfectly still while the dot moves inside it. The halo scales
   with it (box-shadow is transformed too), which is what makes 4px read as a
   bloom rather than a ring.

   1.6s and ease-in-out: slow enough that a wall of thirty running portfolios
   reads as breathing rather than blinking. The keyframes are per theme rather
   than via currentColor because a box-shadow cannot take an alpha off
   currentColor without color-mix, and the two themes want different greens.

   1.6s must stay in step with Builder_Portfolios.PF_PULSE_MS: the chip is
   rebuilt on every poll and carries a negative animation-delay taken from the
   wall clock so the pulse survives the rebuild — a phase computed against a
   different period would make it jump instead. */
.pf_chip.is-running .pf_chip_live { animation: pf_live_pulse 1.6s ease-in-out infinite; }
/* `background`, not `color`: the dot IS its background now, and animating the
   property that paints it beats animating `color` and relying on currentColor
   to follow. */
@keyframes pf_live_pulse {
	0%, 100% { transform:scale(0.86); background:#157a45; box-shadow:0 0 0 0   rgba(42,168,98,0);    }
	50%      { transform:scale(1.2);  background:#2aa862; box-shadow:0 0 0 3px rgba(42,168,98,0.20); }
}
body.appbuilder-dark .pf_chip.is-running .pf_chip_live { animation-name: pf_live_pulse_dk; }
@keyframes pf_live_pulse_dk {
	0%, 100% { transform:scale(0.86); background:#5aab7a; box-shadow:0 0 0 0   rgba(150,245,190,0);    }
	50%      { transform:scale(1.2);  background:#9fe8ba; box-shadow:0 0 0 3px rgba(150,245,190,0.22); }
}
/* Someone who has asked the OS for less motion gets a plain steady dot — the
   status is still legible, it just stops moving. */
@media (prefers-reduced-motion: reduce) {
	.pf_chip.is-running .pf_chip_live { animation:none; }
}
/* The news-mode chip rides in the flow under the title — which is now simply
   what a .pf_chip does, so this only carries its colours. */
.pf_chip.is-news { background:#eef2f7; color:#5a6472; font-size:9.5px; }
/* The fa-newspaper-o glyph sits high in its em box, so flex-centring still
   leaves it above the label. Nudge just the icon down 2px (no layout shift). */
.pf_chip.is-news i { position:relative; top:1px; }

/* A holding's own currency (FX4), shown only when it is NOT the portfolio's.
   Deliberately QUIETER than .pf_chip: this is a label on a row, not a status,
   and a book of thirty foreign names would otherwise be thirty coloured pills
   competing with the "To exit" chip beside them — which IS a status and has to
   stay the loudest thing in the cell. Monospaced digits are irrelevant here;
   what matters is that three letters read as an annotation. */
.pf_ccy {
	display:inline-block; vertical-align:middle;
	font-family:'Open Sans', sans-serif;
	font-size:9.5px; line-height:1.4; font-weight:600; letter-spacing:0.4px;
	padding:1px 5px; border-radius:4px;
	background:#eef2f7; color:#5a6472;
	border:1px solid #dde3ea;
}

/* Summary strip above the grid. */
.pf_summary {
	display:flex; flex-wrap:wrap; gap:10px; margin:0 0 12px;
	font-family:'Open Sans', sans-serif;
}
.pf_sum_cell {
	flex:1 1 150px; min-width:0;
	border:1px solid #e6e8ec; border-radius:8px; padding:10px 14px; background:#fafbfc;
}
.pf_sum_k {
	font-size:10px; font-weight:600; letter-spacing:0.4px; text-transform:uppercase; color:#9aa0a8;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.pf_sum_v { margin-top:4px; font-size:19px; font-weight:600; color:#27251E; }

/* ---- Blotter ------------------------------------------------------------
   Proposal on the left, execution on the right, reason last. The dashes in the
   execution columns are meaningful — a decision that never became an order —
   so they are styled as content rather than faded out like missing data. */
/* A card heading that carries a count and/or a Refresh button is a flex
   line: the count sits a gap after the title, the button at the far right.
   (The portfolio card heading is otherwise a block, where margin-left:auto
   had no effect and the count was glued to the title.) */
.pf_card_h:has(.pf_bl_n, .pf_bl_rf) { display:flex; align-items:center; gap:10px; }
.pf_bl_n    { font-size:11px; font-weight:400; color:#9aa0a8; letter-spacing:0; text-transform:none; }
.pf_bl_rf   { margin-left:auto; font-size:11px; padding:3px 9px; letter-spacing:0; text-transform:none; }
.pf_bl_note { font-size:11.5px; color:#6b7280; line-height:1.5; margin:-2px 0 12px; }
.pf_bl_wrap { overflow:auto; }
.pf_bl      { width:100%; font-family:'Open Sans', sans-serif; font-size:12px; }
/* Sticky/background/nowrap all come from .builder-dashboard-table now, so the only
   thing left here is the stacking order against the sticky column-header row. */
.pf_bl th   { z-index:1; }
/* A sticky <th> in a border-collapse table does not carry its own border: the
   border belongs to the collapsed grid and scrolls away under the header, so the
   heading row appears to shift by a pixel as the first data row slides beneath it.
   An inset shadow is painted by the cell itself, so it sticks with it. */
.pf_bl_wrap .builder-dashboard-table th { border-bottom:0; box-shadow:inset 0 -1px 0 #e6e2da; }
body.appbuilder-dark .pf_bl_wrap .builder-dashboard-table th { box-shadow:inset 0 -1px 0 #3a3a44; }
.pf_bl td   { white-space:nowrap; }
/* Footer lines (the account's Positions at broker: positions / cash / total).
   A subtotal is a quiet rule above the figures; the total is the closing
   line — bolder, a stronger rule, on the elevated surface the header uses. */
.pf_bl tfoot td            { white-space:nowrap; font-weight:600; border-top:1px solid #e6e2da; }
.pf_bl tr.pf_bl_sub td     { color:#4b5563; background:#fafaf8; }
.pf_bl tr.pf_bl_total td   { font-weight:700; border-top:2px solid #c9c4ba; background:#f4f3ef; }
/* The line that opens the second group (Cash after the positions subtotal):
   a gap above the cell plus a darker rule at the top of the gap, so the
   positions block visibly closes before cash and total begin. A gradient is
   used because a collapsed-border table cannot paint a gap between rows. */
.pf_bl tr.pf_bl_break td   {
	padding-top:12px; border-top-color:#c9c4ba;
	background:linear-gradient(#fff 0, #fff 9px, #fafaf8 9px);
}
body.appbuilder-dark .pf_bl tfoot td          { border-top-color:#3a3a44; }
body.appbuilder-dark .pf_bl tr.pf_bl_break td {
	border-top-color:#505060;
	background:linear-gradient(var(--bg, #1e1e24) 0, var(--bg, #1e1e24) 9px, var(--bg-elev, #2b2b33) 9px);
}
body.appbuilder-dark .pf_bl tr.pf_bl_sub td   { color:#aab2bb; background:var(--bg-elev, #2b2b33); }
body.appbuilder-dark .pf_bl tr.pf_bl_total td { border-top-color:#505060; background:#32323c; }
.pf_bl_dir  { font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.3px; }
.pf_bl_dir.is-buy  { color:#116b3a; }
.pf_bl_dir.is-sell { color:#b3261e; }
.pf_bl_dir.is-exit { color:#9a6a10; }
.pf_bl_st {
	font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:.3px;
	padding:2px 7px; border-radius:4px; background:#eceff4; color:#6b7280;
}
.pf_bl_st.is-ok   { background:#e6f4ec; color:#116b3a; }
.pf_bl_st.is-rej  { background:#fbeaea; color:#b3261e; }
.pf_bl_st.is-prot { background:#fdf3e3; color:#9a6a10; }
/* The reason can be long; the row must not become a paragraph. */
.pf_bl_why {
	max-width:280px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
	color:#6b7280; font-size:11.5px;
}
body.appbuilder-dark .pf_bl th        { background:var(--bg-elev, #2b2b33); }
body.appbuilder-dark .pf_bl_st        { background:#3a3a44; color:#aab2bb; }
body.appbuilder-dark .pf_bl_st.is-ok  { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_bl_st.is-rej { background:#3a2626; color:#ef9a9a; }
/* The Cancel chip on an order row: a labelled action, in the sell tint so it
   reads as "undo this" rather than a generic button. Same in both tables. */
.pf_cancel_btn {
	border:1px solid #f0b4ae; border-radius:3px; background:#fbeaea; color:#b3261e;
	font:600 10.5px 'Open Sans', sans-serif; letter-spacing:.2px; padding:2px 8px; cursor:pointer;
}
.pf_cancel_btn:hover { background:#f6d9d6; }
body.appbuilder-dark .pf_cancel_btn       { background:#3a2626; border-color:#6b3a3a; color:#ef9a9a; }
body.appbuilder-dark .pf_cancel_btn:hover { background:#4a2e2e; }
/* PENDING: confirmed by a person, not yet taken by the runner — an amber
   wash, between "nothing happened" and "working at the broker". */
.pf_bl_st.is-pend                     { background:#fdf1dc; color:#8a5a00; }
body.appbuilder-dark .pf_bl_st.is-pend { background:#3d3120; color:#f0c674; }
/* The account Orders tab: the card takes the whole tab (the tab's padding is
   its margin), the heading and the two filter picklists stay put, and the
   table scrolls INSIDE the card — its sticky column header then stays with
   the filters. */
/* The rule for every account tab: short sections keep their size and the
   tab itself never scrolls; the ONE potentially long list takes the
   remaining height and scrolls inside its section. */
.ac_panel .pf_tabbody[data-tabbody='overview'],
.ac_panel .pf_tabbody[data-tabbody='activity'],
.ac_panel .pf_tabbody[data-tabbody='positions'] { display:flex; flex-direction:column; overflow:hidden; }
.ac_panel .pf_tabbody[data-tabbody='overview'] > * { flex:0 0 auto; }
.ac_panel .pf_tabbody[data-tabbody='overview'] > .ac_orders_card { flex:1 1 auto; }
/* The resizer above the exposure panel is VISIBLE, not hover-only: a thin
   bar the reader can find and drag. Painted with an inset box-shadow — w2ui
   sets the resizer's background inline, so a background rule loses even
   with !important (the custom-panel designer learned this first). Hover
   and drag take the accent. Light and dark. */
.w2ui-layout.ex_host_layout > div .w2ui-resizer {
	/* One pixel, the house separator colour — the rest of the resizer stays
	   the invisible grab zone it is everywhere else. */
	box-shadow:inset 0 1px 0 #e6e2da !important;
}
.w2ui-layout.ex_host_layout > div .w2ui-resizer:hover,
.w2ui-layout.ex_host_layout > div .w2ui-resizer.active {
	box-shadow:inset 0 1px 0 #2F9EEE !important;
}
body.appbuilder-dark .w2ui-layout.ex_host_layout > div .w2ui-resizer {
	box-shadow:inset 0 1px 0 #3a3a44 !important;
}
body.appbuilder-dark .w2ui-layout.ex_host_layout > div .w2ui-resizer:hover,
body.appbuilder-dark .w2ui-layout.ex_host_layout > div .w2ui-resizer.active {
	box-shadow:inset 0 1px 0 #2F9EEE !important;
}
/* The exposure panel (Charts / Instrument foot): a strip with the two view
   chips, the charted symbols and Refresh, then the account painter's card
   filling the rest and scrolling inside — the account tab's own rule. */
.ex_panel { display:flex; flex-direction:column; height:100%; box-sizing:border-box; font-family:OpenSans, "Open Sans", sans-serif; }
/* The strip is the house w2ui tab bar (.pf_tabbar); the symbols and Refresh
   ride in its right slot. */
/* The strip's right slot: w2ui pads it 8px top and bottom and lets it grow,
   which pushed the symbols and the button off the tab row's centre and
   clipped the button. It is a centred flex row the height of the strip,
   and the button is sized to it. */
/* The right slot ends ON the strip's own 12px gutter, so what sits in it (Refresh)
   lines up with the right edge of the sections above and below it. */
.ex_tabbar .w2ui-scroll-wrapper .w2ui-tabs-right { display:flex; align-items:center; justify-content:flex-end; padding:0; margin-right:-2px; align-self:stretch; }  /* -2px: w2ui's wrapper pads its right by 2 */
.ex_right { display:inline-flex; align-items:center; gap:8px; }
.ex_syms  { font-size:11px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:320px; line-height:1; }
/* Small on purpose: a 36px strip wants air above and below its one button. */
.pf_btn.ex_rf, .ex_right > .pf_btn { margin-left:0; padding:3px 7px; font-size:10.5px; line-height:1; }
.ex_body  { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; overflow:hidden; padding:8px 12px 10px; box-sizing:border-box; }
.ex_body > .ac_orders_card { flex:1 1 auto; }
/* The Charts side panel wears the same strip. */
.charts_right_tabbar { padding:0 8px; }
/* "as of" beside a section title: a figure's reference time, never real-time. */
.ac_asof { font-size:11px; font-weight:400; letter-spacing:0; text-transform:none; margin-left:4px; }
/* The chips sit flush like a segmented control. Each keeps its OWN left
   border, overlapping the previous chip's by a pixel, and the active one
   rises above its neighbours — so all four of its edges take the accent.
   (The shared rule drops the left border on every chip but the first, which
   left the active chip's left edge grey.) */
/* The chip's accent variable is scoped to the screener / instrument panels;
   the account tab is neither, so without this the active chip had no
   accent to paint — which is what "three edges" was. Same value as theirs. */
.ac_orders_periods { display:inline-flex; gap:0; margin-left:6px; --scr-accent:#2F9EEE; }
.ac_orders_periods .screener_type_tab { padding:3px 8px; font-size:11px; height:auto; }
.ac_orders_periods .screener_type_tab:not(:first-child) { border-left:1px solid #d8d6d2; margin-left:-1px; }
/* The active chip's LEFT edge is set here, after the rule above and at the
   same specificity — that rule's shorthand carries a colour, and without
   this the accent never reached the left border. */
.ac_orders_periods .screener_type_tab.is-active { position:relative; z-index:1; border-left-color:var(--scr-accent); }
body.appbuilder-dark .ac_orders_periods .screener_type_tab:not(:first-child) { border-left-color:#3f4348; }
body.appbuilder-dark .ac_orders_periods .screener_type_tab.is-active { border-left-color:var(--scr-accent); }
.ac_orders_dates { display:inline-flex; align-items:center; gap:6px; margin-left:8px; }
.ac_orders_card          { flex:1 1 auto; display:flex; flex-direction:column; min-height:0; margin-bottom:0; }
.ac_orders_card .pf_card_h, .ac_orders_card .ac_orders_bar { flex:0 0 auto; }
.ac_orders_card .pf_bl_wrap { flex:1 1 auto; min-height:0; overflow:auto; }
.ac_orders_card .ac_empty { flex:1 1 auto; }
/* An empty state INSIDE a card: in the flow under the card's heading and
   note — never the panel-level .anylist_empty, which is an absolutely
   centred overlay and lands on top of the description. */
.ac_empty              { padding:22px 8px; text-align:center; color:#9aa0a8; font-size:12.5px; }
body.appbuilder-dark .ac_empty { color:#7d848c; }
.ac_orders_bar { display:flex; gap:8px; align-items:center; margin:0 0 10px; }
body.appbuilder-dark .pf_bl_st.is-prot{ background:#3a3226; color:#e0b871; }
body.appbuilder-dark .pf_bl_dir.is-buy  { color:#7ddb9a; }
body.appbuilder-dark .pf_bl_dir.is-sell { color:#ef9a9a; }
body.appbuilder-dark .pf_bl_dir.is-exit { color:#e0b871; }

/* ---- Portfolios dashboard widget ----------------------------------------
   Wraps and scrolls INSIDE the widget: a dashboard cell has whatever size the
   author gave it, so the cards flow to fit rather than pushing the canvas. */
.pf_wcards {
	display:flex; flex-wrap:wrap; gap:10px; align-content:flex-start;
	height:100%; overflow:auto; padding:2px;
	font-family:'Open Sans', sans-serif;
}
.pf_wcard {
	flex:1 1 200px; min-width:190px; max-width:280px;
	border:1px solid #e6e8ec; border-radius:8px; padding:10px 12px; background:#fff;
}
.pf_wcard_h { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:6px; }
.pf_wcard_n { font-size:12.5px; font-weight:600; color:#27251E; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf_wcard_kpis { display:flex; gap:14px; margin-top:6px; }
.pf_wcard_kpis > div { display:flex; flex-direction:column; gap:2px; min-width:0; }
.pf_wcard_kpis span { font-size:9.5px; font-weight:600; letter-spacing:.3px; text-transform:uppercase; color:#9aa0a8; }
.pf_wcard_kpis b    { font-size:12.5px; font-weight:600; color:#27251E; white-space:nowrap; }
.pf_wcard_dep  { margin-top:8px; }
.pf_wcard_depk { font-size:9.5px; font-weight:600; letter-spacing:.3px; text-transform:uppercase; color:#9aa0a8; margin-bottom:3px; }
body.appbuilder-dark .pf_wcard   { background:var(--bg-elev, #2b2b33); border-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_wcard_n { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_wcard_kpis b { color:var(--fg-strong, #e6e6ea); }

/* ---- News & Events panel ------------------------------------------------
   Cards read left-to-right as: WHEN · WHERE FROM · WHAT KIND — and then, hard
   right, WHAT THE RUNTIME DID. That last badge is the only part that is not
   description, so it is the only part that gets a strong colour. */
.pf_news_head { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:14px; }
.pf_news_t    { font-family:'Open Sans', sans-serif; font-size:19px; font-weight:600; color:#27251E; }
.pf_news_sub  { font-size:12px; color:#6b7280; margin-top:3px; max-width:640px; line-height:1.45; }
.pf_news_clear{ font-size:11px; padding:4px 10px; }
body.appbuilder-dark .pf_news_t { color:var(--fg-strong, #e6e6ea); }

/* One line, not a stack. Row-gap stays tight for the wrap that happens on a narrow
   panel; the wide COLUMN-gap is what separates Catalyst from Sentiment from Impact,
   so the groups read as groups without rules or extra markup between them.
   Each .pf_nrow keeps its own small gap, so a group never breaks up internally
   before the bar as a whole wraps. */
.pf_nfilters { display:flex; flex-direction:row; flex-wrap:wrap;
               align-items:center; gap:8px 28px; }
/* A real rule between groups: whitespace alone did not read as a break once the
   chips were all on one line - eight catalyst chips beside three sentiment ones
   look like one long run. Drawn as a pseudo-element centred in the column gap
   (half of 28px = 14px to the left) rather than as a border, so it can be short:
   a full-height divider between 22px chips reads as a table, this reads as a
   breath. It follows the group, so a wrap simply carries it to the next line. */
.pf_nfilters > .pf_nrow + .pf_nrow { position:relative; }
.pf_nfilters > .pf_nrow + .pf_nrow::before {
	content:""; position:absolute; left:-14px; top:50%; transform:translateY(-50%);
	width:2px; height:72%; border-radius:1px; background:#a2abb8; }
body.appbuilder-dark .pf_nfilters > .pf_nrow + .pf_nrow::before { background:#79828f; }
/* Locked into the tab header, so it needs the gap the list below it would
   otherwise butt straight up against - .pf_card has no margin of its own. */
.pf_nfilters_card { margin-bottom:12px; }
.pf_nrow     { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.pf_nkey     { font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:.3px; color:#9aa0a8; margin-right:2px; }
.pf_ncount   { margin-left:auto; font-size:11px; color:#9aa0a8; }
.pf_ntag {
	display:inline-flex; align-items:center; gap:5px;
	font-family:'Open Sans', sans-serif; font-size:10.5px; font-weight:600; line-height:1;
	padding:5px 9px 4px; border-radius:10px; cursor:pointer; user-select:none; white-space:nowrap;
	background:#eceff4; color:#6b7280; box-shadow:inset 0 0 0 1px transparent;
	transition:background .12s, color .12s;
}
.pf_ntag:hover { filter:brightness(.96); }
.pf_ntag.is-on          { box-shadow:inset 0 0 0 1px rgba(120,130,145,.35); background:#dfe5ee; color:#41506b; }
.pf_ntag.is-bull.is-on  { background:#e6f4ec; color:#116b3a; }
.pf_ntag.is-bear.is-on  { background:#fbeaea; color:#b3261e; }
.pf_ntag.is-high.is-on  { background:#fde7e5; color:#a01a12; }
.pf_ntag.is-med.is-on   { background:#fdf3e3; color:#9a6a10; }
body.appbuilder-dark .pf_ntag         { background:#3a3a44; color:#aab2bb; }
body.appbuilder-dark .pf_ntag.is-on         { background:#2a3140; color:#a8bdd4; }
body.appbuilder-dark .pf_ntag.is-bull.is-on { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_ntag.is-bear.is-on { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .pf_ntag.is-high.is-on { background:#3a1f1f; color:#ff9b8f; }
body.appbuilder-dark .pf_ntag.is-med.is-on  { background:#3a3226; color:#e0b871; }

.pf_ncard {
	border:1px solid #e6e8ec; border-radius:8px; padding:11px 13px; margin-bottom:10px;
	background:#fff; font-family:'Open Sans', sans-serif;
}
.pf_ncard_top { display:flex; align-items:center; gap:7px; flex-wrap:wrap; margin-bottom:6px; }
.pf_ntime { font-size:11px; color:#9aa0a8; }
.pf_nsrc  { font-size:10.5px; color:#6b7280; background:#f3f5f8; padding:2px 7px; border-radius:4px; }
.pf_nchip {
	font-size:9.5px; font-weight:700; letter-spacing:.3px; text-transform:uppercase;
	padding:2px 7px; border-radius:4px; background:#eef2f7; color:#5a6472;
}
.pf_nchip.is-bullish { background:#e6f4ec; color:#116b3a; }
.pf_nchip.is-bearish { background:#fbeaea; color:#b3261e; }
.pf_nchip.imp-high   { background:#fde7e5; color:#a01a12; }
.pf_nchip.imp-med    { background:#fdf3e3; color:#9a6a10; }
/* The badge: what the RUNTIME did. Pushed right, and the only strong colour. */
.pf_nact { margin-left:auto; font-size:10px; font-weight:700; padding:3px 8px; border-radius:4px; white-space:nowrap; }
.pf_nact.is-exit  { background:#fbeaea; color:#b3261e; box-shadow:inset 0 0 0 1px #eaa9a2; }
.pf_nact.is-block { background:#fdf3e3; color:#9a6a10; box-shadow:inset 0 0 0 1px #e3c98f; }
.pf_nact.is-arm   { background:#e6f4ec; color:#116b3a; box-shadow:inset 0 0 0 1px #9ed3b4; }
.pf_nact.is-none  { background:transparent; color:#9aa0a8; font-weight:600; }
.pf_ntitle { display:block; font-size:13.5px; font-weight:600; color:#27251E; line-height:1.4; }
.pf_nwhy   { font-size:11.5px; color:#6b7280; margin-top:3px; line-height:1.45; }
.pf_nfoot  { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:8px; }
.pf_npeers { font-size:10.5px; color:#9aa0a8; }
/* "held" is a quiet word beside the symbol link — it used to be a box drawn
   round the ticker, which read as a control and was the only one of its kind. */
.pf_nheld { font-size:10.5px; color:#1d6b3a; font-weight:600; margin-left:-6px; }
.pf_nheld::before { content:"· "; color:#9aa0a8; font-weight:400; }
body.appbuilder-dark .pf_nheld { color:#6cc48d; }
body.appbuilder-dark .pf_ncard  { background:var(--bg-elev, #2b2b33); border-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_ntitle { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_nsrc   { background:#33333c; color:#aab2bb; }
body.appbuilder-dark .pf_nchip  { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_nchip.is-bullish { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_nchip.is-bearish { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .pf_nchip.imp-high   { background:#3a1f1f; color:#ff9b8f; }
body.appbuilder-dark .pf_nchip.imp-med    { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .pf_nact.is-exit  { background:#3a1f1f; color:#ff9b8f; box-shadow:inset 0 0 0 1px #6b2f2f; }
body.appbuilder-dark .pf_nact.is-block { background:#3a3226; color:#e0b871; box-shadow:inset 0 0 0 1px #5c4a2a; }
body.appbuilder-dark .pf_nact.is-arm   { background:#22392c; color:#7ddb9a; box-shadow:inset 0 0 0 1px #2f5c42; }

/* The three modes, with the active one raised. */
.pf_nmode_note { font-size:11px; color:#9aa0a8; margin:-4px 0 10px; }
.pf_nmode   { border:1px solid #e6e8ec; border-radius:6px; padding:9px 11px; margin-bottom:8px; }
/* The selected one: the standard 2px. As a real border (padding gives the
   pixel back) rather than border + inset shadow — the dark rule below restated
   the border colour with a higher specificity, which left 1px in dark mode. */
.pf_nmode.is-cur,
body.appbuilder-dark .pf_nmode.is-cur { border:2px solid #269DF0; padding:8px 10px; }
.pf_nmode_h { display:flex; align-items:center; justify-content:space-between; font-size:12.5px; font-weight:600; color:#27251E; }
.pf_nmode_tag { font-size:9.5px; font-weight:700; background:#269DF0; color:#fff; padding:2px 7px; border-radius:4px; }
.pf_nmode_b { font-size:11.5px; color:#6b7280; margin-top:4px; line-height:1.45; }
.pf_nmode_foot { font-size:11px; color:#9aa0a8; line-height:1.5; margin:10px 0 12px; }
body.appbuilder-dark .pf_nmode   { border-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_nmode_h { color:var(--fg-strong, #e6e6ea); }

/* Global kill switch, in the Portfolios directory toolbar.
   SOLID RED, ALWAYS — the same fill, border and hover as `.pf_btn.is-danger`
   (the Delete button), in every state. It is a permanently available control on
   the money path, so it is findable before anybody is looking for it rather
   than only once it has already been pulled.

   No second shade for engaged and no ring around it. The three states are
   carried by the LABEL and the ICON, which change outright — "Kill switch" with
   fa-power-off, "TRADING HALTED" with fa-ban, "AUTO-HALTED" — and words beat a
   shade of red that half the people looking at it would have to compare against
   a memory of the other one. `is-auto` keeps amber because the runtime halting
   ITSELF is a different kind of event, not a different intensity of this one.

   EVERY COLOUR RULE BELOW IS SCOPED `.pf_btn.pf_killbtn`, never `.pf_killbtn`
   alone, and that is load-bearing rather than tidy. The markup is
   `class='pf_btn pf_killbtn'`, and the `.pf_btn` bases live LATER in this file —
   so at one class each they win on source order in light mode, and
   `body.appbuilder-dark .pf_btn` outranks a bare `body.appbuilder-dark
   .pf_killbtn` outright. Written the obvious way, the fill was silently replaced
   by the neutral button background and only the border survived. It is the same
   trap the lifecycle buttons hit (see the `.is-primary` note further down), and
   the same answer: out-specify the base rather than hope to out-order it. */
.pf_kill_wrap { display:flex; align-items:center; margin-right:14px; }
.pf_btn.pf_killbtn {
	font-family:'Open Sans', sans-serif; font-size:11px; font-weight:600;
	display:inline-flex; align-items:center; gap:6px; padding:5px 11px 4px;
	border-radius:4px; cursor:pointer; white-space:nowrap;
	background:#b3261e; border:1px solid #b3261e; color:#fff;
}
.pf_btn.pf_killbtn:hover { background:#8f1e18; border-color:#8f1e18; color:#fff; }
/* ENGAGED inherits the fill outright and only gains weight, so "TRADING HALTED"
   reads heavier without becoming a different colour to decode. */
.pf_btn.pf_killbtn.is-on { font-weight:700; }
/* The runtime halted itself: a different KIND of state, so a different hue. */
.pf_btn.pf_killbtn.is-auto { background:#fdf3e3; border-color:#e8d3a8; color:#9a6a10; }
.pf_btn.pf_killbtn.is-auto:hover { background:#f7e8cf; border-color:#dcc493; color:#7d5608; }
body.appbuilder-dark .pf_btn.pf_killbtn       { background:#d1352c; border-color:#d1352c; color:#fff; }
body.appbuilder-dark .pf_btn.pf_killbtn:hover { background:#e0463c; border-color:#e0463c; color:#fff; }
body.appbuilder-dark .pf_btn.pf_killbtn.is-auto { background:#3a3226; border-color:#5a4a2e; color:#e0b871; }
body.appbuilder-dark .pf_btn.pf_killbtn.is-auto:hover { background:#463c2d; border-color:#6b5836; color:#f0cb8a; }

/* Directory filter tag chips (Type / Status / Mode) — live in the toolbar next to
   the search box. Small pill tags: dark-gray when off, blue when on. */
/* w2ui only flex-centers NON-html toolbar items (see the :not(.w2ui-tb-html)
   rule above), so our html item is left top-aligned. Center it explicitly. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:has(.pf_ftags),
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.w2ui-tb-html:has(.pf_ftags) > * {
	display:flex; align-items:center; height:100%;
}
.pf_ftags    { display:flex; align-items:center; gap:12px; flex-wrap:wrap; font-family:'Open Sans', sans-serif; position:relative; top:2px; }
.pf_ftag_grp { display:inline-flex; align-items:center; gap:5px; }
.pf_ftag_k   { font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:0.3px; color:#9aa0a8; }
.pf_ftag {
	display:inline-flex; align-items:center; justify-content:center;
	font-family:'Open Sans', sans-serif; font-size:10.5px; line-height:1; font-weight:600;
	padding:5px 9px 3px; border-radius:10px; cursor:pointer; user-select:none; white-space:nowrap;
	background:#eceff4; color:#6b7280; transition:background .12s, color .12s;
	/* Transparent ring on every tag so selecting one (which adds a visible ring)
	   never changes the box size. */
	box-shadow:inset 0 0 0 1px transparent;
}
.pf_ftag:hover { filter:brightness(0.96); }
/* Selected: same pale-fill / coloured-text look as the portfolio-widget chips,
   for every group (Status = status palette, Type/Mode = their widget chips).
   The subtle inset ring keeps selection legible even for the grey Draft/Real
   tags. Weight is constant (set above) so width never shifts. */
.pf_ftag.is-on { box-shadow:inset 0 0 0 1px rgba(120,130,145,0.35); }
.pf_ftag.is-on.pf_ft-draft     { background:#eceff4; color:#6b7280; }
.pf_ftag.is-on.pf_ft-armed     { background:#fdf3e3; color:#9a6a10; }
.pf_ftag.is-on.pf_ft-running   { background:#e6f4ec; color:#116b3a; }
.pf_ftag.is-on.pf_ft-error     { background:#fde7e5; color:#a01a12; }
/* Type carries the SAME two hues as the chips it filters — teal and orange. It
   was one shared neutral for both, so selecting "Long" in the toolbar told you
   nothing about which colour you had just asked to see. A filter that does not
   look like the thing it filters is a second vocabulary to learn. */
.pf_ftag.is-on.pf_ft-intraday   { background:#dff3f0; color:#0b6b62; }
.pf_ftag.is-on.pf_ft-long       { background:#fbe9d9; color:#a24a06; }
.pf_ftag.is-on.pf_ft-simulated { background:#eaf1fd; color:#1c53b8; }
.pf_ftag.is-on.pf_ft-real      { background:#eceff4; color:#6b7280; }
body.appbuilder-dark .pf_ftag_k { color:#7a808c; }
body.appbuilder-dark .pf_ftag   { background:#3a3a44; color:#aab2bb; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-draft     { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-armed     { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-running   { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-error     { background:#3a1f1f; color:#ff9b8f; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-intraday   { background:#14332f; color:#6fd3c7; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-long       { background:#38271a; color:#e8a765; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-simulated { background:#22304a; color:#8fb6f0; }
body.appbuilder-dark .pf_ftag.is-on.pf_ft-real      { background:#2c2f33; color:#aab2bb; }

body.appbuilder-dark .pf_card_cap  { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_sum_cell  { background:var(--bg-elev, #2b2b33); border-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_sum_v     { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_chip.is-draft   { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_chip.is-armed   { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .pf_chip.is-running { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_chip.is-paused  { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_chip.is-stopped { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .pf_chip.is-protective { background:#22304a; color:#8fb6f0; }
body.appbuilder-dark .pf_chip.is-error   { background:#3a1f1f; color:#ff9b8f; border-color:#6b2f2f; }
body.appbuilder-dark .pf_chip.is-news    { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_ccy { background:#2c2f33; color:#aab2bb; border-color:#3a3a44; }

/* ---- Portfolio setup wizard ---------------------------------------------
   Four sections in one scrolling dialog. Section headers carry a rule so the
   groups read as groups without needing boxes. */
.pf_wiz_sec {
	/* Room ABOVE, because the thing above is the previous group's last field
	   and the rule under this text is what separates them. 16px left a
	   checkbox sitting against the next header. */
	margin:24px 0 8px; padding-bottom:4px;
	border-bottom:1px solid #e6e8ec;
	font-size:11px; font-weight:700; letter-spacing:0.5px; text-transform:uppercase;
	color:#27251E;
}
/* ONLY THE LEADING SECTION loses its top margin — and only when it really is
   the first thing in the dialog. As a DESCENDANT selector this also matched a
   header that merely opened a wrapper div, which is how "Long book" (first
   child of the container the type toggle shows and hides) ended up glued to
   the checkbox above it. */
.pf_wizard > .pf_wiz_sec:first-child { margin-top:0; }
/* Paired inputs (session start/end) share a row. */
.pf_wiz_row { display:flex; gap:10px; }
.pf_wiz_row > input { flex:1 1 0; min-width:0; margin-bottom:0 !important; }
/* The sources list is short — one column reads better than the two-column grid
   the market-sessions config uses. */
.charts_wl_dlg .pf_wiz_sources { grid-template-columns:1fr; max-height:none; }

body.appbuilder-dark .pf_wiz_sec { color:var(--fg-strong, #e6e6ea); border-bottom-color:var(--border, #3a3a44); }

/* ---- Portfolio panel (Builder_Portfolio) ---------------------------------
   Header (pinned) + tab strip (pinned) + one scrolling body. Same three-part
   split as the instrument panel: the identity band must stay put while the
   content moves, because it is what keeps you oriented. */
.portfolio-panel { display:flex; flex-direction:column; font-family:OpenSans, sans-serif; }
.pf_head {
	flex:0 0 auto; display:flex; align-items:flex-start; gap:12px; flex-wrap:wrap;
	padding:14px 18px 10px; border-bottom:1px solid #ececec;
}
/* The title bar is TINTED BY TYPE, so "what am I looking at" is answered before
   a single chip is read — the same teal/violet split the type chip uses, at a
   wash strength that classifies without competing with the name sitting on it.
   The 2px bottom rule is the load-bearing half: it survives being screenshotted,
   printed, or seen by someone who does not separate the two hues, and it is what
   makes a tab switch between two portfolios visibly a change of KIND rather than
   just a change of name. */
.pf_head.is-intraday { background:#f3fbfa; border-bottom:2px solid #86cfc7; }
.pf_head.is-long     { background:#fdf6f0; border-bottom:2px solid #e8a86f; }
/* The error strip wraps to its own full-width line under the title row rather
   than squeezing in beside the buttons. */
.pf_head_err     { flex:1 1 100%; }
.pf_err_list     { margin:4px 0 0; padding-left:18px; }
.pf_err_list li  { margin:1px 0; }
.pf_head_id      { flex:1 1 auto; min-width:0; }
/* `align-items:center` centres the chips against the TALLEST item, which is the
   17px title — so the title needs to be a real box for the centring to have
   something to measure. It used to be a bare text node (an anonymous flex item),
   which is laid out on the baseline instead and left the status chip sitting a
   pixel or two proud of the name's optical centre.
   `flex-wrap` so a long name plus three chips degrades to a second line rather
   than squeezing the chips to nothing. */
.pf_head_name    { display:flex; align-items:center; flex-wrap:wrap; gap:8px; font-size:17px; font-weight:600; color:#27251E; }
/* An explicit line box for the title, which is what the chips beside it are
   centred against. */
.pf_head_title   { line-height:22px; }
/* Chips are pinned to a card corner in the directory; in this header they are
   part of the flow. */
.pf_head_sub     { margin-top:3px; font-size:11.5px; color:#737485; }
.pf_head_actions { flex:0 0 auto; display:flex; gap:6px; }
.pf_btn {
	border:1px solid #d8d6d2; border-radius:4px; background:#fff; color:#4b5563;
	font:12px OpenSans, sans-serif; padding:5px 11px; cursor:pointer; white-space:nowrap;
}
.pf_btn:hover           { background:#f2f0ec; color:#27251E; }
/* A SPINNING ICON NEEDS A SQUARE BOX.
   `.fa` is inline-block with no dimensions, so its box is the glyph's advance
   width by a line-height of 1 — not square for most glyphs, fa-refresh
   included. `transform-origin:50% 50%` then centres on that oblong box rather
   than on the glyph, and the icon wobbles around a point beside itself instead
   of turning on the spot. A square box with the glyph centred in it puts the
   axis where the eye expects it.

   AND THE IDLE ICON RESERVES THE SAME BOX. Applying this to `.fa-spin` alone
   made the busy state wider than the resting one, so pressing Refresh widened
   its own button and shoved every button beside it along. A control that
   changes size when you use it is worse than one that spins off-centre: the
   box is reserved in both states, and only the animation differs. */
.pf_btn .fa-spin,
.pf_btn .fa-refresh {
	display:inline-block; width:1.28571429em; height:1.28571429em;
	line-height:1.28571429em; text-align:center; vertical-align:middle;
	transform-origin:50% 50%;
}
/* A clicked button keeps DOM focus, and the browser's default ring made it look
   permanently outlined afterwards. :focus-visible draws only for keyboard
   navigation, so the ring survives where it is actually needed. */
.pf_btn:focus           { outline:none; }
.pf_btn:focus-visible   { outline:2px solid var(--accent, #269DF0); outline-offset:1px; }
.pf_btn.is-primary      { background:#269DF0; border-color:#269DF0; color:#fff; }
.pf_btn.is-primary:hover{ background:#1b86d1; border-color:#1b86d1; color:#fff; }
.pf_chip.is-stale       { background:#fdf3e3; color:#9a6a10; }
/* A position queued to exit at the next open (Flatten while the market was closed). */
.pf_chip.is-exiting     { background:#fdf3e3; color:#9a6a10; }
body.appbuilder-dark .pf_chip.is-exiting { background:#3a3226; color:#e0b871; }
/* The broker chips (P7). Real money is a solid red chip — the one chip in the
   product with a filled background, because it is the one state that must be
   impossible to miss. The eToro demo reads as information, not alarm. */
.pf_chip.is-live-real   { background:#c62828; color:#fff; font-weight:700; letter-spacing:0.3px; }
.pf_chip.is-live-demo   { background:#eaf1fd; color:#1c53b8; }
body.appbuilder-dark .pf_chip.is-live-real { background:#b03030; color:#ffe3e0; }
body.appbuilder-dark .pf_chip.is-live-demo { background:#22304a; color:#8fb6f0; }

/* The typed real-trading confirmation in the setup wizard (P7): a red-framed
   block, because the field above it is the one decision in the dialog that
   moves actual money. */
.pf_arm_real            { border:1px solid #e5b5b1; border-radius:6px; padding:8px 10px; background:#fdf4f3; }
.pf_arm_real > label    { color:#a01a12; font-weight:600; }
body.appbuilder-dark .pf_arm_real         { border-color:#5a2c28; background:#31201e; }
body.appbuilder-dark .pf_arm_real > label { color:#ff9b8f; }

/* portfolio.explain (P5-3) — the reading dialog. The digest sits behind a
   disclosure: the reading is the product, the record is the receipt. */
.pf_explain { padding:16px 18px; font-family:OpenSans; height:100%; overflow-y:auto; box-sizing:border-box; }
.pf_explain_wait { color:#8a929b; font-size:12.5px; }
.pf_explain_read p { margin:0 0 10px; font-size:13px; line-height:1.55; color:#3c434a; }
.pf_explain_d { margin-top:12px; }
.pf_explain_d summary { cursor:pointer; font-size:11.5px; color:#8a929b; }
.pf_explain_pre {
	margin:8px 0 0; padding:10px 12px; border-radius:6px;
	background:#f6f7f8; border:1px solid #e3e6e9;
	font:11px/1.5 Consolas, monospace; white-space:pre-wrap; color:#5a626b;
}
/* pf_card_h is a plain block, not flex — float the button to its right
   edge instead; the uppercase title text flows beside it. */
.pf_explain_btn { float:right; margin-top:-4px; text-transform:none; letter-spacing:0; }
body.appbuilder-dark .pf_explain_read p { color:#c8cfd6; }
body.appbuilder-dark .pf_explain_pre {
	background:#1c2025; border-color:#2a2e34; color:#a8b0b9;
}

/* Per-position exit (P5-1) — a quiet icon that colours up on hover; the
   confirm dialog carries the weight, the button must not shout from every
   row of a healthy book. */
.pf_pos_exit {
	border:1px solid transparent; border-radius:3px; background:none;
	color:#9aa0a8; font-size:11px; padding:2px 6px; cursor:pointer;
}
.pf_pos_exit:hover { color:#b3261e; border-color:#e5c9c7; background:#fdf0ef; }
body.appbuilder-dark .pf_pos_exit { color:#8a929b; }
body.appbuilder-dark .pf_pos_exit:hover { color:#e08a84; border-color:#5a3835; background:#332426; }

/* ---- ACCOUNTS (OMS Ship 1-2) ----
   The directory card wears the portfolio card's recipe (.pf_dcard: full-width
   text column, pinned meta row) at its own height — no sparkline, no deployed
   bar, a 2×2 KPI grid instead. */
.applications_element.pf_dcard.ac_card { height:200px; }
.ac_kpis               { display:grid; grid-template-columns:1fr 1fr; gap:6px 16px; margin:4px 0 8px; }
.ac_kpis .pf_dcard_kpi { min-width:0; }
.ac_meta_warn          { color:#9a6a10; font-weight:600; }
body.appbuilder-dark .ac_meta_warn { color:#e0b871; }

/* ---- THE ACCOUNT TAB (Builder_Account) ----
   An account opens as a complete object in its own tab, the way a portfolio
   does, and wears the portfolio panel's chrome (.pf_head / .pf_tabbar /
   .pf_bodies / .pf_tabbody / .pf_card) so the two read as one family. Its
   own root declares the font and the column layout the header + strip +
   bodies split relies on. It replaced the .ac_detail popup. */
.ac_panel              { display:flex; flex-direction:column; font-family:OpenSans, "Open Sans", sans-serif;
                         font-size:12.5px; color:#27251E; background:#f7f8fa; }
.ac_panel button, .ac_panel input { font-family:inherit; }
/* The title bar is tinted by ENVIRONMENT the way a portfolio's is by type —
   a red rule under a real account, blue under the demo, neutral for paper —
   so a switch between two account tabs is visibly a change of KIND. */
.pf_head.is-acct-real  { background:#fdf1f0; border-bottom:2px solid #e5a29c; }
.pf_head.is-acct-demo  { background:#f2f6fd; border-bottom:2px solid #9fbdf0; }
.pf_head.is-acct-paper { background:#f7f8fa; border-bottom:2px solid #d9dce2; }
.ac_panel .pf_head_actions { flex-wrap:wrap; }
.ac_panel .pf_card_h   { display:flex; align-items:center; gap:8px; }
.ac_card_block         { margin-bottom:12px; }
.ac_panel .pf_summary  { margin-bottom:12px; }
.ac_panel .pf_note     { margin-bottom:12px; }
.ac_panel .pf_note a   { color:inherit; font-weight:600; }
/* The stamp is a date, not a figure — the KPI value size would shout it. */
.ac_sum_stamp          { font-size:13px; font-weight:600; line-height:26px; }
.ac_other              { font-size:12px; font-weight:400; }
/* A book row is a link to the portfolio's own tab. */
.ac_book_row           { cursor:pointer; }
.ac_book_row:hover td  { background:#f2f4f8; }
.ac_book_name          { font-weight:600; }
.ac_adopt              { display:inline-block; vertical-align:middle; margin-right:4px; }
.ac_adopt .wf-pickbtn  { padding:2px 8px; font-size:11px; }
.ac_instr_form         { margin:10px 0 0; }
.ac_instr_form > input { flex:1 1 160px; min-width:0; margin-bottom:0 !important; }
.ac_instr_form > input[type=number] { flex:0 1 160px; }
/* The Activity tab's reason column: a sentence, muted, clipped with an
   ellipsis so a long refusal cannot widen the table. */
.ac_reason { max-width:360px; overflow:hidden; text-overflow:ellipsis; color:#6b7280; font-size:11.5px; }
body.appbuilder-dark .ac_reason { color:#aab2bb; }
body.appbuilder-dark .ac_panel { color:var(--fg, #cfd2da); background:var(--bg, #1e1e24); }
/* Barely-there washes on a dark surface, for the same reason the portfolio
   header's are: the 2px rule carries the classification. */
body.appbuilder-dark .pf_head.is-acct-real  { background:#2b1e1e; border-bottom-color:#7a3a35; }
body.appbuilder-dark .pf_head.is-acct-demo  { background:#1c2331; border-bottom-color:#3c5a8c; }
body.appbuilder-dark .pf_head.is-acct-paper { background:var(--bg-elev, #2b2b33); border-bottom-color:var(--border-strong, #505050); }
body.appbuilder-dark .ac_book_row:hover td  { background:var(--bg-hover, #34343d); }

/* ---- THE ORDER TICKET (OMS Ship 4) ----
   The dialog is a charts_wl_dlg / tradingcfg form like the portfolio wizard;
   what is the ticket's own is the side toggle, the preview line and the
   open-orders strip. */
.ot_dlg                { font-family:OpenSans, "Open Sans", sans-serif; }
.ot_dlg .pf_wiz_row    { display:flex; gap:10px; }
.ot_dlg .pf_wiz_row > input { flex:1 1 0; min-width:0; }
/* The submit button when the preview refused the ticket: visibly inert, the
   reason on its tooltip and in red in the preview box. Same in both themes. */
.ot_submit:disabled, .ot_submit.is-refused { opacity:.55; cursor:not-allowed; }
.ot_side               { display:inline-flex; gap:0; }
.ot_side .pf_btn       { border-radius:0; min-width:84px; }
.ot_side .pf_btn:first-child { border-radius:4px 0 0 4px; }
.ot_side .pf_btn:last-child  { border-radius:0 4px 4px 0; margin-left:-1px; }
.ot_side .pf_btn.is-on[data-side=buy]  { background:#e6f4ec; border-color:#a5d5bb; color:#116b3a; font-weight:700; }
.ot_side .pf_btn.is-on[data-side=sell] { background:#fbeaea; border-color:#f0b4ae; color:#b3261e; font-weight:700; }
body.appbuilder-dark .ot_side .pf_btn.is-on[data-side=buy]  { background:#22392c; border-color:#2c5a3c; color:#7ddb9a; }
body.appbuilder-dark .ot_side .pf_btn.is-on[data-side=sell] { background:#3a2626; border-color:#6b3a3a; color:#ef9a9a; }

/* The preview: the server's answer, in a quiet box that colours up when it
   carries a warning (amber) or a refusal (red). */
.ot_preview            { border:1px solid #e3e6e9; border-radius:6px; background:#f6f7f8; padding:8px 10px;
                         font-size:11.5px; line-height:1.5; color:#3c434a; margin-bottom:14px; }
.ot_preview.is-warn    { border-color:#e6cb96; background:#fdf8ec; }
.ot_preview.is-err     { border-color:#e5b5b1; background:#fdf4f3; }
.ot_prev_row           { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ot_prev_row + .ot_prev_row { margin-top:4px; }
.ot_prev_id            { color:#6b7280; }
.ot_prev_warn          { margin:6px 0 0; padding-left:18px; color:#9a6a10; }
.ot_prev_warn li       { margin:2px 0; }
.ot_prev_err           { margin-top:6px; color:#a01a12; font-weight:600; }
body.appbuilder-dark .ot_preview        { border-color:#2a2e34; background:#1c2025; color:#c8cfd6; }
body.appbuilder-dark .ot_preview.is-warn { border-color:#5a4a2e; background:#2b2619; }
body.appbuilder-dark .ot_preview.is-err  { border-color:#5a2c28; background:#31201e; }
body.appbuilder-dark .ot_prev_id        { color:#9aa0ac; }
body.appbuilder-dark .ot_prev_warn      { color:#e0b871; }
body.appbuilder-dark .ot_prev_err       { color:#ff9b8f; }
/* The submit button turns red on a REAL ticket — the one filled red in the
   product, the same red as the LIVE — REAL MONEY chip. */
.w2ui-btn.ot_submit.is-danger       { background:#c62828; border-color:#c62828; color:#fff; }
.w2ui-btn.ot_submit.is-danger:hover { background:#a01a12; border-color:#a01a12; color:#fff; }
body.appbuilder-dark .w2ui-btn.ot_submit.is-danger       { background:#b03030; border-color:#b03030; color:#ffe3e0; }
body.appbuilder-dark .w2ui-btn.ot_submit.is-danger:hover { background:#d1352c; border-color:#d1352c; color:#fff; }

/* The open-orders strip under an instrument header: one chip per resting
   order, a quiet cancel on the working ones. Nothing rendered when empty. */
.ot_openorders         { display:flex; flex-wrap:wrap; gap:6px; padding:6px 16px 0; font-family:OpenSans, "Open Sans", sans-serif; }
.ot_oo_chip            { display:inline-flex; align-items:center; gap:6px; font-size:11px; padding:3px 9px;
                         border-radius:10px; background:#fdf3e3; color:#9a6a10; border:1px solid #e6cb96; white-space:nowrap; }
.ot_oo_chip .cv_close_x { font-size:10px; }
body.appbuilder-dark .ot_oo_chip { background:#3a3226; color:#e0b871; border-color:#5a4a2e; }

.pf_tabbar { flex:0 0 auto; border-bottom:1px solid #ececec; padding:0 12px; }
/* A setup dialog as tabs (Builder_DialogTabs): the strip stays put, the
   active page scrolls under it, and an inactive page is hidden by CLASS so
   the dialog's own inline show / hide of a conditional block is untouched. */
/* Until the tabs are built (the popup's open animation ends first) the body
   stays hidden, or it shows as one long form and blinks into pages. The
   delayed animation is only a net: it reveals the form if the helper never ran. */
.pf_wizard.pf_wiz_pending { visibility:hidden; animation:pf_wiz_reveal 0s linear 1.2s forwards; }
@keyframes pf_wiz_reveal  { to { visibility:visible; } }
.pf_wizard.has-tabs      { display:flex; flex-direction:column; height:100%; box-sizing:border-box; }
.pf_wiz_tabbar           { flex:0 0 auto; padding:0 2px; margin-bottom:10px; }
.pf_wiz_pages            { flex:1 1 auto; min-height:0; overflow:auto; padding-right:4px; }
.pf_wiz_page.is-off      { display:none !important; }
/* A count on a tab label (Builder_TabCountChip): a small muted pill after
   the caption; amber for the pending / working orders that matter at a
   glance. Same pill on the account, portfolio and exposure strips. */
.pf_tabcount {
	display:inline-block; min-width:16px; padding:0 5px; margin-left:4px; border-radius:9px;
	font:600 10px 'Open Sans', sans-serif; line-height:16px; text-align:center; vertical-align:1px;
	background:#e8e6e1; color:#5b6472;
}
.pf_tabcount + .pf_tabcount { margin-left:2px; }
.pf_tabcount.is-open { background:#fdf1dc; color:#8a5a00; }
.w2ui-tab.active .pf_tabcount { background:#dbe8f7; color:#1a5c9c; }
.w2ui-tab.active .pf_tabcount.is-open { background:#fdf1dc; color:#8a5a00; }
body.appbuilder-dark .pf_tabcount { background:#3a3a44; color:#c3c8d0; }
body.appbuilder-dark .pf_tabcount.is-open { background:#3d3120; color:#f0c674; }
body.appbuilder-dark .w2ui-tab.active .pf_tabcount { background:#1c2f45; color:#8ec2ee; }
body.appbuilder-dark .w2ui-tab.active .pf_tabcount.is-open { background:#3d3120; color:#f0c674; }
.pf_bodies { flex:1 1 auto; min-height:0; position:relative; }
.pf_tabbody { position:absolute; inset:0; overflow:auto; padding:16px 18px; box-sizing:border-box; }

.pf_placeholder {
	max-width:520px; margin:56px auto; text-align:center; color:#9aa0a8;
}
.pf_placeholder > .fa      { font-size:30px; opacity:0.5; }
.pf_placeholder_t          { margin-top:12px; font-size:14px; font-weight:600; color:#6b7280; }
.pf_placeholder_b          { margin-top:6px; font-size:12px; line-height:1.5; }
/* Optional call to action. No colours of its own — .pf_btn already themes
   itself in both modes, so this only has to place it. */
/* One or several calls to action: spaced, centred, wrapping on a narrow panel. */
.pf_placeholder_a          { margin-top:16px; display:flex; flex-wrap:wrap; justify-content:center; gap:8px; }

body.appbuilder-dark .pf_head        { border-bottom-color:var(--border, #3a3a44); }
/* The wash is barely-there on a dark surface by design — a saturated tint behind
   17px white text costs legibility for a classification the 2px rule already
   makes. Specificity: two classes + element beats the single-class rule above,
   so the type border wins over the neutral one whatever the source order. */
body.appbuilder-dark .pf_head.is-intraday { background:#16292a; border-bottom-color:#2f635c; }
body.appbuilder-dark .pf_head.is-long     { background:#2b211a; border-bottom-color:#6e4c2b; }
body.appbuilder-dark .pf_head_name   { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_head_sub    { color:var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .pf_tabbar      { border-bottom-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_btn {
	background:var(--bg-elev, #2b2b33); border-color:var(--border-strong, #505050); color:var(--fg, #cfd2da);
}
body.appbuilder-dark .pf_btn:hover   { background:var(--bg-hover, #34343d); color:var(--fg-strong, #fff); }
/* The coloured lifecycle buttons keep their brand fill in dark mode too. The dark
   `.pf_btn` base above outweighs the `.is-*` variants on specificity (element+2
   classes vs 2 classes), so without these it flattened Start/Flatten/Stop to the
   neutral elevated background, leaving only a hover border of colour. Hovers are
   LIGHTENED here (darkening reads wrong on a dark surface). */
body.appbuilder-dark .pf_btn.is-primary       { background:#269DF0; border-color:#269DF0; color:#fff; }
body.appbuilder-dark .pf_btn.is-primary:hover { background:#3aa9f5; border-color:#3aa9f5; color:#fff; }
body.appbuilder-dark .pf_btn.is-warn          { background:#e8850c; border-color:#e8850c; color:#fff; }
body.appbuilder-dark .pf_btn.is-warn:hover    { background:#f5981f; border-color:#f5981f; color:#fff; }
body.appbuilder-dark .pf_btn.is-danger        { background:#d1352c; border-color:#d1352c; color:#fff; }
body.appbuilder-dark .pf_btn.is-danger:hover  { background:#e0463c; border-color:#e0463c; color:#fff; }
body.appbuilder-dark .pf_placeholder_t { color:var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .pf_chip.is-stale { background:#3a3226; color:#e0b871; }

/* ---- Portfolio sub-panels ------------------------------------------------ */
.pf_kpis  { display:flex; gap:10px; flex-wrap:wrap; margin-bottom:14px; }
.pf_kpi   { flex:1 1 150px; min-width:0; border:1px solid #e6e8ec; border-radius:8px; padding:10px 14px; background:#fafbfc; }
.pf_kpi_k { font-size:10px; font-weight:600; letter-spacing:0.4px; text-transform:uppercase; color:#9aa0a8;
            overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf_kpi_v { margin-top:4px; font-size:19px; font-weight:600; color:#27251E; white-space:nowrap; }
.pf_kpi_s { margin-top:2px; font-size:11px; color:#737485; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

.pf_grid2 { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-bottom:12px; }
@media (max-width: 1100px) { .pf_grid2 { grid-template-columns:1fr; } }

/* A fixed head over a section that absorbs the remaining height and scrolls
   INSIDE itself — used by the Live Monitor (KPIs + equity fixed, positions and
   feed filling) and the Allocator (notes + settings fixed, intent queue
   filling). Without it the whole tab scrolled, so a busy feed or a long intent
   queue pushed the figures you are actually watching off screen.
   `:has` rather than a list of tab names, so a panel opts in by USING the shell
   instead of by being added to a selector somewhere else. */
.pf_tabbody:has(> .pf_fillcol) { overflow:hidden; }
.pf_fillcol {
	display:flex; flex-direction:column; height:100%; min-height:0;
	/* Fallback for a genuinely short viewport: once the fixed head plus the
	   fill row's min-height no longer fit, scroll the panel rather than clip it. */
	overflow:auto;
}
.pf_fillcol > * { flex:0 0 auto; }
.pf_fillcol > .pf_grid2.is-fill,
.pf_fillcol > .pf_card.is-fill { flex:1 1 auto; min-height:220px; margin-bottom:0; }
/* min-height:0 on the card — a flex item's default `min-height:auto` refuses to
   shrink below its content, which silently defeats the inner scroll. */
.pf_grid2.is-fill > .pf_card,
.pf_card.is-fill { display:flex; flex-direction:column; min-height:0; position:relative; }
.pf_card_body { flex:1 1 auto; min-height:0; overflow:auto; }
/* The feed carries its own 280px cap and scroller for the Risk panel, where it
   sits in an ordinary document. In the fill row that would nest a scrollbar
   inside a scrollbar AND hold the feed to 280px however much room it was given,
   which is exactly what this layout exists to stop. The body owns scrolling here. */
.pf_grid2.is-fill .pf_feed { max-height:none; overflow-y:visible; }

/* ---- The rest of the fill shell -----------------------------------------
   Everything below generalises the three hooks above so ANY tab can opt in,
   because the panels that had not were each broken in the same way: the tab
   body scrolled as one document, so a long table or feed pushed the header
   off screen, and every list carried a hand-picked max-height (280px feed,
   340px log, 60vh blotter) that ignored how much room it actually had.

   Three hooks, and a panel needs only these:
     .pf_fillcol            on the panel root   - fixed head, filling body
     .pf_fillbox            on a child          - takes the slack, scrolls
     .pf_grid2.is-fill      on a two-column row - both columns scroll

   position:relative on every scroller is LOAD-BEARING: .anylist_empty is
   absolutely positioned and centres on its nearest positioned ancestor, so
   without it an empty list centres itself over the whole tab - which is how
   the Log's "No runtime activity recorded yet" ended up floating across the
   decision feed below it. */
.pf_fillcol > .pf_fillbox { flex:1 1 auto; min-height:0; overflow:auto; position:relative; }
/* Two or more fillboxes share the slack EVENLY (the Log's runtime log and its
   decision feed). flex-basis must be 0, not auto: with auto they are sized from
   their content first and only the leftover is shared, so a busy feed beside an
   empty log takes almost everything. */
.pf_fillcol > .pf_fillbox { flex-basis:0; }
/* ...and a feed nested in a fillbox must give up its own 280px cap and scroller,
   or the box grows to full height with a 280px list stranded at the top of it.
   The fillbox owns the scrolling. */
.pf_fillcol .pf_fillbox .pf_feed { max-height:none; overflow-y:visible; }
.pf_grid2.is-fill > * { min-height:0; overflow:auto; position:relative; }
/* A filling card's own scroller: whichever of these it happens to use. Their
   authored max-heights are dropped - the point of the shell is that height
   comes from the space available, not from a number typed in a stylesheet. */
.pf_card.is-fill > .pf_feed,
.pf_card.is-fill > .pf_bl_wrap,
.pf_card.is-fill > .pf_conc {
	flex:1 1 auto; min-height:0; max-height:none; overflow:auto; position:relative; }
/* basis 0, so the log and the feed split the height evenly however much content
   each happens to hold - see the note on .pf_fillbox above. */
.pf_fillcol .pf_fillbox.pf_diag_log,
.pf_fillcol .pf_fillbox.pf_diag_feed {
	flex:1 1 0; min-height:0; max-height:none; overflow:auto; position:relative; }
.pf_card.is-fill > .pf_card_h { flex:0 0 auto; }

/* ---- HOW TO BUILD A PORTFOLIO TAB ---------------------------------------
   Read this before adding a tab (Long strategies included). Every panel that
   was built without it had to be retro-fitted, and all of them failed the
   same three ways, so the rules are worth following rather than rediscovering.

   THE RULE: a tab never scrolls as a whole. Its header stays put and exactly
   the section that holds the long content scrolls, sized by what is left.

   1. Wrap the panel in `.pf_fillcol`. That is the opt-in - the tab body
      switches to overflow:hidden on its own (see the `:has` rule above), so
      there is nothing else to register.
   2. Mark the ONE section that should absorb the slack:
        a card              -> `.pf_card.is-fill`
        a two-column row    -> `.pf_grid2.is-fill`   (both columns scroll)
        anything else       -> `.pf_fillbox`         (e.g. a log pane)
      Two `.pf_fillbox` siblings split the height evenly - the Log does this
      with its runtime log and decision feed.
   3. Everything else is fixed by default; do not give it a height.
   4. NEVER put a max-height on the content. `max-height:280px` on a feed,
      `340px` on a log and `60vh` on a table were each written for one screen
      and were wrong on every other; the shell exists to make height a
      consequence of the space, not a constant.
   5. Any scroller that can be EMPTY needs position:relative. `.anylist_empty`
      is absolutely positioned and centres on the nearest positioned ancestor,
      so without it an empty list floats over the whole tab. The rules above
      set it for you; a bespoke scroller must set it itself.

   Reference implementations: Live Monitor (KPI head + filling positions/feed
   row), Allocator (settings head + filling intent queue), Risk (fixed limits,
   filling actions feed), Log (two even fill panes), Blotter (filling table),
   News & Events (locked header, two scrolling columns). */
/* position:relative is load-bearing, not decoration: .anylist_empty centres
   itself with position:absolute + top/left 50%, so without a positioned ancestor
   every empty card resolved against the page instead. Two empty cards then
   stacked their messages on top of each other in the middle of the screen. */
.pf_card  { position:relative; border:1px solid #e6e8ec; border-radius:8px; padding:12px 14px; background:#fff; min-width:0; overflow:hidden; }
.pf_card_h{ font-size:11px; font-weight:700; letter-spacing:0.4px; text-transform:uppercase; color:#6b7280; margin-bottom:8px; }
.pf_equity{ position:relative; height:220px; }
/* Inside a card the message is a caption, not a hero — 24px is panel scale. */
.pf_card .anylist_empty { font-size:13px; max-width:90%; }

/* An informational strip above a panel. `is-warn` marks a limitation the user
   must not be left to infer (e.g. news not yet acting on the runtime). */
.pf_note {
	display:flex; gap:8px; align-items:flex-start;
	border:1px solid #dbe5f1; background:#f4f8fd; color:#3f5871;
	border-radius:8px; padding:9px 12px; margin-bottom:12px; font-size:11.5px; line-height:1.5;
}
.pf_note.is-warn { border-color:#f0dcb4; background:#fdf7ec; color:#7a5b1a; }
/* "You are looking at a recording, not a live book." Muted grey rather than the
   informational blue: it is a statement about the FRESHNESS of everything below
   it, and it should not compete with the panel's own notes. */
.pf_note.is-hist { border-color:#e0e2e6; background:#f5f6f8; color:#6b7280; }
/* A real fault, not a caution — the red the error chip uses, so the banner and
   the badge that summons it read as one state. */
.pf_note.is-error { border-color:#eaa9a2; background:#fdE7E5; color:#a01a12; }
.pf_note > .fa   { margin-top:2px; }

/* Warm-up strip. Deliberately the NEUTRAL note colour, not the amber warning:
   warming up is the system working as designed, not a problem — the amber note
   directly below it flags a real limitation and must stay distinguishable. */
.pf_note.is-warm { flex-wrap:wrap; }
.pf_note.is-warm > span { flex:1 1 240px; min-width:0; }
.pf_warm_row  { flex:1 1 100%; display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
/* The chip IS the progress bar: a fill behind the label rather than a separate
   track, so a dozen instruments stay readable in one strip. */
.pf_warm_chip {
	position:relative; overflow:hidden; border-radius:4px;
	border:1px solid #cddcee; background:#fff; padding:3px 8px;
	font-size:11px; line-height:1.35; white-space:nowrap;
}
.pf_warm_bar  { position:absolute; left:0; top:0; bottom:0; background:#dbe9fa; }
.pf_warm_txt  { position:relative; }
.pf_warm_chip.is-ready { border-color:#bfe3d0; }
.pf_warm_chip.is-ready .pf_warm_bar { background:#d8f0e4; }

body.appbuilder-dark .pf_note.is-warm .pf_warm_chip {
	border-color:#33465c; background:#1d232b; color:#a8bdd4;
}
body.appbuilder-dark .pf_warm_bar { background:#2b3d52; }
body.appbuilder-dark .pf_warm_chip.is-ready { border-color:#2f5c46; }
body.appbuilder-dark .pf_warm_chip.is-ready .pf_warm_bar { background:#23412f; }

.pf_alloc      { display:flex; flex-direction:column; gap:6px; }
.pf_alloc_sub  { margin:-2px 0 8px; font-size:11.5px; color:#8a8f98; }
/* Stacked bar: segments are shares of MAX CAPITAL, and idle cash is the last
   one, so a full bar always means "the whole cap is accounted for" and the
   coloured run shows how much of it is at work. */
.pf_alloc_bar  {
	display:flex; height:8px; border-radius:5px; overflow:hidden;
	background:var(--pf-track, #eceff4); margin-bottom:10px;
}
.pf_alloc_seg  { display:block; height:100%; }
.pf_alloc_list { display:flex; flex-direction:column; gap:6px; }
.pf_alloc_row  { display:flex; align-items:center; gap:8px; font-size:12px; }
.pf_alloc_dot  { width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
.pf_alloc_n    { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#27251E; }
.pf_alloc_v    { flex:0 0 auto; font-weight:600; color:#27251E; }
.pf_c0 { background:#2f6fed; } .pf_c1 { background:#0f9d76; } .pf_c2 { background:#8b5cf6; }
.pf_c3 { background:#f0a030; } .pf_c4 { background:#e0508a; } .pf_c5 { background:#4bb3d4; }
.pf_cash { background:#c2c7ce; }

/* Exposure gauge — deployed against the cap, separated from the legend above by
   a rule because it answers a different question: not "where is the money" but
   "how much room is left". Coloured by level, since a single colour would make
   20% and 95% look equally comfortable. */
/* The rule matches the CARD's own border colour rather than a fainter grey: at
   #ececf0 (light) / #33363c (dark) it was all but invisible against the card, so
   the gauge read as part of the legend above it instead of a separate answer. */
.pf_gauge      { margin-top:14px; padding-top:12px; border-top:1px solid #e6e8ec; }
.pf_gauge_h    { display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
.pf_gauge_k    { font-size:10px; font-weight:700; letter-spacing:0.4px; text-transform:uppercase; color:#6b7280; }
.pf_gauge_p    { font-size:15px; font-weight:700; color:#27251E; }
.pf_gauge_track{ height:9px; border-radius:5px; background:#c2c7ce; overflow:hidden; margin:7px 0 6px; }
.pf_gauge_fill { display:block; height:100%; border-radius:5px; transition:width .3s ease; }
.pf_gauge_fill.is-low  { background:#0f9d76; }
.pf_gauge_fill.is-mid  { background:#f0a030; }
.pf_gauge_fill.is-high { background:#b3261e; }
.pf_gauge_p.is-mid     { color:#a06a10; }
.pf_gauge_p.is-high    { color:#b3261e; }
.pf_gauge_f    { display:flex; justify-content:space-between; gap:8px; font-size:11px; color:#8a8f98; }

body.appbuilder-dark .pf_alloc_sub,
body.appbuilder-dark .pf_gauge_f    { color:#7d848c; }
/* No dark override for the tracks — they read --pf-track, which the dark token
   block redefines. Two hand-written dark values (#2c2f33 here, #3a3a44 on
   .pf_bar) are how the exposure gauge and the concentration bars ended up
   looking like different components. */
body.appbuilder-dark .pf_gauge      { border-top-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_gauge_k    { color:#9aa0ac; }
body.appbuilder-dark .pf_gauge_p    { color:#e6e6ea; }
body.appbuilder-dark .pf_gauge_p.is-mid  { color:#e0b871; }
body.appbuilder-dark .pf_gauge_p.is-high { color:#ef9a9a; }
body.appbuilder-dark .pf_gauge_track { background:#4a4f57; }
body.appbuilder-dark .pf_gauge_fill.is-low  { background:#2fa87f; }
body.appbuilder-dark .pf_gauge_fill.is-high { background:#c9433a; }
body.appbuilder-dark .pf_cash { background:#4a4f57; }

/* Journal feed, shared by the Monitor and Risk panels. */
.pf_feed       { display:flex; flex-direction:column; max-height:280px; overflow-y:auto; }
.pf_feed_row   { display:flex; gap:8px; padding:6px 0; border-bottom:1px solid #f0f1f3; font-size:11.5px; }
.pf_feed_row:last-child { border-bottom:0; }
.pf_feed_t     { flex:0 0 52px; color:#9aa0a8; font-size:10.5px; line-height:1.6; }
.pf_feed_main  { flex:1 1 auto; min-width:0; }
.pf_feed_title { color:#27251E; }
.pf_feed_d     { margin-top:2px; font-size:11px; color:#737485; }
.pf_feed_row.sev-warn  .pf_feed_title { color:#9a6a10; }
.pf_feed_row.sev-error .pf_feed_title { color:#b3261e; }
.pf_kind {
	display:inline-block; font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:0.3px;
	padding:1px 5px; border-radius:8px; margin-right:6px; background:#eceff4; color:#6b7280; vertical-align:1px;
}
.pf_kind.k-entry { background:#e6f4ec; color:#116b3a; }
.pf_kind.k-exit  { background:#eef2f7; color:#41506b; }
.pf_kind.k-veto,
.pf_kind.k-risk  { background:#fbeaea; color:#b3261e; }
.pf_kind.k-rotate{ background:#f1ebfd; color:#5b3aa6; }
.pf_kind.k-data  { background:#fdf3e3; color:#9a6a10; }

/* Log / Diagnostics panel — a live, monospace view of the background runtime. */
.pf_diag        { display:flex; flex-direction:column; gap:10px; padding:2px; }
.pf_diag_bar    { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
.pf_diag_chips  { display:flex; gap:6px; flex-wrap:wrap; }
.pf_diag_chip   { font-size:10.5px; color:#6b7280; background:#f5f6f8; border:1px solid #e7e9ee; border-radius:10px; padding:2px 8px; }
.pf_diag_chip b { font-weight:600; color:#41506b; margin-right:4px; }
.pf_diag_chip.is-warn { background:#fdf3e3; border-color:#f0dcb4; color:#9a6a10; }
.pf_diag_busy   { color:#b3261e; font-weight:700; }
.pf_diag_sec    { font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:0.4px; color:#9aa0a8; margin-top:2px; }
.pf_diag_log    { font-family:ui-monospace,SFMono-Regular,Consolas,monospace; font-size:11px; line-height:1.55;
                  max-height:340px; overflow-y:auto; background:#fafbfc; border:1px solid #eceef2; border-radius:6px; padding:6px 8px; }
.pf_diag_row    { display:flex; gap:8px; }
.pf_diag_t      { flex:0 0 56px; color:#9aa0a8; }
.pf_diag_scope  { flex:0 0 56px; font-weight:700; font-size:9px; text-transform:uppercase; letter-spacing:0.3px; color:#6b7280; align-self:center; }
.pf_diag_scope.s-runner    { color:#5b3aa6; }
.pf_diag_scope.s-portfolio { color:#116b3a; }
.pf_diag_stage  { flex:0 0 58px; color:#2f6fed; }
.pf_diag_msg    { flex:1 1 auto; min-width:0; color:#41506b; white-space:pre-wrap; word-break:break-word; }
.pf_diag_row.lv-warn  .pf_diag_msg { color:#9a6a10; }
.pf_diag_row.lv-error .pf_diag_msg { color:#b3261e; }

body.appbuilder-dark .pf_diag_chip   { background:#26282c; border-color:#3a3a44; color:#9aa0ac; }
body.appbuilder-dark .pf_diag_chip b { color:#c2cad3; }
body.appbuilder-dark .pf_diag_chip.is-warn { background:#332c1f; border-color:#5c4a26; color:#e0b871; }
body.appbuilder-dark .pf_diag_busy   { color:#ff9b8f; }
body.appbuilder-dark .pf_diag_sec    { color:#7a808c; }
body.appbuilder-dark .pf_diag_log    { background:#1f2226; border-color:#33363d; }
body.appbuilder-dark .pf_diag_t      { color:#7a808c; }
body.appbuilder-dark .pf_diag_scope.s-runner    { color:#c3a9f0; }
body.appbuilder-dark .pf_diag_scope.s-portfolio { color:#7ddb9a; }
body.appbuilder-dark .pf_diag_stage  { color:#6ea8fe; }
body.appbuilder-dark .pf_diag_msg    { color:#aab6c4; }
body.appbuilder-dark .pf_diag_row.lv-warn  .pf_diag_msg { color:#e0b871; }
body.appbuilder-dark .pf_diag_row.lv-error .pf_diag_msg { color:#ff9b8f; }

.pf_side, .pf_dir {
	font-size:9.5px; font-weight:700; padding:1px 6px; border-radius:8px; letter-spacing:0.3px;
}
.pf_side.is-long, .pf_dir.is-buy   { background:#e6f4ec; color:#116b3a; }
.pf_side.is-short, .pf_dir.is-sell { background:#fbeaea; color:#b3261e; }
.pf_dir.is-exit                    { background:#eceff4; color:#6b7280; }
.pf_reason { font-size:11px; color:#737485; max-width:280px; }
/* No colour of its own: a symbol that opens something wears `.gridurl`, the
   one hyperlink blue (light and dark) every grid and table uses. */
.pf_sym    { font-size:10.5px; font-weight:600; }

/* ---- Performance tab (L5) -----------------------------------------------
   Stacked cards, the same rhythm as the Runs tab: statistics, then the curve,
   then the holdings. Reuses .pf_card / .pf_kpis / .builder-dashboard-table so
   this tab cannot drift from the others visually.
   Layout comes from .pf_fillcol (see "HOW TO BUILD A PORTFOLIO TAB" above) —
   only the gap between cards is stated here. */
.pf_perf      { gap:12px; }
/* A definite height: ECharts measures its host at init, and a container sized
   only by its content is zero pixels tall at that moment. */
.pf_perfchart { width:100%; height:320px; }

/* Sign colours for the drift column. Green = under target (the rebalance would
   BUY), red = over (it would sell) — the sign of a CORRECTION, not of a profit,
   which is why they are stated here rather than borrowed from the PnL palette
   where green means "good". */
.pf_pos { color:#00a152; }
.pf_neg { color:#C0392B; }
body.appbuilder-dark .pf_pos { color:#00c853; }
body.appbuilder-dark .pf_neg { color:#EF6B5B; }

/* Funding: the two inputs and the two verbs on one row. Deliberately plain —
   this is the one control on the screen that moves real money, and it should
   look like a form, not like a button worth pressing to see what happens.

   No font/border/background rules here: the inputs carry .w2ui-input, so they
   already look like every other text box in the builder and follow dark mode
   without a second declaration. Only WIDTH is ours to decide. */
.pf_fund       { display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:2px 0 6px; }
.pf_fund_amt   { width:140px; }
.pf_fund_note  { flex:1 1 200px; min-width:160px; }
.pf_fund_hint  { font:11px OpenSans, sans-serif; color:#8a8a8a; padding-bottom:8px; }
body.appbuilder-dark .pf_fund_hint  { color:#9a9a9a; }

/* Runs tab: Live/Replay filter chips (in the toolbar) + the daily P&L heatmap. */
/* The Daily P&L card and the Runs card are stacked siblings — give the first a
   gap so they don't butt together. */
#id_pf_runs_heatcard { margin-bottom:14px; }
.pf_runs_chips  { display:inline-flex; align-items:center; gap:6px; }
.pf_runs_chipn  { display:inline-block; margin-left:4px; padding:0 5px; border-radius:8px; background:rgba(0,0,0,0.08); font-size:10px; }
/* The run count and the "simulated" tag as pill chips (targeted by id so the
   shared .pf_uni_count elsewhere is untouched). */
#id_pf_runs_n   { align-self:center; padding:2px 9px; border-radius:10px; font-size:11px; background:#eef2f7; color:#41506b; }
#id_pf_runs_sim { align-self:center; padding:2px 9px; border-radius:10px; font-size:10px; font-weight:600;
                  text-transform:uppercase; letter-spacing:0.4px; background:#fdf3e3; color:#9a6a10; }
body.appbuilder-dark #id_pf_runs_n   { background:#2a3140; color:#a8bdd4; }
body.appbuilder-dark #id_pf_runs_sim { background:#3a3226; color:#e0b871; }
/* Broker variants of the runs badge (P7): demo informs, real shouts. */
#id_pf_runs_sim.is-demo { background:#eaf1fd; color:#1c53b8; }
#id_pf_runs_sim.is-real { background:#c62828; color:#fff; }
body.appbuilder-dark #id_pf_runs_sim.is-demo { background:#22304a; color:#8fb6f0; }
body.appbuilder-dark #id_pf_runs_sim.is-real { background:#b03030; color:#ffe3e0; }
.pf_heat        { display:flex; flex-wrap:wrap; gap:6px; }
.pf_heat_cell   { display:flex; flex-direction:column; justify-content:center; align-items:center; width:72px; height:46px;
                  border:1px solid rgba(0,0,0,0.06); border-radius:6px; }
.pf_heat_d      { font-size:10px; color:#6b7280; }
.pf_heat_v      { font-size:11px; font-weight:600; color:#27251E; margin-top:2px; }

body.appbuilder-dark .pf_runs_chipn { background:rgba(255,255,255,0.12); }
body.appbuilder-dark .pf_runs_sim   { color:#7a808c; }
body.appbuilder-dark .pf_heat_sec   { color:#7a808c; }
body.appbuilder-dark .pf_heat_cell  { border-color:rgba(255,255,255,0.08); }
body.appbuilder-dark .pf_heat_d     { color:#9aa0ac; }
body.appbuilder-dark .pf_heat_v     { color:#e6e6ea; }

/* Directory dashboard: live portfolio cards (equity sparkline, KPIs, deployed bar,
   inline lifecycle controls). The base .applications_element is a fixed 308×166 box
   with the text absolutely positioned at left:56px to clear a logo; the dashboard
   card has no logo, so it flows the text to the full width and grows with content. */
.applications_element.pf_dcard { width:340px; height:auto; }
.pf_dcard .applications_element_text { position:static; left:auto; top:auto; width:auto; height:auto;
                                       overflow:visible; padding:2px 4px 4px; }
.pf_dcard_meta         { display:flex; flex-wrap:wrap; gap:14px; margin:8px 0 10px; font-size:11px; color:#737485; }
.pf_dcard_meta i       { margin-right:4px; opacity:0.7; }
/* TYPE, in its own hue per value — see Builder_Portfolios._TypeChip for why this
   is a hue and not a shade. TEAL for intraday (a session, a clock), ORANGE for
   long (a horizon, a calendar) — complementary, so the two are separable at a
   glance and at small size.

   ONE CAUTION, since orange is the nearest of the two to a status colour: the
   `armed` chip is amber (#fdf3e3 / #9a6a10), and it can sit directly beside
   this one. They are kept apart by saturation and by warmth — armed is a pale
   yellow-brown wash, long is redder and stronger — and, more reliably, by the
   border and the icon that only the type chip carries. If those two are ever
   confused in practice, move long's fill redder rather than lightening armed:
   the status palette is the older vocabulary and the one worth protecting. */
.pf_chip.is-type              { background:#eef2f7; color:#41506b; }
/* The border is ADDED where the base chip has none, so the padding gives the 1px
   back on all four sides (3px+0 → 2px+1, 9px+0 → 8px+1). Without that the type
   chip stands 2px taller than the status chip it sits beside — which is exactly
   the ragged chip row this change was asked to fix. */
.pf_chip.is-type.is-intraday,
.pf_chip.is-type.is-long      { padding:2px 8px; border:1px solid transparent; }
.pf_chip.is-type.is-intraday  { background:#dff3f0; color:#0b6b62; border-color:#a9ded8; }
.pf_chip.is-type.is-long      { background:#fbe9d9; color:#a24a06; border-color:#efc49b; }
/* Same high-glyph correction the news chip needs: fa sits above its em box, so
   flex-centring alone still leaves the icon riding over the label. */
.pf_chip.is-type i            { position:relative; top:1px; opacity:0.85; }
.pf_dcard_spark        { margin:8px 0 6px; height:40px; }
.pf_dcard_spark svg    { width:100%; height:40px; display:block; }
/* No curve yet: same 40px reserved, with a faint baseline so the space reads
   as "waiting for data" rather than as a rendering gap. */
.pf_dcard_spark.is-empty { border-bottom:1px dashed #d5dae1; }
body.appbuilder-dark .pf_dcard_spark.is-empty { border-bottom-color:#4a4f57; }
.pf_dcard_kpis         { display:flex; gap:16px; margin:2px 0 8px; flex-wrap:wrap; }
.pf_dcard_k            { font-size:9.5px; font-weight:600; letter-spacing:0.3px; text-transform:uppercase; color:#9aa0a8; }
.pf_dcard_v            { margin-top:2px; font-size:14px; font-weight:600; color:#27251E; white-space:nowrap; }
.pf_dcard_dep          { margin:2px 0 10px; }
.pf_dcard_deprow       { display:flex; justify-content:space-between; font-size:10.5px; color:#737485; margin-bottom:4px; }
/* Deployed bar: same gray as the Capital Allocation "Cash" segment (pf_cash) for the
   track, and the button blue (#269DF0) for the fill — one blue, not several. */
.pf_dcard_depbar       { height:5px; border-radius:3px; background:#c2c7ce; overflow:hidden; }
.pf_dcard_depbar > span{ display:block; height:100%; background:#269DF0; }
/* Lifecycle controls: compact icon buttons pinned top-right (where the status chip
   used to float — the chip now sits below the title). */
.pf_dcard_ctl          { position:absolute; top:10px; right:10px; display:flex; gap:4px; z-index:1; }
.pf_dcard_iconbtn      { padding:4px 8px; line-height:1; }
.pf_dcard .pf_card_title { padding-right:98px; }
.pf_dcard .pf_card_chips { display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin:5px 0 6px; }

body.appbuilder-dark .pf_dcard_k      { color:#9aa0ac; }
body.appbuilder-dark .pf_dcard_v      { color:#e6e6ea; }
body.appbuilder-dark .pf_dcard_deprow { color:#9aa0ac; }
body.appbuilder-dark .pf_dcard_depbar { background:#4a4f57; }
body.appbuilder-dark .pf_dcard_meta   { color:#9aa0ac; }
body.appbuilder-dark .pf_chip.is-type { background:#2a3140; color:#a8bdd4; }
body.appbuilder-dark .pf_chip.is-type.is-intraday { background:#14332f; color:#6fd3c7; border-color:#2c5a55; }
body.appbuilder-dark .pf_chip.is-type.is-long     { background:#38271a; color:#e8a765; border-color:#5e4327; }

/* Utilisation bars, used by both the limits table and the concentration list. */
.pf_bar    { position:relative; height:6px; border-radius:3px; background:var(--pf-track, #eceff4); min-width:70px; overflow:hidden; }
.pf_bar > i{ position:absolute; left:0; top:0; bottom:0; border-radius:3px; display:block; }
.pf_bar > i.is-ok     { background:#0f9d76; }
.pf_bar > i.is-warn   { background:#f0a030; }
.pf_bar > i.is-breach { background:#b3261e; }
.pf_limit  { font-size:9.5px; font-weight:700; padding:1px 6px; border-radius:8px; }
.pf_limit.is-ok     { background:#e6f4ec; color:#116b3a; }
.pf_limit.is-warn   { background:#fdf3e3; color:#9a6a10; }
.pf_limit.is-breach { background:#fbeaea; color:#b3261e; }

.pf_conc      { display:flex; flex-direction:column; gap:7px; }
.pf_conc_row  { display:flex; align-items:center; gap:9px; font-size:11.5px; }
.pf_conc_n    { flex:0 0 74px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#27251E; }
.pf_conc_row .pf_bar { flex:1 1 auto; }
.pf_conc_v    { flex:0 0 58px; text-align:right; color:#737485; }

.pf_kill      { display:flex; align-items:center; justify-content:space-between; gap:16px; margin-bottom:12px; }
.pf_kill_b    { font-size:11.5px; color:#737485; line-height:1.5; }
/* Strategy card live record (Helm B): green-ish when the realised edge is
   positive, red when negative, muted before the first closed trade. */
.pf_strat_stats { margin-left:auto; font-size:10.5px; color:#2f7d4f; white-space:nowrap; }
.pf_strat_stats.is-neg  { color:#b3261e; }
.pf_strat_stats.is-none { color:#9aa0ab; font-style:italic; }
body.appbuilder-dark .pf_strat_stats         { color:#6fbf8f; }
body.appbuilder-dark .pf_strat_stats.is-neg  { color:#e08079; }
body.appbuilder-dark .pf_strat_stats.is-none { color:#767c86; }
/* The record's start after a reset, and the reset itself — quiet, beside the stats. */
/* A BOUND strategy's card: the Lab's script card, with the binding's two actions
   in the corner (as a portfolio card carries its lifecycle) and the whole card
   opening the strategy. The title keeps clear of the corner buttons. */
.pf_scard { position:relative; cursor:pointer; }
.pf_scard .applications_element_text > span.ts_pick_name { display:block; padding:3px 64px 0 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* The name sits on the buttons' centre line; the description clears them and may
   run to three lines — a bound strategy's purpose is worth the extra one. */
.pf_scard .applications_element_desc { margin-top:10px !important; -webkit-line-clamp:3 !important; line-clamp:3 !important; }
.pf_scard .ts_chiprow { display:flex; flex-wrap:nowrap; align-items:center; gap:6px; }
.pf_scard.is-paused .applications_element_logo, .pf_scard.is-paused .applications_element_desc { opacity:.55; }
.pf_scard .pf_strat_stats { margin-left:0; }
.pf_strat_foot { display:flex; align-items:center; flex-wrap:wrap; gap:4px 8px; margin-top:2px; }
.pf_strat_foot .pf_card_toggle { margin:0; }
.pf_strat_since { font-size:10.5px; color:#9aa0ab; white-space:nowrap; }
.pf_btn.pf_btn_icon.pf_strat_ev { flex:0 0 auto; margin-left:auto; padding:1px 7px; font-size:11px; line-height:1.5; }
/* The mandate card's explainer sits at the end of the head row, before the corner
   buttons; the dialogs' action rows. */
.pf_mand_head .pf_mand_how + .pf_mand_actions { margin-left:8px; }
.pf_ev_actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:4px; }
.pf_when { white-space:nowrap; }
/* A day filter in a card header sits WITH the Refresh beside it, at the right end. */
.pf_card_h .pf_period_bar + .pf_bl_rf { margin-left:8px; }

/* Warm-up in progress: the hourglass turns over about its own centre — half a
   turn, a rest, half a turn — which reads as sand running rather than as a spinner.
   The phase comes from the clock (inline negative delay), so the strip being
   rebuilt on every poll does not restart it. Still for readers who ask for less motion. */
.pf_hourglass { display:inline-block; transform-origin:50% 50%; animation:pf_hourglass_turn 2.4s ease-in-out infinite; }
@keyframes pf_hourglass_turn {
	0%, 30%   { transform:rotate(0deg); }
	50%, 80%  { transform:rotate(180deg); }
	100%      { transform:rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) { .pf_hourglass { animation:none; } }

/* The symbol an event in a feed is about. */
.pf_feed_sym { margin-left:6px; }

/* The EV & record dialog: prose that teaches, one formula, two small tables. */
.pf_ev_dlg p { margin:0 0 9px; font-size:12.5px; line-height:1.55; color:#41506b; }
.pf_ev_dlg ul { margin:0 0 10px; padding-left:18px; font-size:12.5px; line-height:1.55; color:#41506b; }
.pf_ev_dlg li { margin-bottom:4px; }
.pf_ev_dlg b { color:#27251E; }
.pf_ev_formula { margin:2px 0 12px; padding:9px 12px; border-radius:6px; background:#f4f6f9; border:1px solid #e3e6ec;
                 font-family:OpenSans; font-size:12.5px; font-weight:600; color:#27251E; text-align:center; }
.pf_ev_h { margin:14px 0 6px !important; font-weight:600; color:#27251E !important; }
.pf_ev_tbl { margin-bottom:10px; }
.pf_ev_tbl td, .pf_ev_tbl th { font-size:12px; }
.pf_ev_tbl tr.pf_ev_now > td { background:#eef5fb; }
.pf_ev_dlg .pf_note { margin:0 0 8px; }
.pf_ev_dlg .pf_btn.is-danger { margin-top:4px; }
body.appbuilder-dark .pf_ev_dlg p, body.appbuilder-dark .pf_ev_dlg ul { color:#a8bdd4; }
body.appbuilder-dark .pf_ev_dlg b, body.appbuilder-dark .pf_ev_h { color:#e6e6ea !important; }
body.appbuilder-dark .pf_ev_formula { background:#232a33; border-color:#33465c; color:#e6e6ea; }
body.appbuilder-dark .pf_ev_tbl tr.pf_ev_now > td { background:#1c2a3a; }
body.appbuilder-dark .pf_strat_since { color:#767c86; }

/* Graded risk state (Helm A2): same layout as the kill-switch card, tinted by
   severity — amber brake, orange halt, red killed. */
.pf_riskstate { display:flex; align-items:center; justify-content:space-between; gap:16px; margin-bottom:12px; }
.pf_riskstate.is-brake  { border-color:#e8c86e; background:#fdf8ea; }
.pf_riskstate.is-halt   { border-color:#e8a04c; background:#fdf1e3; }
.pf_riskstate.is-killed { border-color:#d46a63; background:#fdecea; }
.pf_riskstate.is-killed .pf_card_h { color:#b3261e; }
body.appbuilder-dark .pf_riskstate.is-brake  { border-color:#6a5a2c; background:#332e1f; }
body.appbuilder-dark .pf_riskstate.is-halt   { border-color:#7a5528; background:#362b1d; }
body.appbuilder-dark .pf_riskstate.is-killed { border-color:#7a3630; background:#391f1d; }
body.appbuilder-dark .pf_riskstate.is-killed .pf_card_h { color:#e08079; }
.pf_btn.is-danger { background:#b3261e; border-color:#b3261e; color:#fff; }
.pf_btn.is-danger:hover { background:#8f1e18; border-color:#8f1e18; color:#fff; }
/* Flatten — amber: book-affecting but guarded by a confirm, so distinct from the
   neutral Stop and the blue primary without being as loud as danger red. */
.pf_btn.is-warn { background:#e8850c; border-color:#e8850c; color:#fff; }
.pf_btn.is-warn:hover { background:#c9720a; border-color:#c9720a; color:#fff; }

.pf_mode      { border:1px solid #cfe3f7; background:#f4f9ff; border-radius:8px; padding:10px 12px; margin-bottom:10px; }
.pf_mode_t    { font-size:12px; font-weight:700; color:#1a5c9c; }
.pf_mode_b    { margin-top:3px; font-size:11.5px; color:#41506b; line-height:1.5; }
.pf_kv        { display:flex; justify-content:space-between; gap:10px; font-size:11.5px; color:#737485; margin-bottom:10px; }
.pf_kv > b    { color:#27251E; }

.pf_toolbar   { display:flex; gap:8px; align-items:center; margin-bottom:12px; }
.pf_toolbar > input { flex:1 1 auto; min-width:0; margin-bottom:0 !important; }
.pf_x {
	border:0; background:none; color:#9aa0a8; cursor:pointer; font-size:12px; padding:2px 6px; border-radius:4px;
}
.pf_x:hover   { background:#fbeaea; color:#b3261e; }

/* Universe tab: a toolbar over a grid that takes the rest of the height. The
   grid has fixedBody, so it scrolls INTERNALLY — the wrapper must therefore be
   a definite-height flex column, or the grid collapses to nothing and the tab
   body grows its own second scrollbar next to the grid's. */
.pf_uni { display:flex; flex-direction:column; height:100%; min-height:0; }
.pf_uni > .pf_toolbar { flex:0 0 auto; }
.pf_uni_grid { flex:1 1 auto; min-height:220px; }
/* Count sits hard right, away from the two action buttons. */
.pf_uni_count { margin-left:auto; font-size:11.5px; color:#6b7280; white-space:nowrap; }
/* The open run's id, trailing the count on the same row. Monospace because it
   is a reference to read character by character — and to copy — not prose, and
   truncated rather than allowed to push the buttons around on a narrow panel. */
.pf_runid { font-family:Consolas,"Courier New",monospace; font-size:11px; color:#6b7280;
            max-width:240px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf_btn[disabled] { opacity:.45; cursor:default; }

body.appbuilder-dark .pf_uni_count,
body.appbuilder-dark .pf_runid { color:#7d848c; }

/* Strategy cards — the Lab ▸ Trade Scripts card, reused. The container keeps the
   directory's own flow so a card wraps and sizes identically in both places. */
.pf_cards { padding:0; overflow:visible; }
.pf_bind_dlg { padding:12px 14px; height:100%; overflow:auto; box-sizing:border-box; }
/* The card grid is .applications_container, which in dark mode paints the PAGE background
   (var(--bg), and with !important). Inside a popup that laid a second, different dark over
   the dialog's own body - and only where the cards are, so it read as an inset panel with
   a border of a lighter dark. In a dialog the container must carry no background of its
   own; the specificity here has to beat that themed !important rule. */
.pf_bind_dlg .applications_container,
body.appbuilder-dark .pf_bind_dlg .applications_container { background:transparent !important; }
/* A dialog is not a panel: 24px centred prose is shouting at this size, and an
   explanation needs a measure narrow enough to read. */
.pf_bind_dlg .anylist_empty { font-size:14px; max-width:400px; }

/* The selection checkbox rides in the card's top-right, clear of the published
   tag's corner and of the logo. position:absolute against .applications_element,
   which is already position:relative. */
.ts_pick_card { position:relative; }
.ts_card_check { position:absolute; top:8px; right:10px; margin:0; z-index:2; cursor:pointer; }
/* The checkbox is absolutely positioned, so it does not push the title out of its way -
   a long name simply ran underneath it. Reserve the checkbox's lane and ellipsize instead.
   Keeps the `> span` bold/line-height rule (it is still a direct child span). */
.ts_pick_card .applications_element_text > span.ts_pick_name {
	display:block; padding-right:26px;
	white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.ts_card_check input { width:auto; margin:0; cursor:pointer; accent-color:var(--accent, #269DF0); }

/* Enabled switch, under the provenance line. Muted until checked so a card reads
   as "bound and running" vs "bound and paused" at a glance. */
.pf_card_toggle {
	display:flex; align-items:center; gap:6px; margin:6px 0 0;
	font:11.5px OpenSans, sans-serif; font-weight:400; color:#6b7280; cursor:pointer;
}
.pf_card_toggle input { width:auto; margin:0; accent-color:var(--accent, #269DF0); }
.pf_card_toggle:has(input:checked) { color:#1a7f4b; }

body.appbuilder-dark .pf_card_toggle { color:#7d848c; }
body.appbuilder-dark .pf_card_toggle:has(input:checked) { color:#7ddb9a; }

body.appbuilder-dark .pf_kpi,
body.appbuilder-dark .pf_card      { background:var(--bg-elev, #2b2b33); border-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_kpi_v,
body.appbuilder-dark .pf_alloc_n,
body.appbuilder-dark .pf_alloc_v,
body.appbuilder-dark .pf_conc_n,
body.appbuilder-dark .pf_feed_title,
body.appbuilder-dark .pf_kv > b    { color:var(--fg-strong, #e6e6ea); }
body.appbuilder-dark .pf_kpi_s,
body.appbuilder-dark .pf_feed_d,
body.appbuilder-dark .pf_reason,
body.appbuilder-dark .pf_conc_v,
body.appbuilder-dark .pf_kill_b,
body.appbuilder-dark .pf_kv        { color:var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .pf_feed_row  { border-bottom-color:var(--border, #3a3a44); }
body.appbuilder-dark .pf_kind      { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .pf_note      { background:#232a33; border-color:#33465c; color:#a8bdd4; }
body.appbuilder-dark .pf_note.is-warn { background:#332c1f; border-color:#5c4a26; color:#e0b871; }
body.appbuilder-dark .pf_note.is-hist { background:#26282c; border-color:#3a3a44; color:#9aa0ac; }
body.appbuilder-dark .pf_note.is-error { background:#3a1f1f; border-color:#6b2f2f; color:#ff9b8f; }
body.appbuilder-dark .pf_mode      { background:#232a33; border-color:#33465c; }
body.appbuilder-dark .pf_mode_t    { color:#6ea8ff; }
body.appbuilder-dark .pf_mode_b    { color:#a8bdd4; }
body.appbuilder-dark .pf_x:hover   { background:#3a2626; color:#ef9a9a; }

/* The status/kind chips carry light pastel fills, which read as bright patches
   on a dark panel. Same treatment the .bt_chip family already gets: keep the
   hue, drop the luminance, lift the text. */
body.appbuilder-dark .pf_kind.k-entry  { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_kind.k-exit   { background:#2a3140; color:#a8bdd4; }
body.appbuilder-dark .pf_kind.k-veto,
body.appbuilder-dark .pf_kind.k-risk   { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .pf_kind.k-rotate { background:#2e2740; color:#c3a9f0; }
body.appbuilder-dark .pf_kind.k-data   { background:#3a3226; color:#e0b871; }

body.appbuilder-dark .pf_side.is-long,
body.appbuilder-dark .pf_dir.is-buy    { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_side.is-short,
body.appbuilder-dark .pf_dir.is-sell   { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .pf_dir.is-exit   { background:#2c2f33; color:#aab2bb; }

body.appbuilder-dark .pf_limit.is-ok     { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .pf_limit.is-warn   { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .pf_limit.is-breach { background:#3a2626; color:#ef9a9a; }

.bt_empty {
	padding:28px 20px; text-align:center; font-size:12px; color:#9aa0a8;
	font-family:'Open Sans', sans-serif;
}
.bt_empty_hint { margin-top:6px; font-size:11px; }

/* Detail pane: fixed header/params/stats, then a splittable
   instruments-over-chart pair taking whatever is left. */
.bt_detail {
	display:flex; flex-direction:column; height:100%;
	font-family:'Open Sans', sans-serif;
}
.bt_detail_head {
	flex:0 0 auto; display:flex; align-items:center; gap:8px;
	padding:10px 14px; border-bottom:1px solid #e2e2e2; background:#fafafa;
}
.bt_detail_title { font-size:13px; font-weight:600; color:#333; }
.bt_desc {
	flex:0 0 auto; padding:10px 14px 0; font-size:12px; color:#4b5563;
	line-height:1.5; white-space:pre-wrap;
}
.bt_params {
	flex:0 0 auto; display:flex; flex-wrap:wrap; gap:6px 18px;
	padding:10px 14px; border-bottom:1px solid #eceff4;
}
.bt_param   { display:flex; align-items:baseline; gap:6px; font-size:11.5px; }
.bt_param_k { color:#9aa0a8; }
.bt_param_v { color:#333; font-weight:600; }

.bt_stats {
	flex:0 0 auto; display:flex; gap:26px; padding:10px 14px;
	border-bottom:1px solid #eceff4;
}
.bt_stat_k { font-size:10px; text-transform:uppercase; letter-spacing:0.04em; color:#9aa0a8; }
.bt_stat_v { font-size:15px; font-weight:600; color:#333; margin-top:2px; }
.bt_note   { flex:0 0 auto; padding:8px 14px; font-size:11.5px; color:#b3261e; }

.bt_split  { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
.bt_runs   { flex:0 0 240px; min-height:80px; overflow:auto; padding:8px 14px 12px; }
.bt_runsplit { flex:0 0 5px; cursor:row-resize; background:#eceff4; }
.bt_runsplit:hover { background:var(--scr-accent, #0a66c2); opacity:0.35; }
.bt_rundetail { flex:1 1 auto; min-height:0; overflow:auto; }

/* A draft's instruments are removable chips: editing the list IS the job on
   this screen. Once it has run they become result rows instead. */
.bt_chips { display:flex; flex-wrap:wrap; gap:6px; }
.bt_sym {
	display:inline-flex; align-items:center; gap:4px;
	border:1px solid #e2e6ee; border-radius:12px; padding:2px 4px 2px 9px;
	background:#fff; font-size:11.5px; color:#333;
}
.bt_sym_code { font-weight:600; }
.bt_sym_x {
	border:0; background:none; cursor:pointer; color:#9aa0a8;
	padding:0 3px; border-radius:50%; font-size:10px; line-height:1;
}
.bt_sym_x:hover { background:#f3d6d6; color:#b3261e; }

/* padding-left clears the 2px selection rule: without it the blue inset edge
   paints over the left of the green status dot. The content (dot + symbol)
   sits 6px in, so the accent has its own lane. */
.bt_run {
	display:flex; align-items:center; gap:9px;
	padding:7px 8px 7px 6px; border-bottom:1px solid #eceff4; font-size:12px;
}
.bt_run:last-child { border-bottom:0; }
.bt_run.is-ok, .bt_run.is-failed { cursor:pointer; }
.bt_run.is-ok:hover, .bt_run.is-failed:hover { background:#f7f9fc; }
.bt_run.is-selected {
	background:#f4f9ff; box-shadow:inset 2px 0 0 var(--scr-accent, #0a66c2);
}
.bt_run_dot {
	flex:0 0 7px; width:7px; height:7px; border-radius:50%; background:#c3cbd9;
}
.bt_run.is-ok      .bt_run_dot { background:#00a152; }
.bt_run.is-failed  .bt_run_dot { background:#d32f2f; }
.bt_run.is-running .bt_run_dot { background:var(--scr-accent, #0a66c2); }
.bt_run_sym  { font-weight:600; color:#333; }
.bt_run_meta { font-size:11.5px; color:#4b5563; text-align:right; }
/* Trade count is context, not headline — dimmer than the return figures it
   trails. */
.bt_run_trades { color:#9aa0a8; }
/* Destructive Delete — a red twin of .w2ui-btn-blue, which is how this
   codebase makes a SOLID-coloured w2ui button.
   background-IMAGE, not background-color: .w2ui-btn paints
   `linear-gradient(#E8E8EE…)` over the element, so a background-color sits
   underneath it and never shows. Its border is `1px solid transparent`, so
   colouring only the border is exactly what produced a normal-looking button
   with a red outline. Matching .w2ui-btn-blue's shape (gradient + same-colour
   border + text-shadow) gives the flat filled button, and hover lightens the
   red rather than reverting to the grey gradient.
   Sits a touch apart from the blue Run so destructive and primary do not read
   as one control. */
button.bt_detail_delete,
button.tradescript_editor_delete {
	margin-left:6px;
	color:white !important;
	background-image:linear-gradient(#D32F2F 0%, #D32F2F 100%) !important;
	border:1px solid #D32F2F !important;
	text-shadow:0px 0px 1px #111;
}
button.bt_detail_delete:hover,
button.tradescript_editor_delete:hover {
	color:white !important;
	background-image:linear-gradient(#E24B4B 0%, #E24B4B 100%) !important;
	border:1px solid #E24B4B !important;
}
button.bt_detail_delete:active,
button.bt_detail_delete.clicked,
button.tradescript_editor_delete:active,
button.tradescript_editor_delete.clicked {
	background-image:linear-gradient(#B71C1C 0%, #B71C1C 100%) !important;
	border:1px solid #B71C1C !important;
}
.bt_detail_delete .fa,
.tradescript_editor_delete .fa { font-size:12px; }
/* Dark mode needs its own rule at MATCHING specificity. `body.appbuilder-dark
   button.w2ui-btn` (0,2,2) sets `background: var(--bg-elev) !important` and
   beat the plain `button.bt_detail_delete` (0,1,1) outright — which is why the
   button stayed standard-grey however hard the base rule shouted. It also uses
   the `background` SHORTHAND, so it wiped background-image too. Same pattern
   the blue button uses a few rules up. */
body.appbuilder-dark button.bt_detail_delete,
body.appbuilder-dark button.tradescript_editor_delete {
	background:#D32F2F !important;
	color:white !important;
	border-color:#D32F2F !important;
}
body.appbuilder-dark button.bt_detail_delete:hover,
body.appbuilder-dark button.tradescript_editor_delete:hover {
	background:#E24B4B !important;
	color:white !important;
	border-color:#E24B4B !important;
}
body.appbuilder-dark button.bt_detail_delete:active,
body.appbuilder-dark button.bt_detail_delete.clicked,
body.appbuilder-dark button.tradescript_editor_delete:active,
body.appbuilder-dark button.tradescript_editor_delete.clicked {
	background:#B71C1C !important;
	border-color:#B71C1C !important;
}

body.appbuilder-dark .bt_card_facts     { color:#aab2bb; }
body.appbuilder-dark .bt_card_perf_k,
body.appbuilder-dark .bt_empty,
body.appbuilder-dark .bt_param_k,
body.appbuilder-dark .bt_stat_k         { color:#7d848c; }
body.appbuilder-dark .bt_detail_title,
body.appbuilder-dark .bt_param_v,
body.appbuilder-dark .bt_stat_v,
body.appbuilder-dark .bt_run_sym        { color:#eee; }
body.appbuilder-dark .bt_desc,
body.appbuilder-dark .bt_run_meta       { color:#aab2bb; }
body.appbuilder-dark .bt_detail_head    { border-bottom-color:#3f4348; background:#26282b; }
body.appbuilder-dark .bt_params,
body.appbuilder-dark .bt_stats,
body.appbuilder-dark .bt_run            { border-bottom-color:#2c2f33; }
body.appbuilder-dark .bt_runsplit       { background:#2c2f33; }
body.appbuilder-dark .bt_run.is-ok:hover,
body.appbuilder-dark .bt_run.is-failed:hover { background:#26282b; }
body.appbuilder-dark .bt_run.is-selected{ background:#1e2a36; }
body.appbuilder-dark .bt_sym            { border-color:#3f4348; background:#2b2d30; color:#e6e6e6; }
body.appbuilder-dark .bt_sym_x:hover    { background:#4a2c2c; color:#ef9a9a; }
body.appbuilder-dark .bt_chip.is-draft   { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .bt_chip.is-running { background:#1e3550; color:#8fc2f0; }
body.appbuilder-dark .bt_chip.is-done    { background:#1d3a2a; color:#7fd0a0; }
body.appbuilder-dark .bt_chip.is-failed  { background:#4a2c2c; color:#ef9a9a; }
body.appbuilder-dark .bt_note            { color:#ef9a9a; }

/* ---- instrument-type segmented control ---------------------- */
/* Joined segments. The Chart/Details toggle drops border-left on
   :last-child, which only works for two; with four types the rule
   has to be :not(:first-child). */
.screener_type_tabs { display:inline-flex; vertical-align:middle; }
/* 12px to match the toolbar buttons it sits beside — the segmented control is
   borrowed from the Chart/Details toggle, which lives inside a panel at 11px,
   but here it shares a toolbar row with Apply filters / More filters and has
   to read as the same weight of control.

   HEIGHT IS 26px, NOT 30px, and the difference matters.
   This used to be 30px, "pinned to w2ui's 30px button box so the row's
   baselines line up" — which matched the wrong box. A .w2ui-tb-button is
   height:30px WITH padding:2px, so its visible chrome is ~26px; this control
   is border-box with no padding, so 30px here drew a pill 4px taller than the
   buttons beside it. Worse, the tabs live in a .w2ui-tb-line, which w2ui gives
   `min-height:28px` AND `overflow:hidden` — so the extra height did not push
   the row taller, it pushed the tab's bottom border past the clip and cut it
   off. 26px fits inside the line with a pixel to spare, and the
   `align-items:center` already on .w2ui-scroll-wrapper then centres it. */
.screener_type_tab {
	border:1px solid #d8d6d2; background:#fff; color:#666;
	font:12px OpenSans, sans-serif; padding:0 12px; height:26px; box-sizing:border-box;
	cursor:pointer;
}
.screener_type_tab:first-child          { border-radius:4px 0 0 4px; }
.screener_type_tab:last-child           { border-radius:0 4px 4px 0; }
.screener_type_tab:not(:first-child)    { border-left:0; }
.screener_type_tab:hover                { background:#f2f0ec; }
.screener_type_tab.is-active            { background:var(--scr-accent); border-color:var(--scr-accent); color:#fff; }
/* Disabled = EODHD can't screen that asset class. Muted, not hidden:
   the limitation should be visible, and the tooltip explains it. */
.screener_type_tab.is-disabled          { opacity:0.45; cursor:not-allowed; }
.screener_type_tab.is-disabled:hover    { background:#fff; }

body.appbuilder-dark .screener_type_tab           { background:#2a2b2f; border-color:#3f4348; color:#a0a0a0; }
body.appbuilder-dark .screener_type_tab:hover     { background:#33353a; }
body.appbuilder-dark .screener_type_tab.is-active { background:var(--scr-accent); border-color:var(--scr-accent); color:#fff; }
body.appbuilder-dark .screener_type_tab.is-disabled:hover { background:#2a2b2f; }

/* ---- filter bar --------------------------------------------- */
/* height:auto — the bar must size to its CONTENT so its rendered height can
   be measured and pushed back into the w2ui panel. With height:100% it would
   always report the panel's height and the wrapped rows would clip. */
.screener_filters {
	width:100%; height:auto; box-sizing:border-box;
	padding:8px 12px; background:var(--scr-bg-soft);
	border-bottom:1px solid var(--scr-border);
	/* wrap: the NL row (P3-3) takes a full line of its own above the
	   pickers; without it the two rows sat side by side. */
	display:flex; flex-wrap:wrap; align-items:flex-start; gap:10px;
	overflow:hidden; font-family:OpenSans, sans-serif;
}
/* NL → screen (P3-3): one full-width line above the pickers. The input is
   borderless inside a soft box so it reads as "say it", not "a form". */
.screener_nl_row {
	flex:1 1 100%; display:flex; align-items:center; gap:8px;
	padding:5px 10px; border:1px solid var(--scr-border); border-radius:6px;
	background:var(--scr-bg);
}
/* Focus reads exactly like every other field in the app: the house blue plus
   the 1px inset ring that fakes a 2px border. The input inside is borderless
   by design, so it suppresses the global input:focus rule that gives Symbol
   and the range boxes their ring — which left this row with a single pale
   line and no reason for being the odd one out. The ring goes on the ROW
   because the row IS the field here. */
.screener_nl_row:focus-within {
	border-color:#269DF0;
	box-shadow:inset 0 0 0 1px #269DF0;
}
body.appbuilder-dark .screener_nl_row:focus-within {
	border-color:#269DF0;
	box-shadow:inset 0 0 0 1px #269DF0;
}
.screener_nl_icon { color:#8a929b; font-size:12px; flex:0 0 auto; }
.screener_nl_input {
	flex:1 1 auto; border:none; outline:none; background:transparent;
	font-family:OpenSans; font-size:12.5px; color:var(--scr-fg, #3c434a);
	padding:2px 0;
}
.screener_nl_input::placeholder { color:#a8aeb6; }
.screener_nl_input:disabled { opacity:.55; }
/* "Reading your screen…" while the model call is in flight. Sits at the row's
   right edge, beside the wand that has become a spinner — a model call takes
   several seconds, and a 55% opacity change on the input was the only thing
   marking them. */
.screener_nl_busy {
	flex:0 0 auto; margin-left:auto; padding-left:10px;
	font:11.5px OpenSans, sans-serif; color:#8a929b; white-space:nowrap;
}
body.appbuilder-dark .screener_nl_busy { color:#8a929b; }
body.appbuilder-dark .screener_nl_input { color:#c8cfd6; }
body.appbuilder-dark .screener_nl_input::placeholder { color:#6b727b; }
.screener_filter_row {
	flex:1 1 auto; display:flex; flex-wrap:wrap; gap:10px 14px; min-width:0;
}
.screener_filter       { display:flex; flex-direction:column; gap:2px; }
.screener_filter_label {
	font:10px OpenSans, sans-serif; color:var(--scr-fg-muted);
	text-transform:uppercase; letter-spacing:0.4px;
}
.screener_filter_pick  { width:150px; }
.screener_filter_range { display:flex; gap:4px; }
.screener_filter_input {
	height:26px; box-sizing:border-box; padding:0 6px;
	border:1px solid #d8d6d2; border-radius:4px; background:#fff; color:var(--scr-fg);
	font:12px OpenSans, sans-serif; outline:none; width:150px;
}
.screener_filter_input:focus { border-color:var(--scr-accent); }
.screener_filter_num   { width:72px; }

/* The recap after a natural-language screen: what was understood, and what
   this screener has no filter for. It was 11px muted grey tucked under the
   filter row and reported as "nothing visible" — which for the one line that
   tells you a criterion was DROPPED is the worst possible outcome. Given a
   tinted bar of its own so it reads as a statement about the screen rather
   than as a caption on the control above it. */
/* box-sizing is load-bearing here. The row is a flex child at basis 100%, so
   without it the border and padding are added OUTSIDE that 100% — the bar
   overflowed to the right and .screener_filters clipped it, which read as
   "not aligned with the field above". */
.screener_warn {
	flex:0 0 100%; box-sizing:border-box; width:100%; margin-top:4px;
	font:11.5px/1.5 OpenSans, sans-serif; color:#1a5c9c;
	background:#eaf2fb; border:1px solid #cfe0f2; border-radius:5px;
	padding:5px 9px; position:relative;
}
.screener_warn i { opacity:.75; }
body.appbuilder-dark .screener_warn {
	color:#8fc0ee; background:#16283a; border-color:#27435f;
}
/* The sentence's own recap. Same blue family as the query warning — they are
   both the screen explaining itself, and a second hue implied a second kind of
   message. Told apart by its wand icon and by being dismissible. */
.screener_warn.is-recap { background:#e4eefb; border-color:#bed6f0; }
body.appbuilder-dark .screener_warn.is-recap {
	background:#182c40; border-color:#2d4d6e;
}
/* Dismiss. Same shape as the metric-help card's close (.mh_close): a floated
   glyph at half opacity that comes up on hover. Padded left so a long recap
   wraps clear of it rather than running underneath. */
.screener_warn.is-recap { padding-right:24px; }
.screener_warn_x {
	position:absolute; top:3px; right:5px;
	border:0; background:transparent; color:inherit;
	font-size:12px; line-height:1; cursor:pointer; padding:3px; opacity:.5;
}
.screener_warn_x:hover { opacity:1; }

body.appbuilder-dark .screener_filter_input { background:var(--bg-input, #2b2b2b); border-color:var(--border-strong, #505050); color:var(--fg, #e6e6e6); }

/* The Manual-setup Min/Max steppers. Same fix already applied to the trading
   config dialogs and .charts_date: tell the browser the field is dark and it
   renders its OWN dark stepper, instead of dropping a pale widget on a dark
   field where the arrows read as clipped artefacts.
   `color-scheme` on the INPUT, not the container — it is inherited, and setting
   it wider would re-theme every native control in the filter bar. */
body.appbuilder-dark .screener_filter_input[type=number] { color-scheme:dark; }

/* The grey band shown while the next page loads: <tr id="…_rec_more">
   containing <td class="w2ui-load-more"><div>…spinner…</div></td>.

   w2ui paints rgba(233,237,243,0.5) TWICE — once on the td and again on its
   inner > div, which also carries `border-top/bottom: 1px dashed #D6D5D7`
   (the dashed edges visible on the band). Styling only the td leaves the
   inner div washing over it, which is exactly what happened here. Both
   levels have to be overridden, and the dashed borders removed, or the band
   still reads as a separator slab across a dark grid.

   Selector depth mirrors w2ui's own so the panel-scoped prefix decides,
   rather than relying on !important. */
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more,
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more {
	background-color: var(--scr-bg);
	border-right: 0;
}
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more > div,
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more > div {
	background-color: var(--scr-bg);
	color: var(--scr-fg-muted);
	border-top: 0;
	border-bottom: 0;
}
/* Hover is a "click to load more" affordance we do not use — paging is by
   the footer — so keep it inert rather than flashing #f3f3f3. */
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more > div:hover,
.screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more > div:hover {
	background-color: var(--scr-bg);
	color: var(--scr-fg-muted);
}

body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more,
body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more,
body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more > div,
body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more > div,
body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-records .w2ui-load-more > div:hover,
body.appbuilder-dark .screener-standalone-panel .w2ui-grid .w2ui-grid-body .w2ui-grid-frecords .w2ui-load-more > div:hover {
	background-color: var(--bg-panel, #2b2b2b);
	color: var(--fg-muted, #a0a0a0);
	border-top-color: transparent;
	border-bottom-color: transparent;
}

/* ---- instrument logo ----------------------------------------- */
/* Monogram and image are STACKED, not swapped: the monogram is always in the
   DOM and the logo is absolutely positioned over it. So a row is never blank
   while the image is in flight, and a 404 needs no fallback logic — the
   <img> removes itself on error and the monogram is already there. */
.screener_icon {
	position:relative; display:inline-block;
	width:28px; height:28px; vertical-align:middle;
}
.screener_icon_mono {
	position:absolute; inset:0;
	display:flex; align-items:center; justify-content:center;
	border-radius:50%; background:#eceff4; color:#7a8290;
	font:600 12px OpenSans, sans-serif;
}
/* Circular disc with the logo INSET inside it.
   The padding is what makes this work: a company mark is usually drawn to the
   edges of its square, so without inset the corners get clipped by the circle.
   4px on a 28px disc leaves a 20px mark — small, but whole. object-fit:contain
   keeps non-square marks in proportion rather than stretching them.
   The disc is the SAME grey as the monogram fallback (.screener_icon_mono), so
   a row with a logo and one without read as the same control — a white disc
   stood out against the grid the way the checkboxes did. */
.screener_icon_img {
	position:absolute; inset:0;
	width:28px; height:28px; object-fit:contain;
	border-radius:50%; background:#eceff4;
	padding:4px; box-sizing:border-box;
	border:1px solid rgba(0,0,0,0.06);
}
/* Once the logo has painted the monogram is removed outright. Hiding rather
   than relying on z-order is required: EODHD logos are transparent PNGs, so a
   monogram left behind one reads through its letterforms. */
.screener_icon.has-logo .screener_icon_mono { display:none; }
/* The same disc at the favorites card's 40px slot (the instrument header's
   size), monogram scaled with it. */
.builder_recentobjects_element_logo .screener_icon.fav_icon { width:40px; height:40px; }
.builder_recentobjects_element_logo .fav_icon .screener_icon_mono { font-size:16px; }
.builder_recentobjects_element_logo .fav_icon .screener_icon_img { width:40px; height:40px; padding:6px; }

body.appbuilder-dark .screener_icon_mono { background:var(--bg-elev, #333); color:var(--fg-muted, #a0a0a0); }
/* The disc matches the dark monogram grey, same as light mode does. The
   trade-off is real and worth stating: a black-on-transparent company mark
   (rarer than colour marks, but they exist) has less contrast on grey than on
   white. If that turns out to matter more than the consistency, the fix is a
   lighter grey here — not a return to white, which is what stood out. */
body.appbuilder-dark .screener_icon_img {
	background:var(--bg-elev, #333);
	border-color:rgba(255,255,255,0.10);
}

/* ============================================================
   Instrument zoom view. Reuses the screener's --scr-* tokens so the
   two screens are one family; the panel re-declares them because it
   renders in its own tab, outside .screener-standalone-panel.
   ============================================================ */
.instrument-standalone-panel {
	--scr-border:   #e2e2e2;
	--scr-bg:       #ffffff;
	--scr-bg-soft:  #fafafa;
	--scr-fg:       #27251E;
	--scr-fg-muted: #808080;
	--scr-accent:   #2F9EEE;
	font-family: OpenSans, sans-serif;
	background: var(--scr-bg-soft);
	/* Column flex with the panel itself NOT scrolling: the header is pinned
	   and .instr_scroll takes the overflow, so the scrollbar starts below the
	   identity band instead of carrying it away. */
	display:flex; flex-direction:column; overflow:hidden;
}
.instr_scroll { flex:1 1 auto; min-height:0; overflow:auto; }
body.appbuilder-dark .instrument-standalone-panel {
	--scr-border:   var(--border, #3a3a3a);
	--scr-bg:       var(--bg-panel, #2b2b2b);
	--scr-bg-soft:  var(--bg-alt, #222222);
	--scr-fg:       var(--fg, #e6e6e6);
	--scr-fg-muted: var(--fg-muted, #a0a0a0);
}

.instr_head {
	flex:0 0 auto;
	display:flex; align-items:center; gap:14px;
	padding:14px 18px; background:var(--scr-bg);
	border-bottom:1px solid var(--scr-border);
}
/* Same disc, larger. Padding scales with it (6px on 40px keeps the same
   proportion as 4px on 28px) so the mark is inset by the same ratio rather
   than looking cramped at one size and lost at the other. */
.instr_head .screener_icon { width:40px; height:40px; }
.instr_head .screener_icon_img, .instr_head .screener_icon_mono { width:40px; height:40px; font-size:16px; }
.instr_head .screener_icon_img { padding:6px; }
.instr_head_id   { flex:0 0 auto; }
.instr_head_sym  { font-size:17px; font-weight:600; color:var(--scr-fg); }
.instr_head_name { font-size:12px; color:var(--scr-fg-muted); }
.instr_head_px   { flex:1 1 auto; }
.instr_px        { font-size:20px; font-weight:600; color:var(--scr-fg); }
.instr_chg       { font-size:12px; }
.instr_up        { color:#00a152; }
.instr_down      { color:#d32f2f; }
body.appbuilder-dark .instr_up   { color:#00c853; }
body.appbuilder-dark .instr_down { color:#ea4335; }
.instr_head_meta { flex:0 0 auto; text-align:right; }
.instr_asof      { font-size:11px; color:var(--scr-fg-muted); margin-bottom:4px; }
/* The action row is a flex line, not inline text: the BUY / SELL chips and
   the buttons then share one centre line instead of sitting on a baseline
   the chips do not have. The buttons keep their own right margins. */
.instr_head_acts { display:flex; align-items:center; justify-content:flex-end; flex-wrap:wrap; }
.instr_refresh {
	border:1px solid #d8d6d2; border-radius:4px; background:#fff; color:#666;
	font:11px OpenSans, sans-serif; padding:4px 10px; cursor:pointer;
}
.instr_refresh:hover { background:#f2f0ec; }
body.appbuilder-dark .instr_refresh { background:var(--bg-elev, #333); border-color:var(--border-strong, #505050); color:var(--fg-muted, #a0a0a0); }

/* Outbound action icons (P3-2) — chart / watchlist / alert, the quiet
   utilities beside the tinted Research door. */
.instr_act {
	border:1px solid #d8d6d2; border-radius:4px; background:#fff; color:#666;
	font-size:12px; padding:4px 8px; cursor:pointer; margin-right:4px;
}
.instr_act:hover { background:#f2f0ec; color:#1a5c9c; }
/* A toggling action (the exposure panel) shows its on-state like the
   charts topbar toggle does: accent border and text. */
.instr_act.is-on { border-color:#2F9EEE; color:#1a5c9c; background:#eef5fb; }
/* The exposure button's count chips sit after its icon, on the icon's line. */
.instr_act .pf_tabcount { vertical-align:0; margin-left:5px; }
.instr_act .pf_tabcount + .pf_tabcount { margin-left:2px; }
body.appbuilder-dark .instr_act.is-on { border-color:#2F9EEE; color:#8ec2ee; background:#1c2331; }
body.appbuilder-dark .instr_act {
	background:var(--bg-elev, #333); border-color:var(--border-strong, #505050);
	color:var(--fg-muted, #a0a0a0);
}
body.appbuilder-dark .instr_act:hover { color:#7fb3e0; }

/* The shared action dialogs (Builder_SymbolActions). */
.sa_form { padding:14px 16px; font-family:OpenSans; font-size:12.5px; }
.sa_row { display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.sa_row > label { flex:0 0 84px; color:#5a626b; font-size:12px; }
.sa_input {
	flex:1 1 auto; padding:5px 8px; border:1px solid #d0d7de; border-radius:4px;
	font-family:OpenSans; font-size:12.5px; color:#3c434a; background:#fff;
}
.sa_hint { color:#8a929b; font-size:11.5px; margin-top:2px; }
body.appbuilder-dark .sa_row > label { color:#a8b0b9; }
body.appbuilder-dark .sa_input {
	background:#1c2025; border-color:#3a4048; color:#c8cfd6;
}
body.appbuilder-dark .sa_hint { color:#8a929b; }

/* 10-year history card (P3-2) — the one card allowed to span the column
   flow (it sits LAST, where the forced break costs nothing); the decade
   scrolls horizontally INSIDE it. */
.instr_card_wide { column-span:all; -webkit-column-span:all; }
/* Cards in the column flow need a BOTTOM margin only: the card above supplies
   the gap. A column-span:all card has no card above it - the columns end and
   the spanner begins - so it has to bring its own top gap, matching the 14px
   the flow uses everywhere else.
   Both classes, deliberately: `.instr_card` is declared further down with the
   shorthand `margin: 0 0 14px`, which resets margin-top at equal specificity
   and wins on order. */
.instr_card.instr_card_wide { margin-top:14px; }
.instr_hist_wait { color:#8a929b; font-size:12px; padding:8px 0; }
.instr_hist_ccy  { font-weight:400; color:#8a929b; font-size:11px; }
.instr_hist_scroll { overflow-x:auto; }
.instr_hist_table {
	border-collapse:collapse; font-size:11.5px; white-space:nowrap;
	font-variant-numeric:tabular-nums;
}
.instr_hist_table th, .instr_hist_table td {
	padding:3px 10px; text-align:right; border-bottom:1px solid rgba(0,0,0,0.05);
}
.instr_hist_table th { color:#5a626b; font-weight:600; }
.instr_hist_k { text-align:left !important; color:#5a626b; }
body.appbuilder-dark .instr_hist_table th,
body.appbuilder-dark .instr_hist_k { color:#a8b0b9; }
body.appbuilder-dark .instr_hist_table th,
body.appbuilder-dark .instr_hist_table td { border-bottom-color:rgba(255,255,255,0.06); }

/* The dossier door (P3) — same chip as Refresh, tinted so it reads as the
   header's one navigation among its utilities. */
.instr_research {
	border:1px solid #c4d9ec; border-radius:4px; background:#eef5fb; color:#1a5c9c;
	font:11px OpenSans, sans-serif; padding:4px 10px; cursor:pointer; margin-right:6px;
}
.instr_research:hover { background:#dfeefb; }
body.appbuilder-dark .instr_research {
	background:#1d2b38; border-color:#2f4a63; color:#7fb3e0;
}
body.appbuilder-dark .instr_research:hover { background:#233649; }

/* Progressive cold open (P3) — the dossier's building skeleton. */
.co_building {
	display:flex; flex-direction:column; align-items:center; justify-content:center;
	height:100%; gap:10px; font-family:OpenSans; color:#3c434a;
}
.co_building_head { font-size:15px; font-weight:600; }
.co_building_sub  { font-size:12px; color:#8a929b; }
.co_building_steps {
	margin-top:10px; display:flex; flex-direction:column; gap:6px;
	font-size:12.5px; color:#5a626b;
}
.co_building_step .fa-check { color:#26a69a; }
.co_building_step.is-done   { color:#9aa0a8; }
/* The narrated open: which section the server is on, and how far through.
   FIXED WIDTH so the bar does not resize as the labels change length — a
   progress bar that jumps sideways reads as instability, not progress.
   min-height reserves the slot before the first frame lands, so the block
   does not shift down the moment narration starts. */
.co_openstep {
	margin-top:6px; width:260px; min-height:34px;
	font-family:OpenSans; font-size:12px;
}
.co_openstep_t { display:flex; align-items:baseline; gap:8px; color:#5a626b; }
.co_openstep_n { margin-left:auto; font-size:11px; color:#9aa0a8;
                 font-variant-numeric:tabular-nums; }
.co_openbar    { margin-top:5px; height:4px; border-radius:2px;
                 background:#eceff4; overflow:hidden; }
.co_openbar > i { display:block; height:100%; background:#269DF0;
                  transition:width .25s ease; }

body.appbuilder-dark .co_building      { color:#c8cfd6; }
body.appbuilder-dark .co_openstep_t    { color:#a8b0b9; }
body.appbuilder-dark .co_openstep_n    { color:#8d949c; }
body.appbuilder-dark .co_openbar       { background:#2c2f33; }
body.appbuilder-dark .co_openbar > i   { background:#4a9eff; }
body.appbuilder-dark .co_building_sub  { color:#8a929b; }
body.appbuilder-dark .co_building_steps { color:#a8b0b9; }
body.appbuilder-dark .co_building_step.is-done { color:#6b727b; }

/* Favorite heart toggle — sits beside Refresh. Borderless like the entry
   favorite: a grey outline heart when off, a filled blue heart when on. */
.instr_fav {
	border:0; background:none; color:#9aa0ac;
	font-size:16px; line-height:1; padding:2px 6px; margin-right:2px;
	cursor:pointer; vertical-align:middle;
}
.instr_fav:hover  { color:#2f6fed; }
.instr_fav.is-on  { color:#2f6fed; }
body.appbuilder-dark .instr_fav      { background:none; color:var(--fg-muted, #9aa0ac); }
body.appbuilder-dark .instr_fav:hover { color:#6ea8ff; }
body.appbuilder-dark .instr_fav.is-on { color:#6ea8ff; }

/* Same max-width and horizontal padding as .instr_body, so the chart card's
   edges line up exactly with the column grid below it and it spans however
   many columns there happen to be. */
.instr_chartwrap { max-width:1500px; margin:0 auto; padding:14px 18px 0; box-sizing:border-box; }
.instr_chartcard {
	position:relative;
	background:var(--scr-bg); border:1px solid var(--scr-border);
	border-radius:8px; padding:12px 14px;
}
/* Period buttons are OVERLAID on the chart's top strip rather than stacked
   above it, so they share a row with ECharts' toolbox icons (which live
   inside the canvas and are re-positioned to top:4 in _TuneChart). Stacked,
   the two control groups sat on different lines with no visual relationship. */
.instr_chartwrap .screener_type_tabs { position:absolute; top:12px; left:14px; z-index:3; }
/* The empty-chart message. It had NO styling at all, so it rendered as bare
   text at the top-left of the chart box — directly underneath the
   absolutely-positioned period buttons above, which clipped it to a few
   trailing characters ("…his span."). Centred in the box, and padded clear of
   the buttons' row so the two can never overlap again. */
.instr_chart .screener_empty {
	display: flex; align-items: center; justify-content: center;
	height: 100%; padding-top: 24px; box-sizing: border-box;
	color: var(--scr-fg-muted);
	font: 12px OpenSans, sans-serif;
	text-align: center;
}
/* Period segments are denser than the instrument-type control they borrow
   from: nine of them share one row. */
.instr_chartwrap .screener_type_tab { height:24px; padding:0 10px; font-size:11px; }

/* Height is LOCKED. The shared renderer gives its host `resize:vertical` for
   chat messages, where a user may want a taller chart inline. Here the card
   is a fixed slot in a column layout: dragging it grew the card but, past a
   point, shrank only the chart inside it — the container and its content
   disagreeing, which is what looked broken. */
.instr_chart { width:100%; height:340px; }
.instr_chart .builder-thread-chart-host {
	resize:none !important; height:340px !important; overflow:hidden;
}

/* ---- loading skeleton --------------------------------------- */
/* Grey bars standing in for stat rows while the overview loads. Uses the same
   .instr_card shell so the placeholder occupies the exact footprint its real
   counterpart will, and the column balance does not shift on arrival. */
.instr_skel_title {
	height:11px; width:44%; border-radius:3px; margin-bottom:14px;
	background:var(--scr-border);
}
.instr_skel_row {
	height:9px; border-radius:3px; margin:11px 0;
	background:var(--scr-border);
}
/* Widths alternate so it reads as label/value pairs rather than a barcode. */
.instr_skel_row:nth-child(odd)  { width:82%; }
.instr_skel_row:nth-child(even) { width:64%; }
.instr_skel { animation:instr_pulse 1.4s ease-in-out infinite; }
@keyframes instr_pulse { 0%,100% { opacity:1; } 50% { opacity:0.45; } }

/* ---- busy states -------------------------------------------- */
/* Span switches and Refresh both go to the network. Without a signal the
   panel just sat on stale numbers, which reads as broken rather than busy. */
.instr_chartcard.is-busy::after,
.instr_body.is-busy::after {
	content:""; position:absolute; inset:0; z-index:4;
	background:var(--scr-bg); opacity:0.55; border-radius:8px;
}
.instr_chartcard.is-busy::before,
.instr_body.is-busy::before {
	content:""; position:absolute; z-index:5;
	top:50%; left:50%; width:26px; height:26px; margin:-13px 0 0 -13px;
	border:2px solid var(--scr-border); border-top-color:var(--scr-accent);
	border-radius:50%; animation:instr_spin 0.7s linear infinite;
}
.instr_body { position:relative; }
@keyframes instr_spin { to { transform:rotate(360deg); } }

/* MULTI-COLUMN, not a flex/grid row layout.
   Cards here differ wildly in height — Key statistics is 12 rows, 52-week
   range is one — and any row-based layout gives every card in a row the
   height of its tallest sibling, leaving a void under the short ones. CSS
   columns flow each card immediately after the previous one, so there are no
   holes by construction and every card is the same width automatically.
   `column-width` (not column-count) also means the browser picks the number
   of columns from the space available, and the max-width stops it becoming a
   ribbon of eight columns on an ultrawide display.
   Trade-off, accepted: columns read top-to-bottom then left-to-right rather
   than left-to-right. Fine for independent stat cards, which have no reading
   order — it would not be for a narrative. */
.instr_body {
	padding:14px 18px;
	/* box-sizing MUST match .instr_chartwrap. Without it max-width:1500px is
	   1500 of CONTENT here but 1500 INCLUDING padding there, so above 1500px
	   the body came out 36px wider and, being centred, overhung the chart card
	   by 18px on each side. Below 1500px neither max-width applies and the two
	   agreed, which is why it only showed at full width. */
	max-width:1500px; margin:0 auto; box-sizing:border-box;
	column-width:300px; column-gap:14px;
}
.instr_card {
	break-inside:avoid; -webkit-column-break-inside:avoid; page-break-inside:avoid;
	width:100%; box-sizing:border-box; margin:0 0 14px;
	background:var(--scr-bg); border:1px solid var(--scr-border); border-radius:8px; padding:12px 14px;
}
/* No card spans columns any more. Profile is now an ordinary stats card and
   the description is its own "About" card, so both stack in the flow like
   everything else — a spanning card forces a break in the column flow and
   leaves exactly the kind of gap this layout exists to avoid. */
.instr_card_title { font-size:13px; font-weight:600; color:var(--scr-fg); margin-bottom:10px; }

/* ONE column, always. This was `auto-fit, minmax(190px, 1fr)`, which meant a
   card's internal density depended on how wide the card happened to be —
   Dividends spread to 5 columns and Profile to 7 once they went full-width,
   which is what made those two rows look broken. A single column keeps every
   card the same shape regardless of where the flow places it, and the card
   width is now decided once by .instr_body's column-width. */
.instr_stats  { display:grid; grid-template-columns:1fr; }
.instr_stat   { display:flex; justify-content:space-between; align-items:baseline; gap:12px; padding:5px 0; border-bottom:1px solid var(--scr-border); font-size:12px; min-width:0; }
/* Long values (ISIN, industry) truncate rather than pushing the label away. */
.instr_stat_v { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Description prose sits in a normal-width card now, so it needs a readable
   measure rather than the nowrap/ellipsis treatment stat values get. */
.instr_desc { margin-top:0; }
.instr_stat_k { color:var(--scr-fg-muted); }
.instr_stat_v { color:var(--scr-fg); font-weight:600; text-align:right; }

/* 52-week range: position read at a glance rather than as two numbers. */
.instr_range_bar {
	position:relative; height:6px; border-radius:3px; margin:8px 0 6px;
	background:linear-gradient(90deg, #d32f2f 0%, #d8d6d2 50%, #00a152 100%);
}
/* Solid accent dot. The ring is a box-shadow in the CARD's colour, not a
   border on the dot — it separates the marker from the gradient bar without
   hollowing it out. */
.instr_range_dot {
	position:absolute; top:-4px; width:14px; height:14px; margin-left:-7px;
	border-radius:50%; background:var(--scr-accent); border:0;
	box-shadow:0 0 0 2px var(--scr-bg);
}
.instr_range_ends { display:flex; justify-content:space-between; font-size:11px; color:var(--scr-fg-muted); }

.instr_bars     { display:flex; flex-direction:column; gap:4px; }
.instr_bar_row  { display:flex; align-items:center; gap:8px; font-size:11px; }
.instr_bar_k    { flex:0 0 74px; color:var(--scr-fg-muted); }
.instr_bar_track{ flex:1 1 auto; height:8px; border-radius:4px; background:#eceff4; overflow:hidden; }
body.appbuilder-dark .instr_bar_track { background:var(--bg-elev, #333); }
.instr_bar_fill { display:block; height:100%; border-radius:4px; }
.instr_bar_sb   { background:#00a152; } .instr_bar_b { background:#66bb6a; }
.instr_bar_h    { background:#b0b6c0; } .instr_bar_s { background:#ef9a9a; }
.instr_bar_ss   { background:#d32f2f; }
.instr_bar_n    { flex:0 0 26px; text-align:right; color:var(--scr-fg); }
.instr_rating   { font-weight:600; color:var(--scr-accent); }
.instr_target   { font-size:12px; color:var(--scr-fg-muted); margin-bottom:8px; }

/* ---- financial statements ------------------------------------ */
.instr_fin_title { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.instr_fin_cur   { font-weight:400; color:var(--scr-fg-muted); font-size:11px; }
/* A|Q segmented control, sized down to sit inside a card title. */
.instr_fin_tabs  { display:inline-flex; flex:0 0 auto; }
.instr_fin_tab {
	border:1px solid #d8d6d2; background:#fff; color:#666;
	font:10px OpenSans, sans-serif; padding:1px 7px; cursor:pointer;
}
.instr_fin_tab:first-child       { border-radius:3px 0 0 3px; }
.instr_fin_tab:last-child        { border-radius:0 3px 3px 0; border-left:0; }
.instr_fin_tab.is-active         { background:var(--scr-accent); border-color:var(--scr-accent); color:#fff; }
body.appbuilder-dark .instr_fin_tab           { background:#2a2b2f; border-color:#3f4348; color:#a0a0a0; }
body.appbuilder-dark .instr_fin_tab.is-active { background:var(--scr-accent); border-color:var(--scr-accent); color:#fff; }

.instr_fin_row {
	display:flex; align-items:baseline; gap:6px;
	padding:5px 0; border-bottom:1px solid var(--scr-border); font-size:11.5px;
}
.instr_fin_row:last-child { border-bottom:0; }
/* Label flexes, the three period columns are fixed and equal so figures line
   up down the card regardless of label length. */
.instr_fin_k { flex:1 1 auto; min-width:0; color:var(--scr-fg-muted);
               overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.instr_fin_v { flex:0 0 52px; text-align:right; color:var(--scr-fg); font-weight:600; }
.instr_fin_head              { border-bottom:1px solid var(--scr-border); padding-bottom:4px; }
.instr_fin_head .instr_fin_v { color:var(--scr-fg-muted); font-weight:400; font-size:10px; }

/* ---- holders ------------------------------------------------- */
.instr_hold_row {
	display:flex; align-items:baseline; gap:8px;
	padding:5px 0; border-bottom:1px solid var(--scr-border); font-size:12px;
}
.instr_hold_row:last-of-type { border-bottom:0; }
/* Fund names are long ("Vanguard Total Stock Mkt Idx Inv") — truncate the name
   rather than let it push the numbers out of alignment. Full name on hover. */
.instr_hold_n {
	flex:1 1 auto; min-width:0; color:var(--scr-fg);
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.instr_hold_p  { flex:0 0 46px; text-align:right; font-weight:600; color:var(--scr-fg); }
.instr_hold_ch { flex:0 0 52px; text-align:right; font-weight:600; }
.instr_hold_asof { margin-top:8px; font-size:10px; color:var(--scr-fg-muted); }

/* ---- news ---------------------------------------------------- */
.instr_news     { display:flex; flex-direction:column; }
.instr_news_row {
	display:flex; align-items:baseline; gap:7px;
	padding:6px 0; border-bottom:1px solid var(--scr-border); font-size:12px;
}
.instr_news_row:last-child { border-bottom:0; }
/* Sentiment dot: inline inside the date, vertically centred on it. */
.instr_news_dot {
	display:inline-block; width:6px; height:6px; border-radius:50%;
	margin-right:5px; vertical-align:middle;
}
.instr_news_pos  { background:#00a152; }
.instr_news_neg  { background:#d32f2f; }
.instr_news_flat { background:#c2c7ce; }
body.appbuilder-dark .instr_news_pos  { background:#00c853; }
body.appbuilder-dark .instr_news_neg  { background:#ef5350; }
body.appbuilder-dark .instr_news_flat { background:#55595f; }
.instr_news_d { flex:0 0 52px; font-size:10.5px; color:var(--scr-fg-muted); white-space:nowrap; }
/* Headlines wrap to at most two lines: a full title is often 90+ characters
   and left unclamped one story would own half the card. */
.instr_news_t {
	flex:1 1 auto; min-width:0; line-height:1.35;
	display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}

/* ---- events (upcoming earnings / dividends / splits) ---------------------- */
.instr_ev      { display:flex; flex-direction:column; }
.instr_ev_row  {
	display:flex; align-items:baseline; gap:8px;
	padding:6px 0; border-bottom:1px solid var(--scr-border); font-size:12px;
}
.instr_ev_row:last-child { border-bottom:0; }
.instr_ev_d    { flex:0 0 46px; font-size:10.5px; color:var(--scr-fg-muted); white-space:nowrap; }
.instr_ev_main { flex:1 1 auto; min-width:0; }
.instr_ev_badge {
	display:inline-block; font-size:9.5px; font-weight:700; text-transform:uppercase;
	letter-spacing:0.3px; padding:1px 6px; border-radius:9px; color:#fff; margin-right:6px;
	vertical-align:middle;
}
.instr_ev_k_earnings { background:#2f6fed; }
.instr_ev_k_dividend { background:#00a152; }
.instr_ev_k_split    { background:#8b5cf6; }
.instr_ev_k_ipo      { background:#f0a030; }
.instr_ev_k_economic { background:#6b7280; }
.instr_ev_t      { color:var(--scr-fg); }
.instr_ev_detail { margin-top:2px; font-size:11px; color:var(--scr-fg-muted); line-height:1.35; }

/* ---- ESG ----------------------------------------------------- */
.instr_esg_top   { display:flex; align-items:baseline; gap:7px; margin-bottom:2px; }
.instr_esg_total { font-size:20px; font-weight:600; color:var(--scr-fg); }
/* The band sits beside the number rather than in a tooltip — "26.1" alone
   invites reading a risk score as a rating out of 100. */
.instr_esg_band {
	font-size:10px; font-weight:600; padding:2px 7px; border-radius:10px;
	text-transform:uppercase; letter-spacing:0.3px; color:#fff;
}
.instr_esg_b1 { background:#00a152; } .instr_esg_b2 { background:#66bb6a; }
.instr_esg_b3 { background:#f0a030; } .instr_esg_b4 { background:#ef6c00; }
.instr_esg_b5 { background:#d32f2f; }
.instr_esg_pctl  { font-size:11px; color:var(--scr-fg-muted); margin-bottom:8px; }
.instr_esg_fill  { background:var(--scr-accent); }
.instr_esg_ctv   { margin-top:8px; font-size:11px; color:var(--scr-fg-muted); }
.instr_esg_ctv b { color:var(--scr-fg); }
/* A rating older than two years is flagged rather than silently dated. */
.instr_esg_stale { color:#b26a00; }
body.appbuilder-dark .instr_esg_stale { color:#e0a030; }

/* ---- earnings ------------------------------------------------ */
/* The upcoming quarter sits in its own block above the reported ones — it is
   a forecast, not a result, and must not read as another row in the table. */
.instr_earn_next {
	padding:8px 10px; margin-bottom:10px; border-radius:6px;
	background:var(--scr-bg-soft); border:1px solid var(--scr-border);
}
.instr_earn_next_k   { font-size:10px; text-transform:uppercase; letter-spacing:0.4px; color:var(--scr-fg-muted); }
.instr_earn_next_v   { font-size:13px; font-weight:600; color:var(--scr-fg); margin-top:2px; }
.instr_earn_next_est { font-size:11px; color:var(--scr-fg-muted); margin-top:2px; }

.instr_earn_row {
	display:flex; align-items:baseline; gap:8px;
	padding:5px 0; border-bottom:1px solid var(--scr-border); font-size:12px;
}
.instr_earn_row:last-child { border-bottom:0; }
.instr_earn_q   { flex:0 0 58px; color:var(--scr-fg-muted); }
.instr_earn_v   { flex:1 1 auto; color:var(--scr-fg); font-weight:600; text-align:right; }
.instr_earn_est { color:var(--scr-fg-muted); font-weight:400; }
/* Fixed width so the surprise column lines up regardless of sign or digits. */
.instr_earn_sp  { flex:0 0 52px; text-align:right; font-weight:600; }

.instr_desc { margin-top:0; font-size:12px; line-height:1.55; color:var(--scr-fg); white-space:pre-wrap; }
/* 12 lines ≈ the height of the Key-statistics card, which keeps every card in
   one size band. That matters structurally, not just visually: see the note on
   _AboutCard — an over-tall unbreakable card skews the column balancer and
   empties the last column. */
.instr_desc.is-clamped {
	display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:12;
	overflow:hidden;
}
.instr_more {
	margin-top:6px; padding:0; border:0; background:none; cursor:pointer;
	font:11px OpenSans, sans-serif; color:#0a66c2;
}
.instr_more:hover { text-decoration:underline; }
body.appbuilder-dark .instr_more { color:#7ab1f0; }
.instr_web  { margin-top:8px; font-size:12px; }

/* The screener's Name cell carries .gridurl and takes the shared link
   treatment — no colour of its own. The class is kept only as a hook if the
   cell ever needs layout (truncation, an icon); styling it again would
   re-fork the look it was just unified with. */

/* ---- grid cells --------------------------------------------- */
.screener_code { font-weight:600; color:var(--scr-accent); }
/* Feedback line in the Add-instruments dialog footer. Sits left of the buttons
   because Add no longer closes the dialog, so it is the only confirmation that
   the press did anything. */
.screener_pick_status { float:left; font:11.5px OpenSans, sans-serif; color:#6b7280; line-height:30px; }
body.appbuilder-dark .screener_pick_status { color:#7d848c; }
.screener_up   { color:#2e7d32; }
.screener_down { color:#c62828; }
body.appbuilder-dark .screener_up   { color:#66bb6a; }
body.appbuilder-dark .screener_down { color:#ef5350; }

/* ---- detail pane -------------------------------------------- */
.screener_detail {
	width:100%; height:100%; box-sizing:border-box;
	display:flex; flex-direction:column; overflow:hidden;
	background:var(--scr-bg); font-family:OpenSans, sans-serif;
}
.screener_detail_head {
	flex:0 0 auto; position:relative;
	padding:14px 12px 12px 16px; border-bottom:1px solid var(--scr-border);
}
.screener_detail_code { font-size:18px; font-weight:600; color:var(--scr-accent); }
.screener_detail_name { font-size:12px; color:var(--scr-fg-muted); margin-top:2px; }
/* A flex item, not pinned to the corner: the BUY / SELL chips sit beside it
   on the row's centre line, and the two must share that line. */
.screener_detail_close {
	flex:0 0 auto; margin-left:-4px;
	border:0; background:transparent; color:var(--scr-fg-muted);
	font-size:14px; cursor:pointer; padding:4px; line-height:1;
}

.screener_detail_body { flex:1 1 auto; overflow:auto; padding:8px 16px 16px; }

/* ---- side panel: enriched layout ---------------------------- */
.screener_detail_head { display:flex; align-items:center; gap:10px; }
.screener_detail_id   { flex:1 1 auto; min-width:0; }
.screener_detail_name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* The icon sits beside a two-line id block (code ~18px + name ~12px), so at the
   grid's 28px it looked undersized against it. 40px spans both rows — the same
   size the instrument zoom head uses, so the two headers match. */
.screener_detail_head .screener_icon { width:40px; height:40px; flex:0 0 auto; }
.screener_detail_head .screener_icon_img,
.screener_detail_head .screener_icon_mono { width:40px; height:40px; font-size:16px; }
.screener_detail_head .screener_icon_img { padding:6px; }

.screener_detail_px {
	flex:0 0 auto; display:flex; align-items:baseline; gap:8px;
	padding:10px 16px 2px;
}
.screener_detail_px .instr_px  { font-size:18px; }
.screener_detail_px .instr_chg { font-size:12px; }

/* Fixed height, reserved before the data arrives — the sparkline lands here a
   moment after the panel paints, and a box that grew from zero would shove
   everything below it down as you were reading. */
/* `overflow:hidden` is a guard, not the fix — see min-height below. Without
   it, anything that escapes the 120px box lands on top of the stats rather
   than being clipped, because the box is a flex item with no clipping of its
   own. */
.screener_detail_chart {
	flex:0 0 auto; height:120px; padding:0 8px;
	overflow:hidden; margin-bottom:6px;
}

/* The period the sparkline covers, stamped in the corner.

   Always present, not only on the unusual spans: the window differs per
   segment — one day for a share, a year for a bond, five for a commodity —
   and labelling only the exceptions would replace "you cannot tell" with a
   rule you have to know. Muted and out of the way, since it is a caption
   rather than a control; the panel's period buttons live in the full view. */
.screener_chart_span {
	/* A flex child of .screener_detail_px, pushed to the far right of the
	   price line. `margin-left:auto` rather than absolute positioning: the
	   row is already a flex container, so this needs no anchor and cannot
	   collide with the price when the number is long. */
	margin-left: auto;
	/* The row is baseline-aligned for the price and its change; a padded
	   chip has no meaningful baseline, so it centres against the line
	   instead of hanging off it. */
	align-self: center;
	flex: 0 0 auto;
	padding: 2px 8px; border-radius: 9px;
	/* Accent fill, matching the active segment tab — the one other place in
	   this panel that marks "which view are you looking at". Muted grey read
	   as disabled next to a coloured price. */
	background: var(--scr-accent); color: #fff;
	font: 10px OpenSans, sans-serif; letter-spacing: 0.3px; font-weight: 600;
	white-space: nowrap;
	pointer-events: none;
}
/* MIN-HEIGHT IS THE ONE THAT MATTERS.
   _RenderSimpleChartEnvelope sets the host's height inline to 320px AND
   `min-height:160px`. The `height:120px !important` here beats the inline
   height — but nothing was overriding min-height, and min-height WINS over
   height, so the host computed to 160px inside a 120px box and spilled 40px
   over the first stat rows ("Base", "Quote"…). Overriding both is what
   actually pins it to 120. */
.screener_detail_chart .builder-thread-chart-host {
	height:120px !important; min-height:120px !important;
	resize:none !important; overflow:hidden;
}

/* Chart placeholder: the series is a network round trip behind the rest of
   the panel, which paints instantly from the grid row. Without this the box
   sat empty and the panel looked finished-but-broken rather than loading. */
.screener_chart_wait, .screener_chart_none {
	height:100%; display:flex; align-items:center; justify-content:center;
	gap:8px; color:var(--scr-fg-muted);
	font:11.5px OpenSans, sans-serif;
}
.screener_chart_wait::before {
	content:""; width:15px; height:15px; flex:0 0 auto;
	border:2px solid var(--scr-border); border-top-color:var(--scr-accent);
	border-radius:50%;
	/* Same keyframe the instrument panel's busy state uses. */
	animation:instr_spin 0.7s linear infinite;
}

.screener_detail_rangewrap { margin-top:14px; }
.screener_detail_rangewrap .instr_card_title { font-size:12px; margin-bottom:6px; }

.screener_detail_about { margin-top:16px; }
.screener_detail_about .instr_card_title { font-size:12px; margin-bottom:6px; }
/* 6 lines, not the full view's 12 — this is a preview in a 400px pane, not
   the place to read three paragraphs. */
.screener_detail_about .instr_desc.is-clamped { -webkit-line-clamp:6; }
.screener_detail_about .instr_desc { font-size:11.5px; line-height:1.5; }

/* Side by side, sharing the width. A single button still fills the row on its
   own (flex:1 on the only child), so the segments that show just "Open full
   view" look exactly as they did. */
.screener_detail_foot {
	flex:0 0 auto; display:flex; gap:8px;
	padding:10px 16px 14px; border-top:1px solid var(--scr-border);
}
.screener_detail_open {
	/* min-width:0 so a long label wraps inside its half rather than pushing
	   the pair wider than the 400px pane. */
	flex:1 1 0; min-width:0; padding:7px 10px; cursor:pointer;
	border:1px solid var(--scr-border); border-radius:6px;
	/* Normal text, not the accent: these are ordinary actions sitting under the
	   panel, and blue read as two links competing with the content above. */
	background:var(--scr-bg); color:var(--scr-fg);
	font:12px OpenSans, sans-serif;
}
.screener_detail_open:hover { background:#f2f6fb; }
body.appbuilder-dark .screener_detail_open       { background:var(--bg-elev, #333); border-color:var(--border-strong, #505050); }
body.appbuilder-dark .screener_detail_open:hover { background:var(--bg-hover, #3a3a3a); }
.screener_detail_row {
	display:flex; justify-content:space-between; gap:12px;
	padding:6px 0; border-bottom:1px solid var(--scr-border);
	font-size:12px;
}
.screener_detail_row:last-child { border-bottom:0; }
.screener_detail_k { color:var(--scr-fg-muted); }
.screener_detail_v { color:var(--scr-fg); font-weight:600; text-align:right; }

/* ---- filter bar: multi-select + interval pickers ------------- */
/* The bar wraps to two rows when expanded and grows again for the
   warning line, so it lays out as a wrapping flex row rather than a
   fixed-height strip; _FilterBarHeight() keeps the panel in step. */
.screener_filters      { flex-wrap:wrap; align-content:flex-start; }

/* Pick buttons are the house .wf-pickbtn; only the width is ours.
   Range pickers carry longer labels ("Large 10–200B") than the enum
   ones, hence the wider basis. */
.screener_filter_pick  { width:170px; }
.screener_filter_pick .wf-pickbtn { width:100%; height:26px; }

/* A set filter reads bold, matching SFA's convention of bolding a
   non-default selection so an active filter is visible at a glance
   without a separate chip row. */
.wf-pickbtn-text.is-set { font-weight:600; color:var(--scr-accent); }

/* Manual min/max sit UNDER their picker, revealed by "Manual setup". */
.screener_filter_range { margin-top:4px; }

/* ---- grid chrome --------------------------------------------- */
/* w2ui paints the grid footer on its own light-grey, which reads as a
   hard band across the bottom of a dark grid. Match it to the grid
   body and let a single hairline do the separating. */
.screener-standalone-panel .w2ui-grid-footer {
	background: var(--scr-bg);
	color: var(--scr-fg-muted);
	border-top: 1px solid var(--scr-border);
}
body.appbuilder-dark .screener-standalone-panel .w2ui-grid-footer {
	background: var(--bg-panel, #2b2b2b) !important;
	color: var(--fg-muted, #a0a0a0) !important;
	border-top-color: var(--border, #3a3a3a) !important;
}

/* The "loading" plate shown while a page is fetched. w2ui paints it #555 on
   a #333 dim, which is a slab of grey across the grid on every page change.
   Match the grid instead and let it read as a quiet inline notice — the
   spinner already communicates that something is happening. */
.screener-standalone-panel .w2ui-lock {
	background-color: var(--scr-bg);
	opacity: 0.35;
}
.screener-standalone-panel .w2ui-lock-msg {
	background-color: var(--scr-bg);
	color: var(--scr-fg-muted);
	border: 1px solid var(--scr-border);
	box-shadow: 0 2px 8px rgba(0,0,0,0.12);
	opacity: 1;
	padding: 12px 22px;
	font-family: OpenSans, sans-serif;
}
body.appbuilder-dark .screener-standalone-panel .w2ui-lock {
	background-color: var(--bg, #1a1a1a);
}
body.appbuilder-dark .screener-standalone-panel .w2ui-lock-msg {
	background-color: var(--bg-elev, #333333);
	color: var(--fg-muted, #a0a0a0);
	border-color: var(--border-strong, #505050);
	box-shadow: 0 2px 10px rgba(0,0,0,0.45);
}

/* Package-contributed rows in the top-search popups (recently viewed +
   search results).

   The popups' own rule is `> div > img { width:32px; height:32px }` with no
   object-fit, which is correct for what it was written for: generated
   monograms, which are square by construction. A package row carries a REAL
   vendor logo of arbitrary aspect, and those were being STRETCHED to a square
   — an ETF issuer's wordmark ("Vanguard", "iShares") is several times wider
   than it is tall, so it arrived as an unreadable smear. Stock logos are
   mostly square, which is why this only surfaced once funds appeared in the
   list.

   `contain` fits the whole mark inside the disc; the disc itself is needed
   because these are TRANSPARENT PNGs, and a dark mark on the dark popup would
   otherwise vanish. Same treatment, and the same reasoning, as
   .screener_icon_img in the grid. */
img.pkgrow_logo {
	object-fit: contain;
	background: #eceff4;
	padding: 3px;
	box-sizing: border-box;
	border: 1px solid rgba(0,0,0,0.06);
}
/* Same dark disc the grid's icons use (.screener_icon_img) rather than a
   colour of its own — the two sit inches apart on screen, and a logo that
   changed shade between the grid and the search popup would read as two
   different components. */
body.appbuilder-dark img.pkgrow_logo {
	background: var(--bg-elev, #333);
	border-color: rgba(255,255,255,0.10);
}
/* The monogram fallback gets the OPPOSITE treatment: it is an opaque square we
   generated, so it should fill the round frame edge to edge. Given the disc and
   padding above it would render as a small square floating inside a circle. */
img.pkgrow_mono { object-fit: cover; padding: 0; border: 0; background: none; }

/* ================================================================
   ETF screener + ETF zoom view
   ----------------------------------------------------------------
   Everything here is written against the --scr-* custom properties,
   which are already redefined under body.appbuilder-dark (see the
   block near the top of the screener styles). That is deliberate:
   these rules then carry BOTH themes with no dark-mode twin to keep
   in step, which is where the older instrument styles have needed
   one override per rule.
   ================================================================ */

/* A cell that is blank because the background profile walker has not
   reached this fund yet, as opposed to one the fund genuinely has no
   value for. Without the distinction a half-walked roster reads as
   missing data rather than as loading. */
.screener_pending {
	color: var(--scr-fg-muted);
	opacity: 0.55;
	font-weight: 700;
	/* `help`, matching the other data-tooltip carriers — the marker exists to
	   be hovered, and `default` gives no sign there is anything to read. */
	cursor: help;
}

/* ---- side-panel top holdings --------------------------------- */
.screener_detail_sub {
	font-size: 12px; font-weight: 600; color: var(--scr-fg);
	margin: 14px 0 6px;
}
.etf_minihold { display: flex; flex-direction: column; }
.etf_minihold_row {
	display: flex; justify-content: space-between; gap: 10px;
	padding: 4px 0; border-bottom: 1px solid var(--scr-border);
	font-size: 11.5px;
}
.etf_minihold_row:last-child { border-bottom: 0; }
/* The name is the elastic half and the weight the fixed one: a long
   fund holding truncates, a percentage never does. */
.etf_minihold_n {
	color: var(--scr-fg); overflow: hidden;
	text-overflow: ellipsis; white-space: nowrap;
}
.etf_minihold_w { color: var(--scr-fg-muted); flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* ---- weight bars (sectors, regions, allocation, cap mix) ------ */
/* Reuses .instr_bar_row / _k / _track / _n from the analyst-ratings
   card — same shape, same column widths — and only recolours the
   fill, so the two read as one component family. */
.etf_weights { display: flex; flex-direction: column; gap: 2px; }
.etf_bar_fill { background: var(--scr-accent); opacity: 0.75; }
.etf_weights .instr_bar_k {
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etf_weights .instr_bar_n { font-variant-numeric: tabular-nums; }

/* ---- constituents -------------------------------------------- */
/* OUTSIDE the card flow, in its own block after .instr_body.
   Not a card and not a spanning card. .instr_body is a CSS
   multi-column flow (column-width:300px): a six-column table in a
   300px column wraps every name, and `column-span:all` — the obvious
   fix — forces a BREAK. The browser must finish the columns above
   before placing a spanner, and balancing against one very tall card
   (Fund facts, 17 rows) made every column that tall, so three of
   five columns sat empty and the table was pushed below a band of
   white space. Out of the flow, there is no break to force.
   Padding matches .instr_body's so the block lines up with the left
   edge of the first column; max-width matches its 1500px so the two
   centre together. */
/* A flex ROW, not a block: the table takes two columns' worth and
   About absorbs the remainder, so the bottom of the page is a full
   row rather than a lone table with dead space beside it.
   Padding and max-width match .instr_body's so the row lines up with
   the column grid above it. */
.etf_holdsection {
	max-width: 1500px; margin: 0 auto;
	padding: 0 18px 14px; box-sizing: border-box;
	display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start;
}
/* The cards already carry their own bottom margin for the column
   flow; in a flex row the gap does that job and the margin would
   double it. */
.etf_holdsection > .instr_card,
.etf_holdsection .etf_about > .instr_card { margin: 0; }

/* Width is set in JS — see _SizeConstituents. It has to be MEASURED
   from a real rendered card, because `column-width:300px` is only a
   minimum and the browser stretches the actual columns to fill. */
.etf_card_wide { flex: 0 0 auto; }

/* Takes whatever is left. `min-width:0` is required — a flex item
   defaults to min-width:auto, which refuses to shrink below its
   content and would push the row to wrap even when there is room. */
.etf_about { flex: 1 1 260px; min-width: 0; }

/* The number of underlying assets, in the title where it answers the
   first question anyone has about a fund's holdings. The fund's OWN
   count, which is usually larger than the rows below — .etf_card_note
   says by how much. */
.etf_card_count {
	display: inline-block; margin-left: 8px;
	padding: 1px 7px; border-radius: 9px;
	background: var(--scr-bg-soft); border: 1px solid var(--scr-border);
	font-size: 11px; font-weight: 600; color: var(--scr-fg-muted);
	font-variant-numeric: tabular-nums;
}

/* A secondary line on the card title, for the coverage and source
   caveats — "Top holdings only — 41.2% of fund assets". Quieter than
   the title but on the same line, because it QUALIFIES the table and
   would be missed as a footnote underneath it. */
.etf_card_note {
	float: right; font-weight: 400; font-size: 11px;
	color: var(--scr-fg-muted);
}

/* Scrolls on its own axis. A broad fund can list a few hundred rows,
   and the panel's own scroll is already carrying the whole overview. */
.etf_holdings_wrap { max-height: 420px; overflow: auto; }
.etf_holdings {
	width: 100%; border-collapse: collapse;
	font-size: 12px; color: var(--scr-fg);
}
.etf_holdings thead th {
	position: sticky; top: 0; z-index: 1;
	background: var(--scr-bg);
	text-align: left; font-weight: 600; font-size: 11px;
	color: var(--scr-fg-muted);
	padding: 6px 8px; border-bottom: 1px solid var(--scr-border);
}
.etf_holdings td {
	padding: 5px 8px; border-bottom: 1px solid var(--scr-border);
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.etf_holdings tbody tr:last-child td { border-bottom: 0; }
.etf_holdings tbody tr:hover { background: var(--scr-bg-soft); }
.etf_h_rank { width: 34px; color: var(--scr-fg-muted); text-align: right; }
.etf_h_code { width: 90px; font-weight: 600; }
/* The only column allowed to take the slack — everything else is
   sized, so a 60-character fund name cannot push the weight off the
   right edge. */
.etf_h_name { max-width: 0; width: 100%; }
.etf_h_sec  { width: 150px; color: var(--scr-fg-muted); }
.etf_h_cty  { width: 110px; color: var(--scr-fg-muted); }
.etf_h_w    { width: 80px; text-align: right; font-variant-numeric: tabular-nums; }

/* ---- fund vs category ---------------------------------------- */
.etf_vs { width: 100%; border-collapse: collapse; font-size: 12px; color: var(--scr-fg); }
.etf_vs thead th {
	text-align: right; font-weight: 600; font-size: 11px;
	color: var(--scr-fg-muted); padding: 4px 6px;
	border-bottom: 1px solid var(--scr-border);
}
.etf_vs thead th:first-child { text-align: left; }
.etf_vs td { padding: 5px 6px; border-bottom: 1px solid var(--scr-border); }
.etf_vs tbody tr:last-child td { border-bottom: 0; }
.etf_vs_k { color: var(--scr-fg-muted); }
.etf_vs_v, .etf_vs_c, .etf_vs_d {
	text-align: right; font-variant-numeric: tabular-nums;
}
.etf_vs_v { font-weight: 600; }
.etf_vs_c { color: var(--scr-fg-muted); }

/* ---- crypto: project links + team ----------------------------- */
/* Chips rather than a list: there are usually six to ten of them,
   they are short, and wrapping chips fit a 300px card column where
   one link per row would make the tallest card on the page. */
.crypto_links { display: flex; flex-wrap: wrap; gap: 6px; }
.crypto_link {
	display: inline-flex; align-items: center; gap: 6px;
	max-width: 100%; padding: 4px 9px;
	border: 1px solid var(--scr-border); border-radius: 13px;
	background: var(--scr-bg-soft); color: var(--scr-fg);
	font-size: 11.5px; text-decoration: none;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.crypto_link:hover {
	border-color: var(--scr-accent); color: var(--scr-accent);
	text-decoration: none;
}
.crypto_link i { color: var(--scr-fg-muted); font-size: 12px; }
.crypto_link:hover i { color: var(--scr-accent); }

/* ---- bonds: yield moves + curve ------------------------------- */
/* Basis-point moves are NOT green/red. On an equity, up is good; on
   a yield it depends entirely on whether you hold the bond or are
   about to buy it, so colouring it would assert something false.
   Direction is carried by weight and the explicit +/- sign instead. */
.bond_up, .bond_down { font-weight: 600; }
.bond_up   { color: var(--scr-fg); }
.bond_down { color: var(--scr-fg-muted); }

.bond_curve { display: flex; flex-direction: column; gap: 2px; }
.bond_curve_row { cursor: pointer; border-radius: 3px; }
.bond_curve_row:hover { background: var(--scr-bg-soft); }
/* The tenor you are looking at, marked on its own curve. */
.bond_curve_row.is-current .instr_bar_k,
.bond_curve_row.is-current .instr_bar_n { font-weight: 700; color: var(--scr-accent); }
.bond_curve_row.is-current .bond_bar_fill { opacity: 1; }
.bond_bar_fill { background: var(--scr-accent); opacity: 0.55; }
.bond_curve .instr_bar_n { font-variant-numeric: tabular-nums; }

/* ---- forex: crosses ------------------------------------------- */
/* Bars grow from the CENTRE, not the left: these are signed daily
   moves, and direction is the whole point of the card. A
   left-anchored bar would need the sign read off the number. */
.fx_crosses { display: flex; flex-direction: column; gap: 2px; }
.fx_cross_row { cursor: pointer; border-radius: 3px; }
.fx_cross_row:hover { background: var(--scr-bg-soft); }
.fx_cross_track { position: relative; }
/* The centre line the bars grow from. */
.fx_cross_track::before {
	content: ""; position: absolute; left: 50%; top: 0; bottom: 0;
	width: 1px; background: var(--scr-border);
}
.fx_cross_fill {
	position: absolute; top: 0; bottom: 0;
	border-radius: 3px; min-width: 1px;
}
/* RED / GREEN, and the same green and red the grid's "1D %" column uses
   (.screener_up / .screener_down). These bars are price moves, so the equity
   convention is the right one here — and reusing the exact tokens means the
   card and the column cannot disagree about what "up" looks like on the
   same number.
   This is deliberately the OPPOSITE call to the bond curve below: those
   bars are yield LEVELS rather than changes, and there is no good or bad
   direction for a yield to sit in. */
.fx_cross_fill.is-up   { left: 50%;  background: #2e7d32; opacity: 0.85; }
/* Right-anchored at the midpoint so a negative bar grows leftwards. */
.fx_cross_fill.is-down { right: 50%; background: #c62828; opacity: 0.85; }
body.appbuilder-dark .fx_cross_fill.is-up   { background: #66bb6a; }
body.appbuilder-dark .fx_cross_fill.is-down { background: #ef5350; }
.fx_crosses .instr_bar_n { font-variant-numeric: tabular-nums; }

.fx_inverse { font-size: 13px; font-weight: 600; }

/* Index peers reuse the FX crosses component wholesale — same signed,
   centre-anchored 1D bars. Only the label column differs: a peer is
   keyed by an index CODE ("GDAXI", "MDAXI"), which needs more room
   than a three-letter currency. */
.index_peers .instr_bar_k { flex: 0 0 92px; }

/* Row density for the labelled-bar lists (ETF weights, bond curve, FX
   crosses). The bare .instr_bar_row is an 11px line with no vertical
   padding, which packs eleven sectors into ~120px and reads as a wall.
   Scoped to these three containers rather than applied to .instr_bar_row
   itself — the analyst-ratings card uses the same row and is a five-item
   list where the tighter rhythm is fine. */
.etf_weights .instr_bar_row,
.bond_curve .instr_bar_row,
.fx_crosses .instr_bar_row {
	padding: 4px 6px;
	font-size: 11.5px;
	border-radius: 3px;
}
/* The bar grows with the row so it is not left looking lost in it. */
.etf_weights .instr_bar_track,
.bond_curve .instr_bar_track,
.fx_crosses .instr_bar_track { height: 9px; border-radius: 5px; }
.etf_weights .instr_bar_fill,
.bond_curve .instr_bar_fill { border-radius: 5px; }
/* The numeric column needs more than the shared 26px once it carries a
   sign and a unit ("-1,21%", "4,697%"), or the values wrap. */
.etf_weights .instr_bar_n,
.bond_curve .instr_bar_n,
.fx_crosses .instr_bar_n { flex: 0 0 52px; }

/* LABEL COLUMN WIDTH, per family rather than one number everywhere.

   The shared .instr_bar_k is 74px, which was sized for the analyst card
   ("Strong buy"). The ETF breakdowns carry a Morningstar taxonomy —
   "Communication Services", "Consumer Defensive", "Africa/Middle East",
   "Stock non-US" — and at 74px most of them were clipped to two words and
   an ellipsis, which is the one thing a weights list must not do: the
   label IS the data.

   130px fits essentially the whole taxonomy at 11.5px and still leaves the
   bar ~130px in a 355px card, which is plenty for a shape comparison.

   Bond tenors ("10Y") and FX codes ("USD") are three characters and are
   deliberately NOT widened — giving them 130px would take it straight off
   the bar to display whitespace. Consistent means "the label column fits
   its labels", not "every card uses the same number".  */
.etf_weights .instr_bar_k {
	/* 0 1, not 0 0: the label may SHRINK when the card is narrow. These
	   cards sit in a CSS-columns flow whose column width follows the
	   window, so a rigid 130px would eat the row at the narrow end and
	   leave a 60px stub of bar. Letting the label give way first keeps
	   the bar meaningful, and the full text is on a tooltip anyway. */
	flex: 0 1 130px;
	min-width: 0;
	color: var(--scr-fg);
}
/* …and a floor for the bar, which is what makes that shrink land on the
   label rather than on the thing the card exists to show. */
.etf_weights .instr_bar_track { min-width: 70px; }
/* Belt and braces for the handful that still will not fit: the full name
   is on a data-tooltip (see _WeightsCard), and this makes it clear the
   text is hoverable rather than simply broken. */
.etf_weights .instr_bar_k[data-tooltip] { cursor: help; }

/* ---- commodities: provenance note ----------------------------- */
/* Deliberately quiet but not hidden. Every caveat in it is one that
   changes how the number above should be read — staleness, units,
   and the missing precious metals — so it is a card on the panel
   rather than a tooltip nobody opens. */
.commodity_note {
	display: flex; flex-direction: column; gap: 6px;
	font-size: 11.5px; line-height: 1.5;
	color: var(--scr-fg-muted);
}

.crypto_devs { display: flex; flex-direction: column; gap: 3px; }
.crypto_dev {
	font-size: 11.5px; color: var(--scr-fg);
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ================================================================
 * Charts — the Supercharts-style screen: a topbar of what to draw,
 * a grid of up to four charts, and a collapsible right panel.
 *
 * Light and dark ship together (see the appbuilder-dark block at the
 * end of this section). Anything that sets a colour here has a dark
 * counterpart there — a half-themed screen is worse than an unthemed
 * one, because it looks finished.
 * ================================================================ */

/* ---- topbar ---------------------------------------------------- */
.charts_topbar {
	display:flex; align-items:center; gap:8px;
	height:100%; padding:0 10px; box-sizing:border-box;
	background:#fafafa; border-bottom:1px solid #e2e2e2;
	font-family:OpenSans;
}
/* Instrument / compare field — a bordered box, fixed width, with the chips
   scrolling INSIDE it and the + pinned at its right edge so "add" reads as
   part of the field. flex:0 1 400px caps it at the requested 400px but lets it
   shrink on a narrow window rather than pushing the controls off the bar. */
.charts_field_box {
	display:flex; align-items:center; flex:0 1 400px; min-width:180px;
	height:32px; box-sizing:border-box;
	border:1px solid #dcdcdc; border-radius:4px; background:#fff;
	overflow:hidden;
	/* The whole box opens the picker (except on a chip), so it reads as one
	   big Add control. */
	cursor:pointer;
}
.charts_field_box:hover { border-color:#bcccdc; }
/* Focus belongs to the WHOLE field — chips, input and + together read as
   one control, so the ring wraps all of it (the standard blue, thickened
   with a ring shadow so nothing shifts). The input inside carries inline
   border/outline resets, so no global input rule can draw inside the box. */
.charts_field_box:focus-within {
	border-color:#2F9EEE;
	box-shadow:0 0 0 1px #2F9EEE;
}
body.appbuilder-dark .charts_field_box:focus-within {
	border-color:#3a86c8;
	box-shadow:0 0 0 1px #3a86c8;
}
/* A chip is its own thing — its × removes it — so it does not inherit the
   box's add-pointer. */
.charts_tag { cursor:default; }
.charts_tags {
	display:flex; align-items:center; gap:5px; flex:1 1 auto;
	min-width:0; height:100%; overflow-x:auto; overflow-y:hidden;
	padding:0 6px; box-sizing:border-box;
}
.charts_tags::-webkit-scrollbar { height:4px; }
.charts_tags::-webkit-scrollbar-thumb { background:#ccc; border-radius:2px; }
/* The + lives inside the field, against its right edge. A left divider keeps
   it from crowding a full chip list. */
.charts_field_add {
	flex:0 0 auto; width:30px; height:100%; border:0; cursor:pointer;
	background:transparent; color:#6b7280; font-size:12px;
	border-left:1px solid #ececec;
}
.charts_field_add:hover { background:#f0f4f9; color:#1a5c9c; }
.charts_tag {
	display:inline-flex; align-items:center; gap:5px; flex:0 0 auto;
	font-size:11.5px; font-weight:600; color:#1a5c9c;
	background:#dceafb; border:1px solid #b9d4f5; border-radius:10px; padding:1px 7px;
	white-space:nowrap;
}
/* Benchmarks wear their own colour so the two fields are not mistaken for one
   another — violet, matching the first comparison line the chart draws. */
.charts_cmp_tags .charts_tag {
	color:#6a3fb0; background:#efe7f8; border-color:#d7c4ee;
}
.charts_tag_x {
	font-size:10px; cursor:pointer; opacity:.55;
}
.charts_tag_x:hover { opacity:1; color:#b3261e; }
.charts_tags_empty { font-size:11.5px; color:#9aa0a8; white-space:nowrap; }
.charts_tags_count {
	flex:0 0 auto; margin-left:auto; padding-left:8px;
	font-size:10.5px; color:#9aa0a8; white-space:nowrap;
}
.charts_field {
	display:flex; align-items:center; gap:6px; flex:0 0 auto;
}
.charts_field > label {
	font-size:11px; color:#6b7280; white-space:nowrap;
}
/* Section rule. The topbar runs three groups together — what is charted, how
   it is drawn, over what period — and a hairline is enough to say so without
   spending a caption on it. */
.charts_sep {
	flex:0 0 auto; width:1px; height:20px; background:#e2e2e2;
	margin:0 2px;
}
/* Volume toggle — a labelless icon button beside the style picker, since both
   answer "how is the price drawn?" rather than "what is charted?". It carries
   its own border because, unlike the picker, there is no pick-button chrome
   underneath it. */
.charts_volbtn {
	display:flex; align-items:center; justify-content:center;
	width:34px; height:30px; box-sizing:border-box; cursor:pointer;
	border:1px solid #d7dde3; border-radius:4px; background:#fff;
	color:#4a5158; font-size:12px;
}
.charts_volbtn:hover { border-color:#b9c6d2; color:#1a5c9c; }
/* Off reads as switched off — dimmed and struck through — rather than merely
   quiet, so the panel's absence is explained by the control.  */
.charts_volbtn.is-off { color:#aab2bb; background:#f6f7f8; }
.charts_volbtn.is-off > .fa { position:relative; }
.charts_volbtn.is-off > .fa::after {
	content:""; position:absolute; left:-2px; right:-2px; top:50%;
	border-top:1.5px solid currentColor; transform:rotate(-20deg);
}
/* Chart-style picker — the only labelless picklist on the bar: its button
   carries the chart-type glyph, which says what a "Style" caption would. */
.charts_style_field > span { display:flex; }
.charts_style_field .wf-pickbtn {
	width:auto; min-width:132px; height:30px; padding:0 8px;
}
.charts_style_field .wf-pickbtn-text { display:flex; align-items:center; gap:7px; }
/* One glyph, two homes (the button and the menu rows), so it is styled once.
   Drawn in currentColor — it inherits whatever the surface gives it, which is
   what makes it correct in dark mode for free. */
.charts_style_ico { flex:0 0 auto; display:inline-block; vertical-align:-2px; }
.charts_style_lbl { white-space:nowrap; }
/* w2menu rows: the icon needs the same gap it has on the button. */
.w2ui-menu .charts_style_ico { margin-right:8px; }
.charts_dates_sep { color:#9aa0a8; font-size:12px; }
.charts_date {
	/* The house date control (w2field): a text input, so it needs its own width. */
	width:104px;
	height:28px; padding:0 6px; box-sizing:border-box;
	border:1px solid #dcdcdc; border-radius:4px; background:#fff;
	font-family:OpenSans; font-size:11.5px; color:#333;
}
.charts_spacer { flex:1 1 auto; }
/* Apply stands in the filter row, so it takes the picklists' height (12px text
   + 6px padding + border = 30px) rather than the 32px + 14px text every dialog
   button gets. Every declaration is !important because the builder's own
   w2ui-btn rule (search "Dialog / popup buttons") pins height, line-height and
   padding with !important — the same reason .w2ui-btn-small has to. This rule
   sits after it, so equal weight resolves here. */
button.w2ui-btn.charts_applybtn {
	flex:0 0 auto; box-sizing:border-box !important;
	height:30px !important; padding:0 12px !important;
	line-height:1 !important; font-size:12px !important; min-width:0 !important;
	display:inline-flex !important; align-items:center !important; justify-content:center !important;
}
button.w2ui-btn.charts_applybtn .fa { font-size:11.5px; line-height:1; }
/* Indicators — opens the library palette. Same footprint as Apply and Replay
   either side of it: the three read as one row of chart actions. */
button.w2ui-btn.charts_indbtn {
	flex:0 0 auto; box-sizing:border-box !important;
	height:30px !important; padding:0 12px !important; margin-left:6px;
	line-height:1 !important; font-size:12px !important; min-width:0 !important;
	display:inline-flex !important; align-items:center !important; justify-content:center !important;
}
button.w2ui-btn.charts_indbtn .fa { font-size:11px; line-height:1; }
/* Replay toggle — same footprint as Apply, sits right after it. Outlined
   normally; filled while replay is on so it reads as a live mode. */
button.w2ui-btn.charts_replaybtn {
	flex:0 0 auto; box-sizing:border-box !important;
	height:30px !important; padding:0 12px !important; margin-left:6px;
	line-height:1 !important; font-size:12px !important; min-width:0 !important;
	display:inline-flex !important; align-items:center !important; justify-content:center !important;
}
button.w2ui-btn.charts_replaybtn .fa { font-size:11px; line-height:1; }

/* ---- replay transport bar --------------------------------------- */
/* A neutral strip; the BLUE is on the scrubber (the progress bar) and the
   play button, not the whole bar. */
.charts_replay {
	display:flex; align-items:center; gap:8px;
	height:100%; padding:0 10px; box-sizing:border-box;
	background:#fafafa; border-top:1px solid #e2e2e2; font-family:OpenSans;
}
.charts_replay_sym {
	flex:0 0 auto; font-weight:600; font-size:12px; color:#1a5c9c;
	padding-right:6px; border-right:1px solid #e2e2e2;
}
.charts_replay_btn {
	flex:0 0 auto; width:30px; height:28px;
	display:flex; align-items:center; justify-content:center;
	border:1px solid #dcdcdc; border-radius:5px; background:#fff;
	color:#4a5158; cursor:pointer; font-size:12px; padding:0;
}
.charts_replay_btn:hover { background:#f0f4f9; color:#1a5c9c; border-color:#bcccdc; }
/* Play/pause is the primary control — a filled blue circle, white glyph, no
   border, the way a player's play button reads. */
.charts_replay_btn.is-play {
	background:#2F9EEE; border:0; border-radius:50%; color:#fff; width:30px; height:30px;
}
.charts_replay_btn.is-play:hover { background:#1a86d9; color:#fff; }
/* Closing playback is a CLOSE, not a transport control  so it drops the
   button box the play/step siblings wear and reads as the app-wide quiet
   close (shared hover rule at the end of this file). */
.charts_replay_btn.is-close {
	margin-left:auto; background:transparent; border-color:transparent;
}
/* The progress bar — a BLUE track with a borderless WHITE dot.
   `!important` throughout because w2ui.min.css styles `input[type=range]` (and
   its track/thumb) with a higher-specificity attribute selector — that grey
   track and bordered thumb, plus its `margin:10px 0 0 0`, are what showed
   through and pushed the bar out of line with the counter. */
.charts_replay_scrub {
	flex:1 1 auto; min-width:120px; cursor:pointer;
	-webkit-appearance:none !important; appearance:none !important;
	height:14px !important; margin:0 !important; background:transparent !important;
	border:0 !important;
}
.charts_replay_scrub::-webkit-slider-runnable-track {
	height:6px !important; border-radius:3px !important; background:#2F9EEE !important;
	border:0 !important;
}
.charts_replay_scrub::-webkit-slider-thumb {
	-webkit-appearance:none !important; appearance:none !important;
	width:14px !important; height:14px !important; margin-top:-4px !important;
	border-radius:50% !important; background:#fff !important; border:0 !important;
	box-shadow:0 1px 2px rgba(0,0,0,.35) !important;
}
.charts_replay_scrub::-moz-range-track {
	height:6px !important; border-radius:3px !important; background:#2F9EEE !important;
	border:0 !important;
}
.charts_replay_scrub::-moz-range-thumb {
	width:14px !important; height:14px !important; border:0 !important;
	border-radius:50% !important; background:#fff !important;
	box-shadow:0 1px 2px rgba(0,0,0,.35) !important;
}
.charts_replay_pos {
	flex:0 0 auto; font-size:11.5px; color:#6b7280; min-width:78px; text-align:right;
	font-variant-numeric:tabular-nums;
}
.charts_replay_hint { flex:0 0 auto; font-size:11px; color:#9aa0a8; white-space:nowrap; }
@media (max-width: 900px) { .charts_replay_hint { display:none; } }
/* Layout control — the saved-view name + caret, left of Apply. Reads like a
   picklist button; the caret is the affordance for the manage menu. */
.charts_layout {
	flex:0 0 auto; display:flex; align-items:center; gap:6px;
	max-width:200px; height:30px; padding:0 8px; box-sizing:border-box;
	border:1px solid #dcdcdc; border-radius:4px; background:#fff;
	font-family:OpenSans; font-size:12px; color:#333; cursor:pointer;
}
.charts_layout:hover { border-color:#bcccdc; background:#f7f9fc; }
.charts_layout_name {
	min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
	font-weight:600;
}
/* Not backed by a saved layout yet — italic so the placeholder does not read
   like a real layout name. NOT greyed: grey here reads as "disabled". The
   padding is for the slant: the last glyph leans past its box and the
   overflow:hidden above would shave it off. */
.charts_layout_name.is-untitled {
	font-weight:400; font-style:italic; padding-right:3px;
}
.charts_layout_caret { font-size:11px; color:#9aa0a8; flex:0 0 auto; }

/* Open-layout popup — a simple selectable + deletable list. */
.charts_layout_list { padding:6px 0; font-family:OpenSans; }
.charts_layout_empty { padding:24px; text-align:center; font-size:12px; color:#9aa0a8; }
.charts_layout_row {
	display:flex; align-items:center; gap:8px;
	padding:8px 16px; border-bottom:1px solid #f0f0f0;
}
.charts_layout_row:hover { background:#f6f9fd; }
.charts_layout_row.is-current { background:#eef5fd; }
.charts_layout_row_main { flex:1 1 auto; min-width:0; cursor:pointer; }
.charts_layout_row_top {
	display:flex; align-items:center; gap:8px; min-width:0;
}
/* Real margin, not a lone &nbsp; — the icon was scotched to the label. */
.charts_layout_row_ic { flex:0 0 auto; color:#9aa0a8; font-size:12px; }
.charts_layout_row_name {
	min-width:0; font-size:12.5px; color:#333;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.charts_layout_row_main:hover .charts_layout_row_name { color:#0a66c2; }
.charts_layout_row.is-current .charts_layout_row_name { font-weight:700; }
/* Scope marker after the name — a dim lock on private rows only. */
.charts_layout_scope { flex:0 0 auto; font-size:10.5px; cursor:default; }
.charts_layout_scope.is-private { color:#b0b6be; }
.charts_layout_row_desc {
	font-size:11px; color:#9aa0a8; margin-top:2px; padding-left:20px;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.charts_layout_row_win { flex:0 0 auto; font-size:12px; color:#c8cdd3; cursor:pointer; margin-right:10px; }
.charts_layout_row:hover .charts_layout_row_win { color:#9aa0a8; }
.charts_layout_row_win:hover { color:#0a66c2 !important; }
.charts_layout_row_del { flex:0 0 auto; font-size:12px; color:#c8cdd3; cursor:pointer; }
.charts_layout_row:hover .charts_layout_row_del { color:#9aa0a8; }
.charts_layout_row_del:hover { color:#b3261e !important; }
/* Same control as the trade-script editor's assistant toggle — and the same
   neutral-grey .active fill (#5a6268), not a blue one, so the two toggles read
   as the same kind of control across the app. */
/* Detach + side-panel toggle: borderless icon buttons at the end of the bar,
   sharing one box so the pair reads as a row of view controls. */
.charts_win_btn,
.charts_right_toggle {
	flex:0 0 auto; width:28px; height:28px; border-radius:4px;
	display:flex; align-items:center; justify-content:center;
	color:#555; cursor:pointer;
	transition:background-color 0.12s ease, color 0.12s ease;
}
.charts_win_btn:hover { background:#ECE9E2; color:#333; }
.charts_right_toggle:hover { background:#ECE9E2; color:#333; }
.charts_right_toggle.active { background:#5a6268; color:#fff; }

/* ---- chart grid ------------------------------------------------ */
/* Auto layout by count. A CSS grid rather than nested w2layouts: four
   panels' worth of splitters is a lot of chrome for a screen whose
   content is the pictures, and the grid reflows on its own. */
.charts_grid {
	display:grid; gap:8px; padding:8px; box-sizing:border-box;
	width:100%; height:100%; background:#f4f5f7;
	/* The follower is absolutely placed against this box. */
	position:relative;
}

/* ---- pointer styles ---------------------------------------------------- */
/* What the mouse looks like over a chart — a property of the surface, so it
   is CSS on the grid rather than anything the chart option knows about.
   `!important` because ECharts sets an inline cursor on its own canvas as
   part of its interaction handling, and an inline style outranks a class. */
.charts-cur-cross .charts_cell_canvas,
.charts-cur-cross .charts_cell_canvas canvas { cursor:crosshair !important; }
.charts-cur-arrow .charts_cell_canvas,
.charts-cur-arrow .charts_cell_canvas canvas { cursor:default !important; }
/* Dot and Demonstration draw their OWN mark, so the system cursor goes away
   entirely — two pointers on screen is worse than either alone. */
.charts-cur-dot  .charts_cell_canvas,
.charts-cur-dot  .charts_cell_canvas canvas,
.charts-cur-demo .charts_cell_canvas,
.charts-cur-demo .charts_cell_canvas canvas { cursor:none !important; }

/* The follower. Centred on the pointer and inert — it must never eat a click
   or a hover meant for the chart underneath it. */
.charts_ptr {
	position:absolute; pointer-events:none; z-index:6;
	transform:translate(-50%, -50%); border-radius:50%;
}
.charts_ptr.is-dot {
	width:7px; height:7px; background:#2F9EEE;
	box-shadow:0 0 0 1.5px rgba(255,255,255,.9);
}
/* Blue, and soft enough to read over candles rather than hide them. Sized for
   a shared screen: the point is that a viewer can follow it. */
.charts_ptr.is-demo {
	width:44px; height:44px;
	background:radial-gradient(circle,
		rgba(47,158,238,.34) 0%, rgba(47,158,238,.20) 55%, rgba(47,158,238,0) 72%);
	border:1px solid rgba(47,158,238,.55);
}
body.appbuilder-dark .charts_ptr.is-dot {
	box-shadow:0 0 0 1.5px rgba(0,0,0,.65);
}
body.appbuilder-dark .charts_ptr.is-demo {
	background:radial-gradient(circle,
		rgba(90,180,255,.36) 0%, rgba(90,180,255,.22) 55%, rgba(90,180,255,0) 72%);
	border-color:rgba(90,180,255,.6);
}
.charts_grid.is-1 { grid-template-columns:1fr;             grid-template-rows:1fr; }
.charts_grid.is-2 { grid-template-columns:1fr 1fr;         grid-template-rows:1fr; }
.charts_grid.is-3 { grid-template-columns:repeat(3, 1fr);  grid-template-rows:1fr; }
.charts_grid.is-4 { grid-template-columns:1fr 1fr;         grid-template-rows:1fr 1fr; }
.charts_grid.is-empty { display:flex; align-items:center; justify-content:center; }

.charts_cell {
	display:flex; flex-direction:column; min-width:0; min-height:0;
	background:#fff; border:1px solid #e2e2e2; border-radius:5px;
	overflow:hidden;
}
/* The chart the drawing rail acts on. Applied ONLY when more than one chart
   is on screen — with a single cell there is nothing to disambiguate, and a
   ring that is always on says nothing.
   `outline`, deliberately, for two reasons an inset shadow plus a border
   colour got wrong:
     * Outlines are painted in a FINAL pass, above every descendant. An inset
       shadow sits on the element's own background layer, so the header —
       which carries its own full-width background — painted straight over it
       and the ring stopped dead at the header.
     * One declaration, one colour, no border override. The dark theme's
       `body.appbuilder-dark .charts_cell` rule is (0,2,1) against this
       selector's (0,2,0), so it outranked a `border-color` here and won the
       blue back — which is why dark drew 1px where light drew 2px.
   Offset -1px keeps it inside the border box: nothing reflows when focus
   moves between cells, and nothing can be clipped by the grid gap. */
.charts_cell.is-active {
	outline:2px solid #2F9EEE;
	outline-offset:-1px;
}
.charts_cell.is-active .charts_cell_head { background:#eef6fd; }
.charts_cell.is-active .charts_cell_sym  { color:#1a5c9c; }

/* ---- chart cursor ----------------------------------------------- */
/* A crosshair across the whole plot, drawings included — you are still
   reading a price when the pointer is over one.
   ECharts 6 lays a `cursor:grab` rect over the plot area (that is the flat
   hand you get on an untouched chart), and zrender writes the cursor INLINE —
   not on the host we put the class on, but on its own viewport element inside
   it, the one its DOM handler is bound to. Our value therefore only reached
   that element by INHERITANCE, and any declaration on an element beats an
   inherited one, so the grab always won and the crosshair never showed.
   Hence: `!important` (which does outrank an inline declaration) AND applied
   to the viewport/canvas as well as the host. `:not(.chartdraw_bar)` keeps it
   off the floating toolbar, which is a child of the same host and sets its own
   arrow. The class is only present while the pointer is inside the plot, so
   the toolbox icons and the zoom slider keep the cursors zrender gives them. */
.chartdraw_cur_cross,
.chartdraw_cur_cross canvas,
.chartdraw_cur_cross > div:not(.chartdraw_bar) { cursor:crosshair !important; }
/* A hand over a drawing — it is something you can pick up, and saying so is
   what tells you a shape is grabbable before you press. Same three-selector
   shape, for the same cascade reason. */
.chartdraw_cur_hand,
.chartdraw_cur_hand canvas,
.chartdraw_cur_hand > div:not(.chartdraw_bar) { cursor:pointer !important; }

/* ---- selected-drawing toolbar ----------------------------------- */
/* Floats over the chart, pinned above whatever is selected. Lives inside the
   chart host, so it is positioned against that host's own box. */
.chartdraw_bar {
	position:absolute; z-index:6;
	display:flex; align-items:center; gap:2px;
	padding:3px; box-sizing:border-box;
	background:#fff; border:1px solid #dcdcdc; border-radius:6px;
	box-shadow:0 2px 10px rgba(0,0,0,.14);
	font-family:OpenSans;
	/* An ordinary arrow over the panel chrome: this is a toolbar, not part of
	   the chart surface. A declaration on the element beats the host's
	   inherited crosshair, so the !important above needs no exception. */
	cursor:default;
}
.chartdraw_btn {
	display:flex; align-items:center; justify-content:center;
	width:26px; height:24px; flex:0 0 auto;
	border:0; border-radius:4px; background:transparent;
	color:#6b7280; font-size:12px; cursor:pointer; padding:0;
}
.chartdraw_btn:hover { background:#f0f4f9; color:#1a5c9c; }
.chartdraw_btn.is-danger:hover { background:#fdecea; color:#b3261e; }
.chartdraw_num { font-size:11.5px; font-weight:600; font-family:OpenSans; }
.chartdraw_gap { width:1px; height:16px; background:#ececec; margin:0 2px; flex:0 0 auto; }
/* A filled chip for a colour, a ring for a frame colour, a bar for a width —
   each control previews the thing it sets rather than naming it. */
.chartdraw_sw {
	display:block; width:14px; height:14px; border-radius:3px;
	border:1px solid rgba(0,0,0,.25);
}
/* background-COLOR, not the `background` shorthand: the shorthand resets
   background-image too, which wiped the "none" marking off the chip below and
   left it looking like an empty square. */
.chartdraw_sw.is-ring { background-color:transparent; border-width:2px; border-radius:3px; }
/* "No colour" is the only state a swatch cannot show by being a colour, so it
   is marked instead — a crossed-out chip for a fill... */
.chartdraw_sw.is-none, .chartdraw_cell.is-none {
	background-image:linear-gradient(45deg, transparent 44%, #d33 44%, #d33 56%, transparent 56%);
	border-color:#bbb;
}
/* ...and a DOTTED ring for a frame, which is what "no border" looks like
   everywhere else. A slash would read as "disabled" rather than "off". */
.chartdraw_sw.is-ring.is-none {
	background-image:none; border-style:dotted; border-color:#9aa0a8;
}
.chartdraw_wd { display:block; width:16px; background:currentColor; border-radius:1px; }

.chartdraw_pop {
	position:absolute; z-index:7; min-width:34px;
	padding:4px; box-sizing:border-box;
	background:#fff; border:1px solid #dcdcdc; border-radius:6px;
	box-shadow:0 4px 14px rgba(0,0,0,.18);
	cursor:default;
}
.chartdraw_pop_row {
	display:flex; align-items:center; justify-content:center;
	width:100%; min-width:44px; height:22px;
	border:0; border-radius:3px; background:transparent;
	color:#6b7280; cursor:pointer; padding:0 6px;
}
.chartdraw_pop_row:hover { background:#f0f4f9; color:#1a5c9c; }
.chartdraw_grid { display:grid; grid-template-columns:repeat(6, 18px); gap:4px; }
.chartdraw_cell {
	width:18px; height:18px; padding:0; cursor:pointer;
	border:1px solid rgba(0,0,0,.22); border-radius:3px;
}
.chartdraw_cell:hover { outline:2px solid #2F9EEE; outline-offset:1px; }

/* Note editor — a real textarea, because notes run to more than one line. */
.charts_note_wrap { width:100%; padding:12px; box-sizing:border-box; }
.charts_note_ta {
	width:100%; height:130px; box-sizing:border-box; resize:vertical;
	padding:8px; border:1px solid #dcdcdc; border-radius:4px;
	font-family:OpenSans; font-size:13px; color:#333;
}

/* ---- drawing rail ---------------------------------------------- */
.charts_rail {
	position:relative;
	height:100%; box-sizing:border-box; overflow:hidden;
	background:#fafafa; border-right:1px solid #e2e2e2;
}
/* The tools scroll, but WITHOUT a scrollbar: a gutter down a 46px rail is
   more chrome than the icons it scrolls. Paging arrows take its place. */
.charts_rail_scroll {
	display:flex; flex-direction:column; align-items:center; gap:1px;
	height:100%; padding:6px 0; box-sizing:border-box;
	overflow-y:auto; overflow-x:hidden;
	scrollbar-width:none; -ms-overflow-style:none;
}
.charts_rail_scroll::-webkit-scrollbar { width:0; height:0; display:none; }
/* Shown only when the rail actually overflows AND the pointer is on it —
   an arrow that cannot scroll anything is just a smaller scrollbar. The
   gradient lets the icons fade under it instead of being cut off. */
.charts_rail_arrow {
	position:absolute; left:0; right:0; height:16px; z-index:2;
	display:none; align-items:center; justify-content:center;
	cursor:pointer; color:#6b7280; font-size:11px;
}
.charts_rail_arrow.is-up {
	top:0; background:linear-gradient(to bottom, #fafafa 60%, rgba(250,250,250,0));
}
.charts_rail_arrow.is-down {
	bottom:0; background:linear-gradient(to top, #fafafa 60%, rgba(250,250,250,0));
}
.charts_rail_arrow:hover { color:#1a5c9c; }
.charts_rail.can-scroll:hover .charts_rail_arrow { display:flex; }
.charts_rail.at-top  .charts_rail_arrow.is-up   { display:none; }
.charts_rail.at-end  .charts_rail_arrow.is-down { display:none; }
/* Sized to sit alongside the app's own left sidebar rather than beside it:
   those icons are large and heavy, and a rail of thin 15px glyphs next to
   them read as a different, lesser control. The SVGs carry matching stroke
   weights (see Builder_Charts.ToolIcon). */
.charts_rail_btn {
	display:flex; align-items:center; justify-content:center;
	width:36px; height:32px; flex:0 0 auto;
	border-radius:5px; cursor:pointer; color:#6b7280; font-size:16px;
}
.charts_rail_btn:hover { background:#f0f4f9; color:#1a5c9c; }
/* The armed tool. Filled rather than outlined: this is a mode you are IN,
   and it has to be readable at a glance from across the chart. */
.charts_rail_btn.is-on { background:#2F9EEE; color:#fff; }
.charts_rail_btn.is-on:hover { background:#1a86d9; color:#fff; }
.charts_rail_btn.is-danger:hover { background:#fdecea; color:#b3261e; }
.charts_rail_sep {
	width:24px; height:1px; flex:0 0 auto; margin:3px 0; background:#e2e2e2;
}
/* Magnet and lock are STATES, not modes: they stay on across tools. Outlined
   rather than filled so they never compete with the armed tool for attention. */
.charts_rail_btn.is-on.charts_rail_state {
	background:transparent; color:#1a5c9c;
	box-shadow:inset 0 0 0 1.5px #2F9EEE;
}
.charts_rail_btn.is-on.charts_rail_state:hover { background:#f0f4f9; color:#1a5c9c; }
/* The sticker button shows the glyph it will place, so the rail says which
   one is loaded without opening the menu. */
.charts_rail_emoji { font-size:18px; line-height:1; }
.charts_rail_btn.is-on .charts_rail_emoji { filter:drop-shadow(0 0 1px rgba(0,0,0,.35)); }
.w2ui-menu .charts_sticker_ch { display:inline-block; width:22px; font-size:14px; }

/* A rail slot holding several tools.

   The caret says there is a menu behind the button WITHOUT spending a second
   slot on it — the whole point of the group is that the rail got shorter. It
   points RIGHT because that is where the menu opens, beside the rail rather
   than under it. */
/* On the button itself rather than on the group class: the sticker button
   carries a caret too, and it is not a group. */
.charts_rail_btn { position:relative; }
.charts_rail_more {
	position:absolute; right:0; top:0; bottom:0; width:11px;
	display:flex; align-items:center; justify-content:flex-end;
	padding-right:2px; cursor:pointer;
}
/* The sticker's caret MARKS the button; it does not divide it. The whole
   button opens that menu, so the caret must not intercept the click. */
.charts_rail_more.is-passive { pointer-events:none; }
.charts_rail_more::after {
	content:''; width:0; height:0;
	border-top:3.5px solid transparent;
	border-bottom:3.5px solid transparent;
	border-left:4px solid currentColor;
	opacity:.45;
}
.charts_rail_btn:hover .charts_rail_more::after { opacity:.9; }
.charts_rail_btn.is-on .charts_rail_more::after { opacity:.85; }
/* The caret is its own target, so it earns its own hover — otherwise there is
   nothing to tell you the two halves of the button do different things. */
.charts_rail_more:hover::after { opacity:1; border-left-width:5px; }

/* Menu rows carry the tool's own glyph, so the picker reads the same way the
   rail did before it collapsed. */
.w2ui-menu .charts_tool_ico {
	display:inline-flex; align-items:center; justify-content:center;
	width:24px; vertical-align:middle; color:#6b7280;
}
.w2ui-menu .charts_tool_ico svg { width:15px; height:15px; }
.charts_cell_head {
	display:flex; align-items:center; gap:7px; flex:0 0 auto;
	height:34px; padding:0 10px; box-sizing:border-box;
	border-bottom:1px solid #eee; background:#fafafa;
	font-family:OpenSans;
}
/* The instrument mark, left of the label. Smaller than the grid's 28px — a
   title-bar glyph, not a row icon. */
.charts_cell_head .screener_icon { width:22px; height:22px; flex:0 0 auto; }
.charts_cell_head .screener_icon_img,
.charts_cell_head .screener_icon_mono { width:22px; height:22px; font-size:10px; }
.charts_cell_head .screener_icon_img  { padding:3px; }
.charts_cell_sym  { font-size:12px; font-weight:700; color:#333; }
.charts_cell_name {
	font-size:11px; color:#9aa0a8; min-width:0;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.charts_cell_warn { font-size:11px; color:#c77700; cursor:default; }
.charts_cell_spacer { flex:1 1 auto; }
/* New-alert dialog: a level and what to watch for. Two rows on one column
   so the label/control alignment matches the settings popover. */
.charts_alertnew { padding:14px 16px; font-family:OpenSans; }
.charts_alertnew_row {
	display:flex; align-items:center; gap:12px; padding:5px 0;
	font-size:12px; color:#333;
}
.charts_alertnew_row > label { flex:0 0 88px; }
.charts_alertnew_lvl {
	flex:1 1 auto; height:28px; padding:0 8px; box-sizing:border-box;
	border:1px solid #d7dde3; border-radius:3px; background:#fff; color:#333;
	font-family:OpenSans; font-size:13px;
}
/* The trigger types differ in a way the name alone does not settle, so the
   chosen one explains itself rather than leaving it to be discovered. */
.charts_alertnew_hint { margin:6px 0 0 100px; font-size:11px; color:#8b929a; }
/* Alerts panel — the list of what is being watched, and the only place a fired
   alert can be brought back. A column so the list scrolls under a fixed header,
   matching the palette and the Scripts tab. */
.charts_alerts {
	display:flex; flex-direction:column; height:100%; min-height:0;
	font-family:OpenSans;
}
.charts_alerts_head {
	flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
	padding:8px 12px; border-bottom:1px solid #eee;
	font-size:11px; font-weight:600; color:#6b727a;
}
.charts_alerts_list { flex:1 1 auto; min-height:0; overflow-y:auto; padding:4px 8px 10px; }
/* Marks a conversation that belongs to a chart, in the Recent strip and the
   All-threads list. Quiet by design — it is a provenance note, not a status. */
.thread-kind-chip {
	display:inline-block; margin-left:6px; padding:0 6px; border-radius:9px;
	font:10px OpenSans, sans-serif; font-weight:600; letter-spacing:.03em;
	text-transform:uppercase; vertical-align:middle;
	background:#eef2f7; color:#5b6470; border:1px solid #dde3ea;
}
body.appbuilder-dark .thread-kind-chip {
	background:#252b34; color:#98a0aa; border-color:#333b45;
}

/* A chart alert offer replayed in the Threads view: the record of what was
   proposed, without the button — this view has no chart to arm against. */
.thread_propcard {
	border:1px solid #e2e6ea; border-left:3px solid #8e8ee0; border-radius:6px;
	padding:9px 12px; margin:2px 0; background:#fbfcfd;
	font:12.5px OpenSans, sans-serif; color:#3c434a;
}
.thread_propcard_head { font-weight:600; font-size:11.5px; color:#5b6470; margin-bottom:5px; }
.thread_propcard_row  { padding:2px 0; }
.thread_propcard_lvl  { font-weight:600; }
.thread_propcard_dir  { color:#6b7280; }
.thread_propcard_note { color:#6b7280; font-size:12px; margin-top:1px; }
.thread_propcard_foot { margin-top:6px; font-size:11.5px; color:#8a929b; font-style:italic; }
/* Armed: the offer was accepted. Green rail + a tick, matching the docked
   card, so the two surfaces agree at a glance about the same alert. */
.thread_propcard.is-armed { border-left-color:#1f7a43; }
.thread_propcard.is-armed .thread_propcard_foot { color:#1f7a43; font-style:normal; }
.thread_propcard.is-armed .thread_propcard_row::after {
	content:"\f00c"; font-family:FontAwesome; color:#1f7a43; font-size:11px; margin-left:6px;
}
body.appbuilder-dark .thread_propcard.is-armed { border-left-color:#7fc79b; }
body.appbuilder-dark .thread_propcard.is-armed .thread_propcard_foot,
body.appbuilder-dark .thread_propcard.is-armed .thread_propcard_row::after { color:#7fc79b; }
body.appbuilder-dark .thread_propcard {
	background:#20242b; border-color:#2f3641; border-left-color:#8e8ee0; color:#c9d1d9;
}
body.appbuilder-dark .thread_propcard_head { color:#98a0aa; }
body.appbuilder-dark .thread_propcard_dir,
body.appbuilder-dark .thread_propcard_note,
body.appbuilder-dark .thread_propcard_foot { color:#8a929b; }

/* The divider between alerts on the charted instruments and alerts still
   watching something that is not on screen. A rule with a caption, not a
   heading: the rows below it are the same rows, just not about what you are
   looking at. */
.charts_alerts_sep {
	display:flex; align-items:center; gap:8px;
	margin:12px 0 4px; padding-top:8px; border-top:1px solid #eceff2;
	font-size:10.5px; font-weight:600; letter-spacing:.02em; color:#98a0aa;
	text-transform:uppercase;
}
.charts_alerts_sep > span:first-child { flex:1 1 auto; }
.charts_alerts_sepn {
	flex:0 0 auto; padding:1px 6px; border-radius:9px;
	background:#f1f3f6; color:#6b727a; font-weight:600;
}
body.appbuilder-dark .charts_alerts_sep  { border-top-color:#2a2e34; color:#7f8792; }
body.appbuilder-dark .charts_alerts_sepn { background:#2a2f36; color:#98a0aa; }
/* An alert whose instrument is not on screen. Muted, not hidden: it is still
   armed and still yours to pause or delete, so it stays fully operable — the
   dimming only says "this one is not about what you are looking at". The
   caption alone was too quiet to notice when every alert was off-chart. */
.charts_alert.is-offchart { opacity:.62; }
.charts_alert.is-offchart:hover { opacity:1; }
.charts_alert.is-offchart .charts_alert_sym { font-weight:500; }

/* The "New layout" confirmation — it clears the grid, so it says what goes
   and what deliberately stays. */
.charts_newlayout { padding:14px 16px; font-family:OpenSans; font-size:13px; color:#3c434a; }
.charts_newlayout_lead { font-weight:600; margin-bottom:8px; }
.charts_newlayout_list { margin:0 0 12px; padding-left:20px; }
.charts_newlayout_list li { margin:3px 0; }
.charts_newlayout_keep {
	background:#fdf3e3; border:1px solid #f0dcb8; border-radius:6px;
	padding:9px 11px; font-size:12.5px; line-height:1.5; color:#7a5c14;
}
.charts_newlayout_chat { display:block; margin-top:12px; font-size:12.5px; }
body.appbuilder-dark .charts_newlayout      { color:#c9d1d9; }
body.appbuilder-dark .charts_newlayout_keep { background:#3a3226; border-color:#5a4a2a; color:#e0c284; }
.charts_alert {
	display:flex; align-items:center; gap:8px;
	padding:7px 6px; border-bottom:1px solid #f2f4f6;
}
.charts_alert_main { flex:1 1 auto; min-width:0; }
.charts_alert_head { display:flex; align-items:baseline; gap:8px; }
.charts_alert_sym { font-size:12px; font-weight:700; color:#333; }
.charts_alert_lvl { font-size:12px; color:#26a69a; font-weight:600; }
.charts_alert_note {
	font-size:11px; color:#7b828b; margin-top:1px;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.charts_alert_state { font-size:10px; color:#9aa0a8; margin-top:2px; }
/* Fired and paused both read as "not watching", but differently: one has done
   its job, the other was switched off. */
.charts_alert.is-fired .charts_alert_lvl  { color:#9aa0a8; }
.charts_alert.is-fired .charts_alert_state { color:#2e7d32; }
.charts_alert.is-paused { opacity:.6; }
.charts_alert_btn { flex:0 0 auto; font-size:11px; color:#9aa0a8; cursor:pointer; }
.charts_alert_btn:hover { color:#1a5c9c; }
.charts_alert_btn.fa-times:hover { color:#b3261e; }
.charts_alerts_empty {
	flex:1 1 auto; display:flex; flex-direction:column; align-items:center;
	justify-content:center; gap:6px; padding:24px; text-align:center;
	font-size:12px; color:#9aa0a8;
}
.charts_alerts_empty > .fa { font-size:26px; color:#cbd2d9; }
.charts_alerts_hint { font-size:11px; color:#aab2bb; max-width:220px; line-height:1.4; }

/* What a mark means, on hover. Positioned inside the cell, which is why the
   canvas is a positioning context. Narrow on purpose — it explains one
   glyph, and a wide card would cover the bars it is describing. */
.charts_markcard {
	position:absolute; z-index:6; display:none; max-width:250px;
	padding:7px 9px; border-radius:4px; pointer-events:none;
	border:1px solid #e2e5e8; background:#fff; box-shadow:0 3px 10px rgba(0,0,0,.10);
	font-family:OpenSans; font-size:11px; color:#5b626a; line-height:1.45;
}
.charts_markcard b { display:block; font-size:11.5px; color:#2c3138; margin-bottom:2px; }
.charts_cell_canvas { position:relative; }
/* The chart's clock. Quieter than the feed badge and never coloured: it is
   a standing fact about the axis, not a state that changes. Sits beside the
   feed chip so the two facts the picture cannot carry are in one place. */
.charts_tz {
	flex:0 0 auto; padding:0 5px; border-radius:3px;
	border:1px solid #e6e8ea; background:#f7f8f9; color:#8b929a;
	font-size:9px; line-height:14px; white-space:nowrap; cursor:default;
}
/* Feed state. Deliberately quiet when DELAYED and only coloured when live:
   the badge exists to stop a delayed chart implying real-time, not to
   decorate. Uppercase and small — a label, not a button. */
.charts_feed {
	flex:0 0 auto; padding:0 5px; border-radius:3px;
	border:1px solid #e2e5e8; background:#f5f6f7; color:#9aa0a8;
	font-size:8.5px; font-weight:700; letter-spacing:.5px; line-height:14px;
	cursor:default;
}
.charts_feed.is-live { border-color:#bfe3d4; background:#eaf7f1; color:#1b7a54; }
/* Alert bell. Muted like the rest of the cell chrome until something is
   actually armed, then it takes the alert colour — the point of the icon is
   to answer "is anything watching this?" without opening anything. */
.charts_cell_bell { font-size:11px; color:#9aa0a8; cursor:pointer; padding:2px 4px; border-radius:3px; }
.charts_cell_bell:hover { color:#1a5c9c; }
/* Armed is an EMOJI bell, so it brings its own colour — the amber tint that
   used to carry the state is gone with the outline glyph it was tinting.
   Sized down and baseline-nudged: an emoji renders larger than the 11px
   FontAwesome chrome beside it and would otherwise sit proud of the row. */
.charts_cell_bell.is-on {
	/* 13px, not the 11px of the FontAwesome bell beside it: an emoji is drawn
	   with padding inside its em box, so it renders visibly smaller than an
	   icon-font glyph set to the same size. Matched by eye against the idle
	   bell — the armed state should read as bigger, never as shrunken. */
	font-size:13px; line-height:1; vertical-align:middle;
	filter:saturate(0.9);
}
/* Maximize sits left of the close, in the same muted weight: both are cell
   chrome, and only one of them is destructive. */
.charts_cell_max  { font-size:11px; color:#9aa0a8; cursor:pointer; padding:2px 4px; border-radius:3px; }
.charts_cell_max:hover { color:#1a5c9c; }
/* The order ticket (OMS Ship 4), beside the bell — same quiet grey, same hover. */
/* THE BUY / SELL chips (Builder_OrderTicket.ChipsHTML) — the one way a symbol
   offers trading: the chart cell header, the instrument header, the screener
   side panel. The order ticket's own side colours (.ot_side), at header size,
   so the chip and the ticket it opens agree. */
.tr_chip {
	display:inline-block; cursor:pointer; margin-left:2px; padding:1px 6px; border-radius:3px;
	font-size:9.5px; font-weight:700; letter-spacing:.3px; line-height:14px;
	border:1px solid transparent; font-family:'Open Sans', sans-serif; vertical-align:middle;
}
.tr_chip.is-buy  { background:#e6f4ec; border-color:#a5d5bb; color:#116b3a; }
.tr_chip.is-sell { background:#fbeaea; border-color:#f0b4ae; color:#b3261e; }
.tr_chip.is-buy:hover  { background:#d3ecdd; }
.tr_chip.is-sell:hover { background:#f6d9d6; }
body.appbuilder-dark .tr_chip.is-buy  { background:#22392c; border-color:#2c5a3c; color:#7ddb9a; }
body.appbuilder-dark .tr_chip.is-sell { background:#3a2626; border-color:#6b3a3a; color:#ef9a9a; }
body.appbuilder-dark .tr_chip.is-buy:hover  { background:#2a4735; }
body.appbuilder-dark .tr_chip.is-sell:hover { background:#4a2e2e; }
/* Where the pair sits: inline among the instrument header's action buttons
   (spaced like them), and as a flex item before the screener panel's close
   button, whose 40px right padding already keeps it clear. */
.instr_trade           { display:inline-block; margin-right:6px; vertical-align:middle; }
.screener_detail_trade { flex:0 0 auto; display:flex; gap:2px; }
.charts_cell_x    { font-size:11px; color:#9aa0a8; cursor:pointer; }
/* Per-cell interval — the topbar pickbtn shrunk to header scale. Resting
   label = the toolbar interval; an override colours up so a cell showing
   different bars than its neighbours SAYS so. */
.charts_cell_tf { flex:0 0 auto; }
.charts_cell_tf .wf-pickbtn {
	height:20px; min-height:20px; padding:0 5px; font-size:10px;
	border-radius:3px; background:transparent; border:1px solid transparent;
	color:#9aa0a8;
}
.charts_cell_tf .wf-pickbtn:hover { border-color:#d0d7de; color:#1a5c9c; background:#fff; }
.charts_cell_tf .wf-pickbtn-caret { font-size:9px; margin-left:3px; }
.charts_cell_tf.has-override .wf-pickbtn {
	color:#1a5c9c; font-weight:700; border-color:#c4d9ec; background:#eef5fb;
}
body.appbuilder-dark .charts_cell_tf .wf-pickbtn { color:#8a929b; }
body.appbuilder-dark .charts_cell_tf .wf-pickbtn:hover {
	border-color:#3a4048; color:#7fb3e0; background:#23272d;
}
body.appbuilder-dark .charts_cell_tf.has-override .wf-pickbtn {
	color:#7fb3e0; border-color:#2f4a63; background:#1d2b38;
}
/* Applied-script chips — what this chart is showing on top of price, and the
   controls for it. Sits between the header and the canvas, wrapping rather
   than scrolling: the list is short by nature and a hidden chip is a control
   nobody can find. `flex:0 0 auto` keeps it out of the canvas' 1fr share. */
.charts_chips {
	display:flex; flex-wrap:wrap; gap:4px; flex:0 0 auto;
	padding:4px 8px; font-family:OpenSans;
}
.charts_chip {
	display:inline-flex; align-items:center; gap:5px;
	max-width:100%; padding:1px 6px; border-radius:10px;
	border:1px solid #dbe6f0; background:#f3f8fd; color:#2c3e50;
	font-size:10px; line-height:16px;
}
.charts_chip_name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Repeats the shape the chart is drawing, so stacked pattern indicators can
   be told apart at a glance. Slightly tighter than the name it precedes. */
.charts_chip_glyph { flex:0 0 auto; font-size:9px; letter-spacing:-1px; opacity:.85; }
/* A hidden indicator stays listed — that IS the affordance to bring it back —
   but reads as switched off rather than merely quiet. */
.charts_chip.is-off { opacity:.55; }
.charts_chip.is-off .charts_chip_name { text-decoration:line-through; }
/* The strategy chip is the odd one out (one per chart, draws trades), so it
   is coloured apart from the stackable indicators. */
.charts_chip.is-strategy { border-color:#e3d6b8; background:#fdf8ec; color:#6b5628; }
.charts_chip_btn { font-size:10px; color:#8a97a5; cursor:pointer; }
.charts_chip_btn:hover { color:#2F9EEE; }
.charts_chip_btn.fa-times:hover { color:#b3261e; }
/* The indicator palette. A two-column dialog: sections down the left like a
   library's shelves, search + list on the right. The explanation for each
   entry is rendered IN the list rather than in a tooltip — a tooltip hides it
   from the one person who needs it, the reader browsing to find out what
   these things are. */
.charts_lib {
	display:flex; height:100%; min-height:0;
	box-sizing:border-box; font-family:OpenSans;
}
.charts_lib_nav {
	flex:0 0 176px; min-height:0; overflow-y:auto;
	padding:10px 8px 12px 12px; box-sizing:border-box;
	border-right:1px solid #e8ebee;
}
.charts_lib_navitem {
	display:flex; align-items:center; gap:8px; padding:5px 8px;
	border-radius:4px; cursor:pointer; font-size:11.5px; color:#4a5158;
}
.charts_lib_navitem:hover { background:#f2f6fa; }
.charts_lib_navitem.is-on { background:#e8f2fc; color:#1a5c9c; font-weight:600; }
.charts_lib_navitem > span:first-child {
	flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* The count is the point of the sidebar during a search: it says where the
   matches are before you go clicking through sections to find out. */
.charts_lib_navn { flex:0 0 auto; font-size:10px; color:#9aa0a8; }
.charts_lib_navitem.is-on .charts_lib_navn { color:#1a5c9c; }

.charts_lib_right {
	flex:1 1 auto; min-width:0; min-height:0;
	display:flex; flex-direction:column;
	padding:10px 14px 12px; box-sizing:border-box;
}
.charts_lib_search {
	flex:0 0 auto; height:30px; padding:0 10px; box-sizing:border-box;
	border:1px solid #d7dde3; border-radius:4px; background:#fff; color:#333;
	font-family:OpenSans; font-size:12px; margin-bottom:8px;
}
.charts_lib_list { flex:1 1 auto; min-height:0; overflow-y:auto; }
.charts_lib_group {
	font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.4px;
	color:#9aa0a8; margin:12px 0 4px; position:sticky; top:0; background:#fff;
}
/* A row is now a BLOCK, not a line: name + Add on top, then the purpose, then
   the explanation. */
.charts_lib_row { padding:8px 2px 10px; border-bottom:1px solid #f0f2f4; }
/* The drawing sits inside the explanation, picture left and words right:
   one is an illustration of the other, so they read as a single thought. */
.charts_lib_pic {
	flex:0 0 auto; display:flex; align-items:center; justify-content:center;
	width:74px; color:#9aa0a8;
}
.charts_lib_head { display:flex; align-items:center; gap:8px; }
.charts_lib_name { flex:1 1 auto; min-width:0; font-size:12.5px; font-weight:600; color:#333; }
/* The purpose line is the whole reason the palette is browsable — it wraps
   rather than truncating, because a half-sentence teaches nothing. */
.charts_lib_purpose { font-size:11.5px; color:#6b727a; line-height:1.4; margin-top:3px; }
.charts_lib_how {
	display:flex; gap:10px; align-items:center; margin-top:6px; padding:7px 9px;
	background:#f7f9fb; border:1px solid #eceff2; border-left:2px solid #cfdae6;
	border-radius:3px; font-size:11px; color:#71787f; line-height:1.5;
}
.charts_lib_how > .fa { flex:0 0 auto; margin-top:1px; color:#9fb3c6; font-size:11px; }
.charts_lib_tag {
	margin-left:6px; padding:0 5px; border-radius:8px;
	background:#fdf8ec; border:1px solid #e3d6b8; color:#6b5628;
	font-size:9px; font-weight:600; text-transform:uppercase;
}
.charts_lib_on {
	flex:0 0 auto; display:inline-flex; align-items:center; gap:2px;
	padding:1px 7px; border-radius:9px;
	background:#eaf6ee; border:1px solid #bfe0cb; color:#1f7a43;
	font-size:10px; font-weight:600; white-space:nowrap;
}
.charts_lib_add { flex:0 0 auto; }
.charts_lib_empty { padding:24px 0; text-align:center; font-size:12px; color:#9aa0a8; }

/* One applied script's parameters. Label left, control right on a fixed
   column so a list of mixed types still reads as one aligned form. */
.charts_indset { padding:4px 14px 10px; font-family:OpenSans; }
.charts_indset_group {
	font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.4px;
	color:#9aa0a8; margin:12px 0 4px;
}
.charts_indset_row {
	display:flex; align-items:center; gap:10px; padding:3px 0;
	font-size:12px; color:#333;
}
.charts_indset_row > label { flex:1 1 auto; min-width:0; }
.charts_indset_row > input[type=text],
.charts_indset_row > input[type=number],
.charts_indset_row > select {
	flex:0 0 150px; width:150px; box-sizing:border-box;
	height:24px; padding:0 6px; font-family:OpenSans; font-size:12px;
	border:1px solid #d7dde3; border-radius:3px; background:#fff; color:#333;
}
.charts_indset_row > input[type=checkbox] { flex:0 0 auto; margin:0; }
/* min-height:0 on a flex child is what allows it to be SHORTER than its
   content; without it the canvas grows the cell and the grid row stops
   honouring 1fr. */
.charts_cell_canvas { flex:1 1 auto; min-height:0; width:100%; }
.charts_cell_msg {
	flex:1 1 auto; display:flex; align-items:center; justify-content:center;
	font-family:OpenSans; font-size:12px; color:#6b7280; padding:12px;
	text-align:center;
}
.charts_cell_msg.is-error { color:#b3261e; }

/* A chart whose window holds no bars. Deliberately NOT the red is-error
   treatment: an intraday range that opens before the market does is a correct
   answer, not a failure, and colouring it as one trains you to ignore the
   colour. Self-contained (own height, own centring) because the renderer that
   writes it also serves dashboard widgets and thread cards, not just a
   flex charts cell. */
.chart_nodata {
	height:100%; min-height:80px;
	display:flex; flex-direction:column;
	align-items:center; justify-content:center; gap:4px;
	font-family:OpenSans; text-align:center; padding:12px;
}
.chart_nodata_t   { font-size:12.5px; color:#6b7280; }
.chart_nodata_why { font-size:11px;   color:#9aa1a9; }
body.appbuilder-dark .chart_nodata_t   { color:#aab2bb; }
body.appbuilder-dark .chart_nodata_why { color:#8d949c; }

.charts_empty {
	display:flex; flex-direction:column; align-items:center; gap:8px;
	font-family:OpenSans; text-align:center; padding:24px;
}
.charts_empty > .fa { font-size:34px; color:#c8cdd3; margin-bottom:4px; }
.charts_empty_t { font-size:14px; font-weight:600; color:#333; }
.charts_empty_s { font-size:12px; color:#6b7280; max-width:340px; line-height:1.5; }

/* ---- right panel ----------------------------------------------- */
.charts_right {
	display:flex; flex-direction:column; width:100%; height:100%;
	background:#fff; border-left:1px solid #e2e2e2; font-family:OpenSans;
}
/* The side panel's tab strip is the house w2ui tab bar (.pf_tabbar, see
   _RenderRight) — the strip of its own that lived here is gone. */
.charts_right_body {
	flex:1 1 auto; min-height:0; overflow:hidden;
	display:flex; flex-direction:column;
}

/* ---- Pine tab --------------------------------------------------- */
.charts_pine { display:flex; flex-direction:column; width:100%; height:100%; }
.charts_pine_bar {
	display:flex; align-items:center; gap:6px; flex:0 0 auto;
	padding:6px 8px; border-bottom:1px solid #eee;
}
/* The Scripts bar's actions use the watchlist row's icon treatment
   (.charts_wl_icon) unchanged — same size, same grey, same hover. An accent
   on Add was tried and removed: fa-plus-circle is a FILLED disc, so colouring
   it read as a button with its own background sitting among two bare glyphs. */
/* A flex ROW: CodeMirror takes the space, the minimap rides the right edge —
   the same arrangement as the Lab editor's body_inner, which is what lets the
   two share one canvas implementation. CodeMirror is inserted straight after
   the textarea, so it lands before the canvas in document (= screen) order. */
.charts_pine_editor {
	flex:1 1 auto; min-height:0; position:relative; overflow:hidden;
	display:flex; align-items:stretch;
}
/* min-width:0 lets the editor be NARROWER than its longest line; without it a
   wide script pushes the minimap off the panel. */
.charts_pine_editor .CodeMirror { flex:1 1 auto; min-width:0; height:100%; font-size:12px; }
/* A third narrower than the Lab's 62px. This editor lives in a ~400px side
   panel, where the Lab's has a full window: the same canvas costs a much
   larger share of the code area here, and the map stays readable at 41px
   because it scales to its own width (see _DrawMinimap). */
.charts_pine_editor .ts_minimap { flex:0 0 41px; width:41px; }
.charts-pine-editor {
	width:100%; height:100%; box-sizing:border-box; border:0; resize:none;
	font-family:Consolas,'Courier New',monospace; font-size:12px; padding:8px;
}
/* Compile output — collapsed to nothing until Compile writes into it, then a
   capped, scrollable strip carrying the trade-script editor's own result
   blocks (tradescript_results*). :empty is what keeps it invisible with zero
   layout cost the rest of the time. */
.charts_pine_results { flex:0 0 auto; }
.charts_pine_results:empty { display:none; }
.charts_pine_results:not(:empty) {
	max-height:42%; overflow:auto; padding:8px;
	border-top:1px solid #eee; background:#fafafa;
}

/* ---- Chat tab ---------------------------------------------------- */
.charts_chat_host  { width:100%; flex:1 1 auto; min-height:0; overflow:hidden; }
/* The tab body is the flex column the strip and the transcript share. */
.charts_right_body > .charts_chat_ctx { flex:0 0 auto; }
.charts_chat_empty {
	display:flex; flex-direction:column; align-items:center; justify-content:center;
	gap:8px; height:100%; padding:24px; text-align:center;
}
.charts_chat_empty > .fa { font-size:30px; color:#c8cdd3; }

/* ---- Watchlists tab ---------------------------------------------- */
.charts_wl { display:flex; flex-direction:column; width:100%; height:100%; }
.charts_wl_bar {
	display:flex; align-items:center; gap:6px; flex:0 0 auto;
	padding:6px 8px; border-bottom:1px solid #eee;
}
/* FIXED WIDTH, not the glyph's own. Font Awesome glyphs are not the same
   width — fa-check is narrower than fa-floppy-o, fa-pencil than fa-trash-o —
   and these rows are RIGHT-aligned, so the leftmost icon's position depended
   on the total width of everything to its right. Switching between Scripts and
   Watchlists, whose icon sets differ, made the first icon visibly jump. One
   box per icon means three icons occupy the same run in either panel. */
.charts_wl_icon {
	font-size:14px; color:#6b7280; cursor:pointer;
	display:inline-block; width:16px; text-align:center;
}
.charts_wl_icon:hover { color:#1a5c9c; }
.charts_wl_add { flex:0 0 auto; padding:6px 8px; border-bottom:1px solid #eee; }
/* Description sits directly under +Add instruments — display only; editing is
   the header pencil now. Hidden entirely when empty (rendered conditionally),
   so there is no dead affordance to style. */
.charts_wl_desc {
	flex:0 0 auto; padding:7px 10px; border-bottom:1px solid #eee;
	font-size:11.5px; color:#4b5563; line-height:1.45;
}
.charts_wl_desc_txt  { white-space:pre-wrap; word-break:break-word; }

/* New / Edit watchlist dialog — two stacked fields. */
.charts_wl_dlg { padding:16px 18px; font-family:OpenSans; box-sizing:border-box; }
.charts_wl_dlg label {
	display:block; font-size:11px; color:#6b7280; margin:0 0 4px; font-weight:600;
}
.charts_wl_dlg input,
.charts_wl_dlg textarea {
	width:100%; box-sizing:border-box; margin-bottom:14px;
	font-family:OpenSans; font-size:12.5px;
}
.charts_wl_dlg textarea { resize:vertical; min-height:74px; line-height:1.45; }
/* The last field's 14px bottom margin stacks on the dialog's own 16px bottom
   padding — ~30px of dead space that pushed the body a few px into a scrollbar
   even when it looks like there's room. Drop the trailing margin; the padding
   already provides the bottom gap. */
.charts_wl_dlg > *:last-child { margin-bottom:0; }
.charts_wl_list { flex:1 1 auto; min-height:0; overflow-y:auto; }
.charts_wl_empty { padding:20px; font-size:12px; color:#9aa0a8; text-align:center; line-height:1.5; }
.charts_wl_row {
	display:flex; align-items:center; gap:8px;
	padding:6px 8px; border-bottom:1px solid #f0f0f0;
}
.charts_wl_row:hover { background:#f6f9fd; }
/* Explicit add-to-chart control — clearer than a whole-row click. Dim until
   the row is hovered so a long list stays calm; on direct hover it goes to full
   contrast (black in light, white in dark) — no background pill. */
.charts_wl_add_btn {
	flex:0 0 auto; font-size:12px; color:#c8cdd3; cursor:pointer;
	transition:color 0.12s ease;
}
.charts_wl_row:hover .charts_wl_add_btn { color:#6b7280; }
.charts_wl_add_btn:hover { color:#000 !important; }
.charts_wl_logo { width:22px; height:22px; flex:0 0 auto; border-radius:50%; object-fit:contain; }
.charts_wl_main { flex:1 1 auto; min-width:0; }
.charts_wl_sym  { font-size:11.5px; font-weight:700; color:#333; }
.charts_wl_name {
	font-size:10.5px; color:#9aa0a8;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.charts_wl_nums { flex:0 0 auto; text-align:right; }
.charts_wl_last { font-size:11.5px; font-weight:600; color:#333; }
.charts_wl_chg  { font-size:10.5px; color:#9aa0a8; white-space:nowrap; }
/* Colour is a SECOND signal, never the only one — the number carries an
   explicit +/- sign so direction survives for anyone who cannot tell red
   from green. */
.charts_wl_nums.is-up   .charts_wl_chg { color:#1a7f37; }
.charts_wl_nums.is-down .charts_wl_chg { color:#b3261e; }
.charts_wl_x { flex:0 0 auto; font-size:11px; color:#c8cdd3; cursor:pointer; }
.charts_wl_row:hover .charts_wl_x { color:#9aa0a8; }
.charts_wl_x:hover { color:#b3261e !important; }

/* ---- dark ------------------------------------------------------- */
body.appbuilder-dark .charts_topbar {
	background:var(--bg-alt); border-bottom-color:var(--border);
}
body.appbuilder-dark .charts_volbtn {
	background:var(--bg-alt); border-color:var(--border); color:#c8d0d8;
}
body.appbuilder-dark .charts_volbtn:hover { border-color:#505a64; color:#8ec2ee; }
body.appbuilder-dark .charts_volbtn.is-off { background:#1c1f24; color:#6b727a; }
body.appbuilder-dark .charts_field_box {
	background:var(--bg-input); border-color:var(--border);
}
body.appbuilder-dark .charts_field_box:hover { border-color:var(--border-strong, #505050); }
body.appbuilder-dark .charts_tags::-webkit-scrollbar-thumb { background:#4a4a4a; }
body.appbuilder-dark .charts_field_add { color:#aab2bb; border-left-color:var(--border); }
/* Focus ring must survive hover: the dark :hover rule above this point
   would otherwise revert the border to gray while the box is focused
   (equal specificity, later in the file → hover won), which read as the
   ring flickering between 2px and 1px. Declared HERE — after the hover
   rule — with the :hover combo spelled out, so focused always wins. */
body.appbuilder-dark .charts_field_box:focus-within,
body.appbuilder-dark .charts_field_box:focus-within:hover {
	border-color:#3a86c8;
	box-shadow:0 0 0 1px #3a86c8;
}
body.appbuilder-dark .charts_field_add:hover { background:var(--bg-hover); color:#8ec2ee; }
/* Chips lifted off the dark field: the old #1d3348 sat almost on top of the
   input's own #2b2b2b. A brighter fill and a real border make them read as
   distinct pills. */
body.appbuilder-dark .charts_tag {
	background:#274764; color:#bfe0ff; border-color:#3a6791;
}
body.appbuilder-dark .charts_cmp_tags .charts_tag {
	background:#332a4b; color:#cbb6f2; border-color:#4d3d70;
}
body.appbuilder-dark .charts_tags_empty,
body.appbuilder-dark .charts_tags_count,
body.appbuilder-dark .charts_dates_sep,
body.appbuilder-dark .charts_field > label { color:#7d848c; }
body.appbuilder-dark .charts_sep { background:var(--border); }
body.appbuilder-dark .charts_rail {
	background:var(--bg-alt); border-right-color:var(--border);
}
body.appbuilder-dark .charts_rail_btn { color:#aab2bb; }
body.appbuilder-dark .charts_rail_btn:hover { background:var(--bg-hover); color:#8ec2ee; }
body.appbuilder-dark .charts_rail_btn.is-on { background:#2F9EEE; color:#fff; }
body.appbuilder-dark .charts_rail_btn.is-on.charts_rail_state {
	background:transparent; color:#8ec2ee; box-shadow:inset 0 0 0 1.5px #2F9EEE;
}
body.appbuilder-dark .charts_rail_btn.is-on.charts_rail_state:hover {
	background:var(--bg-hover); color:#8ec2ee;
}
body.appbuilder-dark .charts_rail_btn.is-danger:hover { background:#4a2320; color:#ef9a9a; }
body.appbuilder-dark .chartdraw_bar,
body.appbuilder-dark .chartdraw_pop {
	background:var(--bg-panel); border-color:var(--border);
	box-shadow:0 4px 14px rgba(0,0,0,.5);
}
body.appbuilder-dark .chartdraw_btn,
body.appbuilder-dark .chartdraw_pop_row { color:#aab2bb; }
body.appbuilder-dark .chartdraw_btn:hover,
body.appbuilder-dark .chartdraw_pop_row:hover { background:var(--bg-hover); color:#8ec2ee; }
body.appbuilder-dark .chartdraw_btn.is-danger:hover { background:#4a2320; color:#ef9a9a; }
body.appbuilder-dark .chartdraw_gap { background:var(--border); }
body.appbuilder-dark .chartdraw_sw,
body.appbuilder-dark .chartdraw_cell { border-color:rgba(255,255,255,.28); }
body.appbuilder-dark .chartdraw_sw.is-ring.is-none { border-color:#7d848c; }
body.appbuilder-dark .charts_note_ta {
	background:var(--bg-input); border-color:var(--border); color:var(--fg);
}
/* The caret inherits currentColor from the button, so it is already themed by
   the rules above — only the menu glyphs carry a colour of their own. */
body.appbuilder-dark .w2ui-menu .charts_tool_ico { color:#aab2bb; }
body.appbuilder-dark .charts_rail_sep { background:var(--border); }
body.appbuilder-dark .charts_rail_arrow { color:#aab2bb; }
body.appbuilder-dark .charts_rail_arrow:hover { color:#8ec2ee; }
/* The fade has to match the rail it sits on, so it tracks --bg-alt too. */
body.appbuilder-dark .charts_rail_arrow.is-up {
	background:linear-gradient(to bottom, var(--bg-alt) 60%, transparent);
}
body.appbuilder-dark .charts_rail_arrow.is-down {
	background:linear-gradient(to top, var(--bg-alt) 60%, transparent);
}
body.appbuilder-dark .charts_cell.is-active .charts_cell_head { background:#1d3348; }
body.appbuilder-dark .charts_cell.is-active .charts_cell_sym  { color:#8ec2ee; }
body.appbuilder-dark .charts_replay {
	background:var(--bg-alt); border-top-color:var(--border);
}
body.appbuilder-dark .charts_replay_sym { color:#8ec2ee; border-right-color:var(--border); }
body.appbuilder-dark .charts_replay_btn {
	background:var(--bg-input); border-color:var(--border); color:#aab2bb;
}
body.appbuilder-dark .charts_replay_btn:hover { background:var(--bg-hover); color:#8ec2ee; }
/* Play stays a filled blue circle in dark mode too. */
body.appbuilder-dark .charts_replay_btn.is-close {
	background:transparent; border-color:transparent;
}
body.appbuilder-dark .charts_replay_btn.is-play { background:#2F9EEE; color:#fff; }
body.appbuilder-dark .charts_replay_btn.is-play:hover { background:#1a86d9; }
body.appbuilder-dark .charts_replay_pos { color:#9aa0a8; }
body.appbuilder-dark .charts_replay_hint { color:#7d848c; }
body.appbuilder-dark .charts_date {
	background:var(--bg-input); border-color:var(--border); color:var(--fg);
	color-scheme:dark;
}
body.appbuilder-dark .charts_win_btn,
body.appbuilder-dark .charts_right_toggle { color:#aab2bb; }
body.appbuilder-dark .charts_win_btn:hover,
body.appbuilder-dark .charts_right_toggle:hover { background:var(--bg-hover); color:#eee; }
body.appbuilder-dark .charts_right_toggle.active { background:#5a6268; color:#fff; }
body.appbuilder-dark .charts_layout {
	background:var(--bg-input); border-color:var(--border); color:var(--fg);
}
body.appbuilder-dark .charts_layout:hover { background:var(--bg-hover); border-color:var(--border-strong, #505050); }
body.appbuilder-dark .charts_layout_caret { color:#7d848c; }
body.appbuilder-dark .charts_layout_empty { color:#7d848c; }
body.appbuilder-dark .charts_layout_row      { border-bottom-color:#2c2f33; }
body.appbuilder-dark .charts_layout_row:hover { background:var(--bg-hover); }
body.appbuilder-dark .charts_layout_row.is-current { background:#1d3348; }
body.appbuilder-dark .charts_layout_row_name { color:#eee; }
body.appbuilder-dark .charts_layout_row_main:hover .charts_layout_row_name { color:#7ab1f0; }
body.appbuilder-dark .charts_layout_row_ic   { color:#7d848c; }
body.appbuilder-dark .charts_layout_row_desc { color:#7d848c; }
body.appbuilder-dark .charts_layout_scope.is-private { color:#6b727b; }
body.appbuilder-dark .charts_layout_row_win  { color:#4a4f55; }
body.appbuilder-dark .charts_layout_row:hover .charts_layout_row_win { color:#7d848c; }
body.appbuilder-dark .charts_layout_row_win:hover { color:#7ab1f0 !important; }
body.appbuilder-dark .charts_layout_row_del  { color:#4a4f55; }
body.appbuilder-dark .charts_layout_row:hover .charts_layout_row_del { color:#7d848c; }

body.appbuilder-dark .charts_grid { background:var(--bg); }
body.appbuilder-dark .charts_cell {
	background:var(--bg-panel); border-color:var(--border);
}
body.appbuilder-dark .charts_cell_head {
	background:var(--bg-alt); border-bottom-color:var(--border);
}
body.appbuilder-dark .charts_cell_sym    { color:#eee; }
body.appbuilder-dark .charts_cell_name   { color:#7d848c; }
/* The light amber (#c77700) is nearly invisible on a dark cell head, and the
   light hover red is too dark to read on a dark chip. Both need lifting rather
   than inheriting. */
body.appbuilder-dark .charts_cell_warn   { color:#e0a44a; }
body.appbuilder-dark .charts_tag_x:hover { color:#ef9a9a; }
body.appbuilder-dark .charts_cell_msg    { color:#aab2bb; }
body.appbuilder-dark .charts_cell_msg.is-error { color:#ef9a9a; }
body.appbuilder-dark .charts_alertnew_row { color:#dfe3e8; }
body.appbuilder-dark .charts_alertnew_lvl {
	background:var(--bg-alt); border-color:var(--border); color:#dfe3e8;
}
body.appbuilder-dark .charts_alertnew_hint { color:#7d848c; }
body.appbuilder-dark .charts_alerts_head { border-bottom-color:var(--border); color:#98a0aa; }
body.appbuilder-dark .charts_alert { border-bottom-color:#2a2e34; }
body.appbuilder-dark .charts_alert_sym { color:#eee; }
body.appbuilder-dark .charts_alert_note { color:#98a0aa; }
body.appbuilder-dark .charts_alert_state { color:#7d848c; }
body.appbuilder-dark .charts_alert.is-fired .charts_alert_lvl { color:#7d848c; }
body.appbuilder-dark .charts_alert.is-fired .charts_alert_state { color:#7fbf85; }
body.appbuilder-dark .charts_alert_btn { color:#7d848c; }
body.appbuilder-dark .charts_alert_btn:hover { color:#8ec2ee; }
body.appbuilder-dark .charts_alert_btn.fa-times:hover { color:#ef9a9a; }
body.appbuilder-dark .charts_alerts_empty { color:#7d848c; }
body.appbuilder-dark .charts_alerts_empty > .fa { color:#3a3f45; }
body.appbuilder-dark .charts_alerts_hint { color:#6b727a; }
body.appbuilder-dark .charts_tz {
	border-color:#2f343a; background:#22262b; color:#7d848c;
}
body.appbuilder-dark .charts_feed {
	border-color:#2f343a; background:#22262b; color:#7d848c;
}
body.appbuilder-dark .charts_feed.is-live { border-color:#245c46; background:#14291f; color:#5cc79a; }
body.appbuilder-dark .charts_cell_bell   { color:#7d848c; }
body.appbuilder-dark .charts_cell_bell:hover { color:#8ec2ee; }
/* Nothing to re-colour in dark mode — the armed bell is an emoji and carries
   its own palette. Kept as a rule so the next reader sees the state was
   considered rather than forgotten. */
body.appbuilder-dark .charts_cell_bell.is-on { filter:saturate(0.85); }
body.appbuilder-dark .charts_cell_max    { color:#7d848c; }
body.appbuilder-dark .charts_cell_max:hover { color:#8ec2ee; }
body.appbuilder-dark .charts_cell_x      { color:#7d848c; }
/* Chips: the light tints wash out on a dark cell, so both the indicator and
   the strategy chip get their own dark pairing rather than inheriting. */
body.appbuilder-dark .charts_chip {
	border-color:#2c3f52; background:#1b2836; color:#c8d4e0;
}
body.appbuilder-dark .charts_chip.is-strategy {
	border-color:#4a4026; background:#2c2618; color:#d8c48b;
}
body.appbuilder-dark .charts_chip_btn { color:#7d848c; }
body.appbuilder-dark .charts_chip_btn:hover { color:#8ec2ee; }
body.appbuilder-dark .charts_chip_btn.fa-times:hover { color:#ef9a9a; }
body.appbuilder-dark .charts_lib_search {
	background:var(--bg-alt); border-color:var(--border); color:#dfe3e8;
}
/* The sticky group heading paints over the rows scrolling beneath it, so its
   background has to be the dialog's own — transparent would smear. */
body.appbuilder-dark .charts_lib_group { color:#7d848c; background:var(--bg-panel); }
body.appbuilder-dark .charts_lib_row { border-bottom-color:#2a2e34; }
body.appbuilder-dark .charts_lib_name { color:#eee; }
body.appbuilder-dark .charts_lib_purpose { color:#98a0aa; }
body.appbuilder-dark .charts_lib_pic { color:#7d848c; }
body.appbuilder-dark .charts_markcard {
	border-color:#2f343a; background:#1b1f24; color:#aab2bb;
	box-shadow:0 3px 10px rgba(0,0,0,.45);
}
body.appbuilder-dark .charts_markcard b { color:#e8ecef; }
body.appbuilder-dark .charts_lib_tag {
	background:#2c2618; border-color:#4a4026; color:#d8c48b;
}
body.appbuilder-dark .charts_lib_on {
	background:#1c2e22; border-color:#2f5540; color:#7fc79b;
}
body.appbuilder-dark .charts_lib_nav { border-right-color:#2a2e34; }
body.appbuilder-dark .charts_lib_navitem { color:#b6bdc5; }
body.appbuilder-dark .charts_lib_navitem:hover { background:#242a31; }
body.appbuilder-dark .charts_lib_navitem.is-on { background:#1d3348; color:#8ec2ee; }
body.appbuilder-dark .charts_lib_navn { color:#7d848c; }
body.appbuilder-dark .charts_lib_navitem.is-on .charts_lib_navn { color:#8ec2ee; }
/* The explanation block needs to sit BACK from the row without disappearing —
   on dark it reads as a recessed panel rather than the light grey tint. */
body.appbuilder-dark .charts_lib_how {
	background:#20242a; border-color:#2a2e34; border-left-color:#3c4a58;
	color:#98a0aa;
}
body.appbuilder-dark .charts_lib_how > .fa { color:#6d7c8b; }
body.appbuilder-dark .charts_lib_info { color:#7d848c; }
body.appbuilder-dark .charts_lib_info:hover { color:#8ec2ee; }
body.appbuilder-dark .charts_lib_empty { color:#7d848c; }
body.appbuilder-dark .charts_indset_row { color:#dfe3e8; }
body.appbuilder-dark .charts_indset_group { color:#7d848c; }
body.appbuilder-dark .charts_indset_row > input[type=text],
body.appbuilder-dark .charts_indset_row > input[type=number],
body.appbuilder-dark .charts_indset_row > select {
	background:var(--bg-alt); border-color:var(--border); color:#dfe3e8;
}
body.appbuilder-dark .charts_empty > .fa { color:#4a4f55; }
body.appbuilder-dark .charts_empty_t     { color:#eee; }
body.appbuilder-dark .charts_empty_s     { color:#aab2bb; }

body.appbuilder-dark .charts_right {
	background:var(--bg-panel); border-left-color:var(--border);
}

body.appbuilder-dark .charts_pine_bar,
body.appbuilder-dark .charts_wl_bar,
body.appbuilder-dark .charts_wl_add,
body.appbuilder-dark .charts_wl_desc  { border-bottom-color:var(--border); }
body.appbuilder-dark .charts_pine_results:not(:empty) {
	background:var(--bg-alt); border-top-color:var(--border);
}
body.appbuilder-dark .charts-pine-editor {
	background:#1f2124; color:#e6e6e6;
}
body.appbuilder-dark .charts_wl_icon  { color:#aab2bb; }
body.appbuilder-dark .charts_wl_icon:hover { color:#8ec2ee; }
body.appbuilder-dark .charts_chat_empty > .fa { color:#4a4f55; }

body.appbuilder-dark .charts_wl_desc      { color:#aab2bb; }
body.appbuilder-dark .charts_wl_dlg label { color:#aab2bb; }
/* The name input is covered by the global dark input rule; the textarea is not
   (that rule targets `input`, not `textarea`), so it needs its own dark skin to
   match. */
body.appbuilder-dark .charts_wl_dlg textarea {
	background:var(--bg-input, #2b2b2b); color:var(--fg, #e6e6e6);
	border:1px solid var(--border-strong, #505050); border-radius:3px;
	color-scheme:dark;
}
body.appbuilder-dark .charts_wl_row      { border-bottom-color:#2c2f33; }
body.appbuilder-dark .charts_wl_row:hover { background:var(--bg-hover); }
body.appbuilder-dark .charts_wl_empty    { color:#7d848c; }
body.appbuilder-dark .charts_wl_sym,
body.appbuilder-dark .charts_wl_last     { color:#eee; }
body.appbuilder-dark .charts_wl_name,
body.appbuilder-dark .charts_wl_chg      { color:#7d848c; }
body.appbuilder-dark .charts_wl_nums.is-up   .charts_wl_chg { color:#7ddb9a; }
body.appbuilder-dark .charts_wl_nums.is-down .charts_wl_chg { color:#ef9a9a; }
body.appbuilder-dark .charts_wl_add_btn  { color:#5a626b; }
body.appbuilder-dark .charts_wl_row:hover .charts_wl_add_btn { color:#9aa0a8; }
body.appbuilder-dark .charts_wl_add_btn:hover { color:#fff !important; }
body.appbuilder-dark .charts_wl_x        { color:#4a4f55; }
body.appbuilder-dark .charts_wl_row:hover .charts_wl_x { color:#7d848c; }

/* ---- PineLab ▸ Market Data (#55) ---------------------------------------
   Same visual family as the portfolio panels (cards, KPI strip, utilisation
   bars) rather than a second design language: this is one more research
   surface in the same app, not a separate product. Light + dark together. */
.pl_data_panel  { font-family:OpenSans; background:#f7f8fa; }
.pl_wrap        { padding:18px 20px 28px; }
.pl_head        { margin-bottom:14px; }
.pl_title       { font-size:19px; font-weight:700; color:#27251E; }
.pl_sub         { margin-top:4px; font-size:11.5px; color:#737485; line-height:1.55; max-width:900px; }
.pl_root        { margin-top:6px; font-size:10.5px; color:#9aa0ab; font-family:Consolas,monospace; }

.pl_kpis        { display:flex; gap:12px; margin-bottom:14px; flex-wrap:wrap; }
.pl_kpi         { flex:1 1 160px; background:#fff; border:1px solid #e3e6ec; border-radius:8px; padding:10px 12px; }
.pl_kpi_l       { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.pl_kpi_v       { font-size:20px; font-weight:700; color:#27251E; margin-top:2px; }
.pl_kpi_h       { font-size:10.5px; color:#9aa0ab; margin-top:2px; }

.pl_card        { background:#fff; border:1px solid #e3e6ec; border-radius:8px; padding:12px 14px; margin-bottom:14px; }
.pl_card_h      { font-size:12px; font-weight:700; color:#27251E; margin-bottom:10px;
                  display:flex; align-items:center; gap:10px; }
.pl_win         { font-size:10.5px; font-weight:400; color:#9aa0ab; }

.pl_form        { display:flex; flex-direction:column; gap:8px; }
.pl_form > label { font-size:11px; color:#737485; }
.pl_syms        { width:100%; font-family:Consolas,monospace; font-size:11.5px; resize:vertical; }
.pl_form_row    { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.pl_inline      { font-size:11px; color:#737485; margin-left:4px; }
.pl_date        { width:150px; }
.pl_gap         { flex:1 1 auto; }
.pl_est         { font-size:11.5px; color:#1a5c9c; font-weight:600; }

.pl_btn         { font-family:OpenSans; font-size:11.5px; padding:5px 11px; border-radius:5px;
                  border:1px solid #ccd2dc; background:#fff; color:#27251E; cursor:pointer; }
.pl_btn:hover   { background:#f2f4f7; }
.pl_btn[disabled] { opacity:.5; cursor:not-allowed; }
.pl_btn.is-primary { background:#1a5c9c; border-color:#1a5c9c; color:#fff; }
.pl_btn.is-primary:hover { background:#14497d; }
.pl_btn.is-danger  { background:#b3261e; border-color:#b3261e; color:#fff; }

.pl_note        { font-size:11px; color:#737485; background:#f4f6f9; border-radius:5px; padding:6px 9px; }
.pl_note.is-err  { background:#fdecea; color:#b3261e; }
.pl_note.is-warn { background:#fdf6e3; color:#8a6d1f; }

.pl_job         { border:1px solid #e3e6ec; border-radius:6px; padding:9px 11px; margin-bottom:8px; }
.pl_job.is-run  { border-color:#9fc6ea; background:#f5faff; }
.pl_job.is-ok   { border-color:#bfe0c8; background:#f6fbf7; }
.pl_job.is-warn { border-color:#e8c86e; background:#fdf8ea; }
.pl_job.is-err  { border-color:#d46a63; background:#fdecea; }
.pl_job_top     { display:flex; align-items:center; gap:10px; margin-bottom:6px; }
.pl_job_st      { font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.4px; color:#4a5160; }
.pl_job_win     { font-size:11px; color:#737485; }
.pl_job_cur     { font-size:11px; font-weight:600; color:#1a5c9c; font-family:Consolas,monospace; }
.pl_job_x       { margin-left:auto; }

/* ---- Graduation: stage rail + section explanations ----------------------
   The pipeline is a SEQUENCE, and a single stage word could not say where a
   strategy stood among six of them or what came next. The rail says both, so
   the prose banner that used to repeat the stage is no longer needed. */
/* CHEVRONS, not dots-on-a-line. The rail is a progression, and an arrow pointing
   at the next stage says that on its own - the connector-line version needed a
   separate bar between the dots and never lined up with them. Each segment is
   notched on the left and pointed on the right (clip-path), so they interlock. */
/* Rounding lives on the WRAPPER, not the segments: clip-path cannot round a
   corner, so the rail is clipped as one rounded strip. That rounds exactly the
   two outer extremes - the left of the first step and the right of the last -
   and leaves every interior chevron edge sharp.

   NOTE THE PREFIX: `.pl_step` was already taken further down this file by the
   unrelated `.pl_steps` widget, whose pill styling (border-radius:20px, a border,
   its own .is-done) is defined LATER and therefore won every tie - which is why
   these chevrons rendered as rounded pills. Hence `pl_gstep`. */
.pl_grail       { display:flex; gap:3px; margin:2px 0 14px;
	border-radius:6px; overflow:hidden; }
.pl_gstep       { flex:1 1 0; min-width:0; display:flex; align-items:center; gap:6px;
	min-height:34px; padding:5px 22px 5px 26px; box-sizing:border-box; border-radius:0;
	background:#eef0f4; color:#8a90a0; overflow:hidden;
	clip-path:polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%, 12px 50%); }
/* First has no left notch, last no right point - so neither wastes the padding
   that exists only to keep the label clear of the chevron. */
.pl_gstep:first-child { padding-left:14px;
	clip-path:polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%); }
.pl_gstep:last-child  { padding-right:14px;
	clip-path:polygon(0 0, 100% 0, 100% 100%, 0 100%, 12px 50%); }
.pl_gstep_mark  { flex:0 0 auto; font-size:10.5px; font-weight:700; opacity:.85; }
.pl_gstep_txt   { display:flex; flex-direction:column; min-width:0; line-height:1.25; }
.pl_gstep_lbl   { font-size:11px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pl_gstep_gate  { font-size:9.5px; letter-spacing:.2px; opacity:.9; white-space:nowrap;
	overflow:hidden; text-overflow:ellipsis; }
.pl_gstep.is-done { background:#3a9d5d; color:#fff; }
.pl_gstep.is-now  { background:#1a5c9c; color:#fff; }
.pl_gstep.is-now  .pl_gstep_lbl { font-weight:700; }
.pl_gstep.is-next.is-open    { background:#e7f4ec; color:#2f7d4f; }
.pl_gstep.is-next.is-blocked { background:#fdecea; color:#b3261e; }
.pl_gstep.is-retired { background:#b3261e; color:#fff; }

/* One line under each card head saying what the section is FOR. The panel
   assumed the reader already knew the pipeline's vocabulary; they do not. */
.pl_sec_x       { font-size:11px; color:#8a90a0; line-height:1.5; margin:-4px 0 10px; max-width:860px; }
.pl_actbar      { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 14px; }
/* Panel-level notes - the gate caveat, the holdout's running/failed line - sit in the
   flow between the stage rail and the action bar, and .pl_note carries no margin of its
   own (it is normally inside a card, where the card's padding does the work). Scoped to
   DIRECT children so notes inside cards keep their existing tight spacing. */
.pl_wrap > .pl_note { margin:0 0 14px; }
.pl_wrap > .pl_note + .pl_note { margin-top:-6px; }

/* A card dropped into the slot by an owner (the strategy's "Used by") has its own
   margins from when it stood alone in the tab body - which left it inset from every
   pl_card beside it. Inside the rail's column it must BE a pl_card. */
.pl_slot_extra > .ts_pf_card {
	margin:0 0 14px; padding:12px 14px; border-radius:8px;
	background:#fff; border-color:#e3e6ec; }
body.appbuilder-dark .pl_slot_extra > .ts_pf_card {
	background:#272a30; border-color:#383c44; }
.pl_more > summary { font-size:12px; font-weight:700; color:#27251E; cursor:pointer; outline:none; }
.pl_more[open] > summary { margin-bottom:8px; }

body.appbuilder-dark .pl_gstep       { background:#31353c; color:#8b919b; }
body.appbuilder-dark .pl_gstep.is-done { background:#2f7d4f; color:#fff; }
body.appbuilder-dark .pl_gstep.is-now  { background:#2b6cb0; color:#fff; }
body.appbuilder-dark .pl_gstep.is-next.is-open    { background:#20372a; color:#6cc48d; }
body.appbuilder-dark .pl_gstep.is-next.is-blocked { background:#391f1d; color:#e08079; }
body.appbuilder-dark .pl_gstep.is-retired { background:#8f2019; color:#fff; }
body.appbuilder-dark .pl_sec_x      { color:#8b919b; }
body.appbuilder-dark .pl_more > summary { color:#e6e8ec; }
.pl_job_b       { font-size:11px; color:#737485; margin-top:5px; }

.pl_bar         { height:7px; background:#eceff3; border-radius:4px; overflow:hidden; min-width:70px; }
.pl_bar > i     { display:block; height:100%; background:#1a5c9c; }
.pl_bar.is-ok  > i { background:#2f7d4f; }
.pl_bar.is-warn > i { background:#d99a1a; }
.pl_bar.is-bad > i { background:#b3261e; }

/* Containing block for the absolutely-centered .anylist_empty message (it is
   position:absolute / top:50%, so without a positioned ancestor of real height
   it escapes the card and overlaps whatever follows). Same fix the members
   section uses. */
.pl_cardbody    { position:relative; min-height:96px; }

.pl_table       { width:100%; }
.pl_table .pl_sym { font-weight:600; font-family:Consolas,monospace; }

body.appbuilder-dark .pl_data_panel { background:#1f2126; }
body.appbuilder-dark .pl_title      { color:#e6e8ec; }
body.appbuilder-dark .pl_sub        { color:#9aa0a8; }
body.appbuilder-dark .pl_root       { color:#6b7280; }
body.appbuilder-dark .pl_kpi,
body.appbuilder-dark .pl_card       { background:#272a30; border-color:#383c44; }
body.appbuilder-dark .pl_kpi_v,
body.appbuilder-dark .pl_card_h     { color:#e6e8ec; }
body.appbuilder-dark .pl_kpi_l,
body.appbuilder-dark .pl_kpi_h,
body.appbuilder-dark .pl_win,
body.appbuilder-dark .pl_inline,
body.appbuilder-dark .pl_form > label,
body.appbuilder-dark .pl_job_win,
body.appbuilder-dark .pl_job_b      { color:#9aa0a8; }
body.appbuilder-dark .pl_btn        { background:#31353c; border-color:#454a53; color:#dfe3e8; }
body.appbuilder-dark .pl_btn:hover  { background:#3a3f47; }
body.appbuilder-dark .pl_btn.is-primary { background:#2b6cb0; border-color:#2b6cb0; color:#fff; }
body.appbuilder-dark .pl_note       { background:#2e3238; color:#9aa0a8; }
body.appbuilder-dark .pl_note.is-err  { background:#391f1d; color:#e08079; }
body.appbuilder-dark .pl_note.is-warn { background:#332e1f; color:#e0c071; }
body.appbuilder-dark .pl_job        { border-color:#383c44; }
body.appbuilder-dark .pl_job.is-run { border-color:#2b5a80; background:#22303b; }
body.appbuilder-dark .pl_job.is-ok  { border-color:#2f6b45; background:#1f2f26; }
body.appbuilder-dark .pl_job.is-warn { border-color:#6a5a2c; background:#332e1f; }
body.appbuilder-dark .pl_job.is-err { border-color:#7a3630; background:#391f1d; }
body.appbuilder-dark .pl_job_st     { color:#aab2bb; }
body.appbuilder-dark .pl_bar        { background:#383c44; }

/* Gap report (drill-down): a monthly histogram answers 'block or scatter' at a
   glance, which a missing-day COUNT cannot. */
.pl_row         { cursor:pointer; }
.pl_row:hover   { background:#f4f7fb; }
.pl_det_x       { margin-left:auto; }
.pl_months      { display:flex; align-items:flex-end; gap:3px; padding:6px 0 2px;
                  overflow-x:auto; min-height:64px; }
.pl_mo          { display:flex; flex-direction:column; align-items:center; gap:3px; min-width:26px; }
.pl_mo > i      { display:block; width:16px; background:#d99a1a; border-radius:2px 2px 0 0; }
.pl_mo.is-full > i { background:#b3261e; }
.pl_mo > span   { font-size:8.5px; color:#9aa0ab; white-space:nowrap; }
.pl_days        { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; max-height:150px; overflow:auto; }
.pl_day         { font-size:10px; font-family:Consolas,monospace; padding:2px 5px; border-radius:3px;
                  background:#fdf6e3; color:#8a6d1f; }
.pl_day.is-missing { background:#fdecea; color:#b3261e; }
.pl_day_more    { font-size:10px; color:#9aa0ab; padding:2px 5px; }
body.appbuilder-dark .pl_row:hover { background:#2e333a; }
body.appbuilder-dark .pl_mo > span { color:#767c86; }
body.appbuilder-dark .pl_day       { background:#332e1f; color:#e0c071; }
body.appbuilder-dark .pl_day.is-missing { background:#391f1d; color:#e08079; }
body.appbuilder-dark .pl_day_more  { color:#767c86; }

/* Coverage % is the link into the gap report — same blue affordance the rest of
   the builder uses for a clickable value, so it is visible without a hover. */
.pl_pctlink     { color:#1a5c9c; cursor:pointer; text-decoration:none; border-bottom:1px dotted #9fc0e0; }
.pl_pctlink:hover { color:#0d4278; border-bottom-color:#1a5c9c; }

/* Gap dialog: opens immediately with a spinner, because the coverage read walks
   every Parquet partition the window touches. */
.pl_dlg         { font-family:OpenSans; padding:4px 6px; }
.pl_spin        { display:flex; flex-direction:column; align-items:center; justify-content:center;
                  gap:12px; height:220px; color:#737485; font-size:12px; }
.pl_spinner     { width:28px; height:28px; border:3px solid #e3e6ec; border-top-color:#1a5c9c;
                  border-radius:50%; animation:pl_spin 0.8s linear infinite; }
@keyframes pl_spin { to { transform:rotate(360deg); } }
body.appbuilder-dark .pl_pctlink  { color:#6aa9e0; border-bottom-color:#3c5f80; }
body.appbuilder-dark .pl_pctlink:hover { color:#9ac8f0; }
body.appbuilder-dark .pl_spin     { color:#9aa0a8; }
body.appbuilder-dark .pl_spinner  { border-color:#383c44; border-top-color:#6aa9e0; }

/* Busy overlay on the coverage list. Always in the DOM, revealed by .is-busy —
   creating it at the moment the UI is least responsive is the wrong time. */
.pl_cardbody.is-busy > :not(.pl_busy) { opacity:.35; pointer-events:none; }
.pl_busy        { display:none; position:absolute; inset:0; z-index:2;
                  align-items:center; justify-content:center; gap:10px;
                  font-family:OpenSans; font-size:11.5px; color:#737485; }
.pl_cardbody.is-busy > .pl_busy { display:flex; }

/* Indeterminate progress: the server has been asked but cannot yet say how
   much work there is. A 0% bar would claim it had started and stalled. */
.pl_bar.is-indet > i { width:35%; background:#1a5c9c; animation:pl_slide 1.1s ease-in-out infinite; }
@keyframes pl_slide { 0% { margin-left:0; } 50% { margin-left:65%; } 100% { margin-left:0; } }
body.appbuilder-dark .pl_busy { color:#9aa0a8; }

.pl_force       { display:inline-flex; align-items:center; gap:5px; cursor:pointer; }
.pl_force input { margin:0; }

/* ---- validation grid (#58): Backtest Lab, Leaderboard, Run Detail ----------
   Deliberately built on the pl_* vocabulary above rather than a second one.
   Three screens in the same corner of the app that looked like three different
   products would make the pipeline between them harder to see than it is. */

.pl_steps       { display:flex; gap:6px; margin-bottom:14px; flex-wrap:wrap; }
.pl_step        { display:flex; align-items:center; gap:7px; font-size:11px; color:#8a90a0;
                  background:#fff; border:1px solid #e3e6ec; border-radius:20px; padding:5px 12px; }
.pl_step > b    { display:inline-flex; align-items:center; justify-content:center;
                  width:17px; height:17px; border-radius:50%; background:#eceff3;
                  color:#737485; font-size:10px; font-weight:700; }
.pl_step.is-on  { border-color:#1a5c9c; color:#1a5c9c; }
.pl_step.is-on > b   { background:#1a5c9c; color:#fff; }
.pl_step.is-done > b { background:#2f7d4f; color:#fff; }

.pl_script      { width:100%; min-height:190px; font-family:Consolas,monospace; font-size:11.5px;
                  resize:vertical; }
.pl_num         { width:70px; }

/* The headline. DSR is deliberately the loudest number on the screen and raw
   Sharpe the quietest — see DeflatedSharpe for why that ordering is the point
   rather than a style choice. */
.pl_dsr         { font-size:22px; font-weight:700; color:#1a5c9c; }
.pl_dsr.is-weak { color:#b3261e; }
.pl_dsr.is-mid  { color:#8a6d1f; }
.pl_dim         { color:#9aa0ab; font-weight:400; }

.pl_flags       { display:flex; gap:6px; flex-wrap:wrap; }
.pl_flag        { font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.3px;
                  border-radius:4px; padding:2px 6px; background:#f4f6f9; color:#737485; }
.pl_flag.is-warn { background:#fdf6e3; color:#8a6d1f; }
.pl_flag.is-bad  { background:#fdecea; color:#b3261e; }
.pl_flag.is-ok   { background:#f6fbf7; color:#2f7d4f; }

/* Fold strip: one block per walk-forward window, train muted, test emphasised —
   the shape of the validation, readable before any number is. */
.pl_folds       { display:flex; gap:6px; flex-wrap:wrap; }
.pl_fold        { flex:1 1 150px; border:1px solid #e3e6ec; border-radius:6px; padding:8px 10px; }
.pl_fold_h      { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0;
                  margin-bottom:5px; }
.pl_fold_r      { display:flex; justify-content:space-between; font-size:11px; color:#737485;
                  margin-top:2px; }
.pl_fold_r > b  { font-weight:600; color:#27251E; }
.pl_fold.is-neg > .pl_fold_r > b.is-oos { color:#b3261e; }
.pl_fold.is-pos > .pl_fold_r > b.is-oos { color:#2f7d4f; }

/* Equity curve, drawn as an inline SVG. No chart library: it is one polyline
   over a few hundred points, and a dependency for that is a dependency to keep
   working forever. */
/* The plot is the SVG; the axis labels are HTML on top of it.
   Text inside the viewBox is drawn in user units, so its size follows the panel
   width - the same chart gave 7px type in a narrow panel and 18px in a wide one.
   Positioned as percentages of the same box, the labels stay on their gridlines
   at any width while being set in real pixels, which also lets the plot keep
   preserveAspectRatio=none and fill its height. */
.pl_eqwrap      { position:relative; }
.pl_eq          { width:100%; height:170px; display:block; }
.pl_eq_line     { fill:none; stroke:#1a5c9c; stroke-width:1.6; }
.pl_eq_dd       { fill:#b3261e; opacity:.12; }
.pl_eq_zero     { stroke:#9aa0a8; stroke-width:1; stroke-dasharray:3 3; }
.pl_eq_grid     { stroke:#e6e8ea; stroke-width:1; }
.pl_eq_yl       {
	position:absolute; left:0; text-align:right; transform:translateY(-50%);
	font-size:10px; line-height:1; color:#9aa0ab; white-space:nowrap;
	font-variant-numeric:tabular-nums; pointer-events:none;
}
.pl_eq_xl       {
	position:absolute; bottom:3px; font-size:10px; line-height:1; color:#9aa0ab;
	white-space:nowrap; font-variant-numeric:tabular-nums; pointer-events:none;
}
.pl_eq_xl.is-end { transform:translateX(-100%); }
.pl_eq_cap      { font-size:10.5px; color:#9aa0ab; line-height:1.5; margin-top:4px; }
body.appbuilder-dark .pl_eq_grid { stroke:#3f4348; }
body.appbuilder-dark .pl_eq_yl,
body.appbuilder-dark .pl_eq_xl,
body.appbuilder-dark .pl_eq_cap  { color:#7d848c; }

.pl_back        { font-size:11.5px; color:#1a5c9c; cursor:pointer; margin-bottom:10px;
                  display:inline-flex; align-items:center; gap:6px; }
.pl_mono        { font-family:Consolas,monospace; font-size:10.5px; color:#737485; }
.pl_pos         { color:#2f7d4f; font-weight:600; }
.pl_neg         { color:#b3261e; font-weight:600; }

body.appbuilder-dark .pl_step   { background:#272a30; border-color:#383c44; color:#9aa0a8; }
body.appbuilder-dark .pl_step > b { background:#383c44; color:#9aa0a8; }
body.appbuilder-dark .pl_step.is-on { border-color:#2b6cb0; color:#6aa9e0; }
body.appbuilder-dark .pl_step.is-on > b { background:#2b6cb0; color:#fff; }
body.appbuilder-dark .pl_step.is-done > b { background:#2f6b45; color:#fff; }
body.appbuilder-dark .pl_dsr    { color:#6aa9e0; }
body.appbuilder-dark .pl_dsr.is-weak { color:#e08079; }
body.appbuilder-dark .pl_dsr.is-mid  { color:#e0c071; }
body.appbuilder-dark .pl_dim,
body.appbuilder-dark .pl_mono   { color:#767c86; }
body.appbuilder-dark .pl_flag   { background:#2e3238; color:#9aa0a8; }
body.appbuilder-dark .pl_flag.is-warn { background:#332e1f; color:#e0c071; }
body.appbuilder-dark .pl_flag.is-bad  { background:#391f1d; color:#e08079; }
body.appbuilder-dark .pl_flag.is-ok   { background:#1f2f26; color:#7fbf95; }
body.appbuilder-dark .pl_fold   { border-color:#383c44; }
body.appbuilder-dark .pl_fold_h { color:#9aa0a8; }
body.appbuilder-dark .pl_fold_r { color:#9aa0a8; }
body.appbuilder-dark .pl_fold_r > b { color:#e6e8ec; }
body.appbuilder-dark .pl_eq_line { stroke:#6aa9e0; }
body.appbuilder-dark .pl_eq_zero { stroke:#454a53; }
body.appbuilder-dark .pl_back   { color:#6aa9e0; }
body.appbuilder-dark .pl_pos    { color:#7fbf95; }
body.appbuilder-dark .pl_neg    { color:#e08079; }

/* ---- amendment loop kanban (#63) ------------------------------------------
   A horizontal board: one column per loop state, cards flowing left to right.
   Built on the pl_* vocabulary so the loop reads as part of the same lab. */
/* The board fills the panel: wrap -> pipeline card -> kanban -> column body, each a
   flex child that may shrink (min-height:0), so the SCROLL lands on the column body
   rather than on the page. A crowded stage then scrolls inside its own column instead
   of stretching the board and pushing the other columns out of view. */
.pl_wrap.is-board { display:flex; flex-direction:column; height:100%; box-sizing:border-box; }
.pl_wrap.is-board > .pl_card.is-pipeline {
	flex:1 1 auto; min-height:0; display:flex; flex-direction:column; margin-bottom:0; }
.pl_card.is-pipeline > .pl_kanban { flex:1 1 auto; min-height:0; align-items:stretch; }
/* Cards used to be spaced by the column's own gap; now that they live in the scroller,
   the spacing has to travel with them. */
.pl_kcol_body   { flex:1 1 auto; min-height:0; overflow-y:auto;
	display:flex; flex-direction:column; gap:8px; }

.pl_kanban      { display:flex; gap:10px; overflow-x:auto; padding:2px 0 6px; }
.pl_kcol        { flex:1 1 0; min-width:200px; min-height:0; background:#f4f6f9;
                  border-radius:8px; padding:8px;
                  display:flex; flex-direction:column; gap:8px; }
.pl_kcol_h      { flex:0 0 auto;
                  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.4px;
                  color:#737485; }
.pl_amend_card  { background:#fff; border:1px solid #e3e6ec; border-left:3px solid #9aa0ab;
                  border-radius:6px; padding:8px 10px; font-size:11.5px; color:#27251E; }
/* Plain, not a link: the whole card is the click target and already says so with its
   pointer cursor - underlining the name too would only imply a second, different action. */
.pl_cardname    { font-weight:600; }
.pl_amend_card.is-ok   { border-left-color:#2f7d4f; }
.pl_amend_card.is-run  { border-left-color:#1a5c9c; }
.pl_amend_card.is-bad  { border-left-color:#b3261e; }
/* A GRADUATION card (pl_gcard) takes its left edge from its STAGE instead of the gate
   verdict, and wider - it is the card's primary signal, and it matches the chip the same
   strategy carries in the Strategies list. Extra specificity so it wins over the .is-ok /
   .is-run / .is-bad rules above regardless of where this lands in the file; those still
   colour the AMENDMENT board's cards, which carry no stage. */
.pl_kcol .pl_amend_card.pl_gcard { border-left:8px solid var(--stage, #9aa0ab); }
/* The gate verdict moved off the border (which now carries the stage) onto the words
   that state it - one edge cannot mean two things. */
.pl_gate         { font-weight:600; }
.pl_gate.is-ok   { color:#2f7d4f; }
.pl_gate.is-run  { color:#1a5c9c; }
.pl_gate.is-bad  { color:#b3261e; }
body.appbuilder-dark .pl_gate.is-ok  { color:#6cc48d; }
body.appbuilder-dark .pl_gate.is-run { color:#7fb2e8; }
body.appbuilder-dark .pl_gate.is-bad { color:#e08079; }

body.appbuilder-dark .pl_kcol       { background:#22252b; }
body.appbuilder-dark .pl_kcol_h     { color:#9aa0a8; }
body.appbuilder-dark .pl_amend_card { background:#272a30; border-color:#383c44;
                                      border-left-color:#5a6270; color:#e6e8ec; }
body.appbuilder-dark .pl_amend_card.is-ok  { border-left-color:#2f6b45; }
body.appbuilder-dark .pl_amend_card.is-run { border-left-color:#2b6cb0; }
body.appbuilder-dark .pl_amend_card.is-bad { border-left-color:#7a3630; }

/* ================================================================
   Detached chart window
   ----------------------------------------------------------------
   A chart window is the whole app booted onto one panel (see
   Builder_ChartWindowForm), so the chrome has to be taken away rather
   than never built: the dark sidebar and, via the boot, the app top bar
   (w2layout.hide("top")). Same sidebar selectors as the Tower Control
   profile in ChapsV_TowerControl.css — one way of going chrome-less.

   The TAB STRIP deliberately stays: instruments opened from a chart open
   in this window, and the strip is the way back to the charts. Which
   tabs it carries is decided in Builder_RefreshTabs, not here — hiding
   the strip in CSS left w2layout still offsetting the content by the tab
   row's height, which is what showed as a dark bar above the charts.
   ================================================================ */
body.appbuilder-chartwindow #mySidebar                { display:none !important; }
body.appbuilder-chartwindow #mySidebar + td > #myForm { width:100vw !important; }

/* ================================================================
   RESEARCH package — theme cards (Builder_Themes).
   Ship 0 of docs/thesis-engine-plan.md.

   Same card anatomy as the portfolio dashboard cards (.pf_dcard) so the
   two directories read as one family: a title, a chip row, a headline
   figure, a meta strip. Deliberately its own `rs_` prefix rather than
   reusing `pf_`: the chips carry a DIFFERENT vocabulary (a research
   stage is not a runtime status), and sharing the selectors would mean a
   colour tuned for "running" silently restyling "live".
   ================================================================ */
.applications_element.rs_tcard { width:340px; height:auto; }
.rs_tcard .applications_element_text {
	position:static; left:auto; top:auto; width:auto; height:auto;
	overflow:visible; padding:2px 4px 4px;
}
.rs_tcard_title   { display:block; padding-right:8px; line-height:20px; font-weight:600;
                    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rs_tcard_chips   { display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin:5px 0 6px; }
/* Two lines then ellipsis: a tagline is one sentence, and a card that grows to
   fit a paragraph breaks the grid's even rows. */
.rs_tcard_tagline { margin:0 0 8px; font-size:11.5px; color:#6b7280; line-height:1.45;
                    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden; }
.rs_tcard_conv    { margin:2px 0 8px; }
.rs_tcard_convk   { font-size:9.5px; font-weight:600; letter-spacing:0.3px; text-transform:uppercase; color:#9aa0a8; }
.rs_tcard_convv   { margin-top:2px; font-size:14px; font-weight:600; color:#27251E; white-space:nowrap; }
.rs_tcard_meta    { display:flex; flex-wrap:wrap; gap:14px; margin:8px 0 10px; font-size:11px; color:#737485; }
.rs_tcard_meta i  { margin-right:4px; opacity:0.7; }

/* Chips. GEOMETRY IS NOT RESTATED HERE — `.rs_chip` is grouped with `.pf_chip`
   at its own definition, so the two chip families cannot drift apart when one
   is tuned. What lives below is only what differs: the colours. */
.rs_chip i { position:relative; top:1px; opacity:0.85; }
/* ...EXCEPT a Font Awesome glyph. The 1px nudge above was tuned when the chip
   was inline-BLOCK and the icon sat on the text baseline. The chip is
   inline-flex with align-items:center now, so the icon is already centred and
   the nudge pushes it a pixel below the label — visible on a 10px chip.
   The nudge stays for the other `<i>` in here, which are not icons at all: the
   filter count (.co_fcn) and the purity beta (.co_thbeta) are spans wearing an
   `<i>`, and they were what it was written for.
   `line-height:1` with a square box so flex centres the GLYPH rather than an
   oblong advance-width box — the same reason the spinning icons needed one. */
.rs_chip > .fa {
	position:static; top:auto;
	display:inline-flex; align-items:center; justify-content:center;
	width:1em; height:1em; line-height:1;
}

/* The governance ladder, coloured as a PROGRESSION — grey (nothing committed)
   → blue (watched) → amber (money at risk on paper) → green (money at risk for
   real). The jump to amber is where the palette gets loud on purpose: paper is
   the last rung before a theme can cost something. */
.rs_chip.is-draft     { background:#eceff4; color:#6b7280; }
.rs_chip.is-watchlist { background:#eaf1fd; color:#1c53b8; }
.rs_chip.is-paper     { background:#fdf3e3; color:#9a6a10; }
.rs_chip.is-live      { background:#e6f4ec; color:#116b3a; }
/* The family had a green and no red, which is why "net selling" had to borrow
   the grey draft chip. Same pair `.pf_side.is-short` uses, so a red chip means
   the same thing here as it does on a position. */
.rs_chip.is-neg       { background:#fbeaea; color:#b3261e; }
/* Lifecycle is a CLASSIFICATION, not a state, so it gets one neutral outlined
   treatment for every value rather than four hues — four more colours beside
   the stage ladder would make the card a paint chart and imply the two rows
   mean the same kind of thing. */
.rs_chip.is-lifecycle { background:transparent; color:#41506b; border:1px solid #d5dae1; padding:2px 8px; }

body.appbuilder-dark .rs_tcard_tagline { color:#9aa0ac; }
body.appbuilder-dark .rs_tcard_convk   { color:#9aa0ac; }
body.appbuilder-dark .rs_tcard_convv   { color:#e6e6ea; }
body.appbuilder-dark .rs_tcard_meta    { color:#9aa0ac; }
body.appbuilder-dark .rs_chip.is-draft     { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .rs_chip.is-watchlist { background:#1e2c44; color:#8ab4f8; }
body.appbuilder-dark .rs_chip.is-paper     { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .rs_chip.is-live      { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .rs_chip.is-neg       { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .rs_chip.is-lifecycle { background:transparent; color:#a8bdd4; border-color:#4a4f57; }

/* ================================================================
   RESEARCH — Radar card scores + filter chips (Ship 1).
   ================================================================ */
/* The star, pinned to the card corner where the portfolio cards put their
   controls. Dim until set, so a grid of unstarred cards is quiet. */
.rs_tcard_fav {
	position:absolute; top:8px; right:8px; z-index:1;
	border:0; background:transparent; cursor:pointer;
	padding:4px 6px; font-size:13px; color:#c8ccd4; line-height:1;
}
.rs_tcard_fav:hover        { color:#9aa0a8; }
.rs_tcard_fav.is-on        { color:#e8a600; }
.rs_tcard .rs_tcard_title  { padding-right:28px; }

/* Four score bars, label / track / value on one row each. A grid rather than
   flex so the labels and the numbers line up down the card no matter how long
   a translated label is. */
/* The score cells are defined in the UI-corrections block near the end of this
   file — two columns, label left, value right, bar below. The original
   single-column `label | bar | value` grid lived here and was REMOVED rather
   than shadowed: `.rs_score { display:contents }` would still have applied
   (the replacement sets no `display`), and a layout that works only because of
   source order is the drift this file has been bitten by before. */

.rs_tcard_figs   { display:flex; gap:18px; margin:2px 0 6px; }
.rs_tcard_convk  { font-size:9.5px; font-weight:600; letter-spacing:0.3px; text-transform:uppercase; color:#9aa0a8; }
.rs_tcard_convv  { margin-top:2px; font-size:14px; font-weight:600; color:#27251E; white-space:nowrap; }

.rs_filterbar    { display:flex; align-items:center; gap:4px; flex-wrap:wrap; padding:0 8px; }
.rs_fchip {
	font-family:'Open Sans', sans-serif; font-size:10.5px; line-height:1.5;
	padding:3px 9px; border-radius:10px; white-space:nowrap; cursor:pointer;
	border:1px solid #d5dae1; background:transparent; color:#6b7280;
}
.rs_fchip:hover  { border-color:#9aa0a8; }
.rs_fchip.on     { background:#eaf1fd; border-color:#a8c6f5; color:#1c53b8; }
.rs_fsep         { width:1px; height:16px; background:#d5dae1; margin:0 5px; }

body.appbuilder-dark .rs_tcard_fav      { color:#565b64; }
body.appbuilder-dark .rs_tcard_fav:hover{ color:#8b919b; }
body.appbuilder-dark .rs_tcard_fav.is-on{ color:#f0b400; }
body.appbuilder-dark .rs_score_k        { color:#8b919b; }
body.appbuilder-dark .rs_score_bar      { background:#3a3f47; }
body.appbuilder-dark .rs_score_v        { color:#9aa0ac; }
body.appbuilder-dark .rs_tcard_convk    { color:#9aa0ac; }
body.appbuilder-dark .rs_tcard_convv    { color:#e6e6ea; }
body.appbuilder-dark .rs_fchip          { border-color:#4a4f57; color:#9aa0ac; }
body.appbuilder-dark .rs_fchip:hover    { border-color:#6b7280; }
body.appbuilder-dark .rs_fchip.on       { background:#1e2c44; border-color:#33507d; color:#8ab4f8; }
body.appbuilder-dark .rs_fsep           { background:#4a4f57; }

/* ================================================================
   RESEARCH — the theme workspace (Builder_Theme).

   Same skeleton as the portfolio panel: a header band, a w2tabs strip,
   one scrolling body per tab. The panel/dial/bar vocabulary is its own
   (th_) because a theme's numbers are judgements on a 0-100 scale, not
   money — sharing the portfolio classes would inherit colours that
   already mean profit and loss.
   ================================================================ */
.theme-panel      { display:flex; flex-direction:column; font-family:'Open Sans', sans-serif; background:#FAF8F5; }
.th_head          { flex:0 0 auto; padding:12px 16px 0; background:#fff; border-bottom:1px solid #e2e2e2; }
.th_tabbar        { flex:0 0 auto; }
.th_body          { flex:1 1 auto; overflow:auto; min-height:0; }

/* THREE SECTIONS, TWO OF THEM FIXED.
   Identity on the left, actions in the middle, the three numbers on the
   right. The two ends size to their content and never shrink; the MIDDLE is
   the only section that gives, and its buttons wrap inside it.
   This row used to wrap, and the right side carried the actions AND the
   readouts — so a document button appearing, or a modal taking the scrollbar
   away, spent itself by dropping the numbers below the theme name. A large
   break from a tiny overflow, and the same defect the company header had. */
.th_head_main     { display:flex; align-items:flex-start; justify-content:space-between;
                    gap:16px; flex-wrap:nowrap; }
/* Fixed end, sized to its content. A max so a long theme name or tagline
   cannot eat the middle instead — past it they wrap, which they already do. */
.th_head_id       { display:flex; align-items:flex-start; gap:8px;
                    min-width:0; max-width:420px; flex:0 0 auto; }
.th_head_name     { font-size:17px; font-weight:600; color:#27251E; }
.th_head_tag      { font-size:12px; color:#6b7280; margin-top:2px; }
.th_head_chips    { display:flex; gap:6px; flex-wrap:wrap; margin-top:6px; }
/* The give. `min-width:0` so it can be squeezed below its buttons' natural
   row width — without it a flex item refuses to go under its min-content and
   the squeeze lands on its neighbours again. */
.th_head_c        { flex:1 1 auto; min-width:0; }
/* The other fixed end: three readouts, side by side, no wrap. Its width is a
   constant whatever the numbers say. flex-start, not center: the readouts are
   taller than a row of buttons, and centring against them left the buttons
   floating in the middle of the header instead of on the theme name's line. */
.th_head_right    { flex:0 0 auto; display:flex; align-items:flex-start; gap:14px;
                    flex-wrap:nowrap; justify-content:flex-end; }

/* ================================================================
   THE HEADER'S THREE NUMBERS.

   Replaces a single conviction dial, which showed one figure with no
   context: 62 out of what, resting on how many names, and is the gate
   even open? Each block carries a sub-line so the number is never
   alone, and the gate is tinted by STATE because open and closed mean
   opposite things and "not computed" means neither.
   ================================================================ */
/* In the header row now, not on a band of their own — so no padding of their
   own, and half the width they had as a standalone strip. */
.th_kpis          { display:flex; gap:8px; flex-wrap:nowrap; }
/* ONE DECLARED WIDTH, not a range. Between 96 and 120 the three blocks sized
   themselves to their own text, so the strip changed width as the numbers
   changed — and 'not computed' made it a different shape from a computed
   one. 112 fits the longest label ('Timing gate') at its 8.5px caps. */
.th_kpi {
	flex:0 0 112px;
	border:1px solid #e2e5ea; border-radius:6px; padding:6px 9px; background:#fbfbfc;
}
.th_kpi_k         { font-size:8.5px; font-weight:600; letter-spacing:0.4px; text-transform:uppercase;
                    color:#9aa0a8; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.th_kpi_v         { font-size:20px; font-weight:600; line-height:1.15; color:#27251E;
                    font-variant-numeric:tabular-nums; margin-top:1px; }
.th_kpi_s         { font-size:9.5px; color:#9aa0a8; margin-top:1px;
                    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

.th_kpi.is-open   .th_kpi_v { color:#0f9d76; }
.th_kpi.is-shut   .th_kpi_v { color:#b3261e; }
/* Not computed is GREY, never red — an unknown gate is not a closed one, and
   colouring it as one would read as a refusal nobody issued. */
.th_kpi.is-unknown .th_kpi_v { color:#c8ccd4; }

body.appbuilder-dark .th_kpi     { background:#2b2f35; border-color:#3a3f47; }
body.appbuilder-dark .th_kpi_v   { color:#e6e6ea; }
body.appbuilder-dark .th_kpi.is-open   .th_kpi_v { color:#4fd1a5; }
body.appbuilder-dark .th_kpi.is-shut   .th_kpi_v { color:#f0837a; }
body.appbuilder-dark .th_kpi.is-unknown .th_kpi_v { color:#5a616b; }
.th_head_actions  { display:flex; align-items:center; gap:8px; }
.th_fav           { border:0; background:transparent; cursor:pointer; padding:2px 4px; font-size:15px; color:#c8ccd4; line-height:1; }
.th_fav:hover     { color:#9aa0a8; }
.th_fav.is-on     { color:#e8a600; }

/* The governance ladder as four clickable rungs. Each shows its own state:
   past, here, open, or locked — so the obstacle is visible before it is hit,
   rather than only when the user walks into it. */
.th_ladder        { display:flex; gap:6px; margin:12px 0 0; padding-bottom:10px; }
.th_rung {
	flex:1; border:0; background:transparent; cursor:pointer; padding:0 2px;
	font-family:'Open Sans', sans-serif; font-size:10.5px; color:#9aa0a8; text-align:center;
}
.th_rung_bar      { display:block; height:4px; border-radius:2px; background:#e4e7ec; margin-bottom:5px; }
/* The label is `.th_rung_lbl` and the lock is inline inside it — both defined
   in the UI-corrections block at the end of this file. The old `.th_rung span`
   / `.th_rung_lock` pair is gone rather than overridden: it was the block-level
   span that pushed the lock onto its own line and knocked the locked rungs'
   bars out of alignment. */
.th_rung.is-past  > .th_rung_bar { background:#a8c6f5; }
.th_rung.is-past    { color:#6b7280; }
.th_rung.is-here  > .th_rung_bar { background:#269DF0; }
.th_rung.is-here    { color:#1c53b8; font-weight:600; }
.th_rung.is-open  > .th_rung_bar { background:#bfe3cd; }
.th_rung.is-open    { color:#116b3a; }
.th_rung.is-locked  { color:#b9bec6; cursor:not-allowed; }
.th_rung.is-locked:hover { color:#9aa0a8; }

/* Two columns at width, one below 1100px — the Canvas is a reading surface and
   a three-across grid at 1280 makes every panel too narrow for its prose. */
/* The right column is a FIXED 400px, matching the side panel on Evidence and
   the Value Chain. Conviction and Score breakdown are compact readouts — given
   half a wide screen they stretched their bars across a metre of whitespace
   while Admission and Lifecycle, which carry prose and a stage bar, were
   squeezed into the same width. */
.th_grid          { display:grid; grid-template-columns:1fr 400px; gap:12px; padding:12px; align-items:start; }
@media (max-width: 1100px) { .th_grid { grid-template-columns:1fr; } }
.th_col           { display:flex; flex-direction:column; gap:12px; min-width:0; }
.th_panel         { background:#fff; border:1px solid #e2e2e2; border-radius:6px; overflow:hidden; }
.th_panel_head    { display:flex; align-items:center; justify-content:space-between; gap:10px;
                    padding:9px 12px; border-bottom:1px solid #eceff4; background:#fbfbfc; }
.th_panel_head h2 { margin:0; font-size:12.5px; font-weight:600; color:#27251E; }
.th_panel_body    { padding:10px 12px; }
.th_muted         { color:#9aa0a8; font-size:11.5px; margin:0; }

/* Tri-state admission row. All three marks are always visible rather than one
   control cycling, because "not assessed" has to be reachable in one click from
   either answer — an analyst retracts a judgement as often as they make one. */
.th_check         { display:flex; gap:10px; padding:9px 0; border-bottom:1px solid #f0f2f5; }
.th_check:last-child { border-bottom:0; }
.th_check_marks   { display:flex; flex-direction:column; gap:3px; flex:0 0 auto; }
.th_mark {
	width:22px; height:20px; border-radius:4px; cursor:pointer; line-height:1;
	border:1px solid #e2e5ea; background:#fff; color:#b9bec6; font-size:11px;
}
.th_mark:hover        { border-color:#9aa0a8; }
.th_mark.is-ok.on     { background:#e6f4ec; border-color:#a8d8bd; color:#116b3a; }
.th_mark.is-no.on     { background:#fbeaea; border-color:#eeb4b0; color:#b3261e; }
.th_mark.is-none.on   { background:#eceff4; border-color:#c8ccd4; color:#6b7280; }
.th_check_body    { min-width:0; }
.th_check_label   { font-size:12.5px; font-weight:500; color:#27251E; }
.th_check_glyph   { display:none; }
.th_check_hint    { font-size:11px; color:#9aa0a8; margin-top:2px; line-height:1.45; }
.th_check_note    { font-size:11.5px; color:#41506b; margin-top:5px; cursor:pointer;
                    border-left:2px solid #d5dae1; padding-left:7px; line-height:1.45; }
.th_check_note:hover { border-left-color:#269DF0; }
.th_check_note i  { color:#b9bec6; }
.th_check.is-none .th_check_label { color:#6b7280; }

.th_rulebox       { display:flex; gap:8px; align-items:flex-start; font-size:11.5px; line-height:1.5;
                    background:#fdf3e3; border:1px solid #f0dcb4; color:#7a5410;
                    border-radius:5px; padding:9px 11px; }
.th_rulebox i     { margin-top:2px; opacity:0.7; }
/* min-width, because the longest option is "Commercialization" and the host
   sized itself to whatever was picked — so the widest label was the one that
   got clipped. */
.th_pick_host     { display:inline-flex; min-width:170px; }

/* ================================================================
   LIFECYCLE — the four-stage track.

   The picker says WHERE the theme is; the track says where that sits
   in the arc. Past and present are both filled because the arc is
   cumulative: a theme at Commercialization has been through the two
   before it.
   ================================================================ */
/* ================================================================
   THE THEME COMPOSITE, on the Canvas.

   An inline SVG rather than a charting library: two polylines over a
   fixed window, on ONE shared scale. Independent scales would make
   "above trend" a picture of nothing.
   ================================================================ */
.th_compsvg       { display:block; width:100%; height:150px; }
.th_comp_line     { fill:none; stroke:#e8a600; stroke-width:1.6;
                    vector-effect:non-scaling-stroke; stroke-linejoin:round; }
/* Dashed, so the trend line reads as a reference rather than a second
   instrument — and so the two stay apart for anyone who cannot separate
   the colours. */
.th_comp_ema      { fill:none; stroke:#4a90d9; stroke-width:1.3; stroke-dasharray:5 4;
                    vector-effect:non-scaling-stroke; }
.th_complegend    { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:8px;
                    font-size:10.5px; color:#6b7280; }
.th_comp_k1       { color:#b07d10; font-weight:600; }
.th_comp_k2       { color:#3a76b8; font-weight:600; }
.th_comp_n        { color:#9aa0a8; margin-left:auto; }

body.appbuilder-dark .th_comp_k1 { color:#e8c98a; }
body.appbuilder-dark .th_comp_k2 { color:#8fc0f0; }

.th_lcbar         { display:flex; gap:6px; margin-bottom:12px; }
.th_lcstep        { flex:1; min-width:0; text-align:center; }
.th_lcstep_bar    { display:block; height:4px; border-radius:2px; background:#e4e7ec; }
.th_lcstep_l      { display:block; margin-top:5px; font-size:10px; color:#9aa0a8;
                    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.th_lcstep.is-past .th_lcstep_bar { background:#d8a23a; }
.th_lcstep.is-here .th_lcstep_bar { background:#e8a600; }
.th_lcstep.is-here .th_lcstep_l   { color:#b07d10; font-weight:600; }

/* The strip under the rule: what this theme spans, and when it was last
   touched. Wraps rather than scrolls — a truncated sector list would be worse
   than a second row. */
.th_lcfoot        { display:flex; flex-wrap:wrap; gap:18px; margin-top:12px;
                    padding-top:10px; border-top:1px solid #eceff4; }
.th_lcfoot_b      { min-width:0; }
.th_lcfoot_k      { font-size:9px; font-weight:600; letter-spacing:0.5px; text-transform:uppercase;
                    color:#9aa0a8; margin-bottom:4px; }
.th_lcfoot_v      { display:flex; flex-wrap:wrap; gap:4px; font-size:11px; color:#27251E; }

body.appbuilder-dark .th_lcstep_bar        { background:#3a3f47; }
body.appbuilder-dark .th_lcstep.is-past .th_lcstep_bar { background:#8a6a24; }
body.appbuilder-dark .th_lcstep.is-here .th_lcstep_l   { color:#e8c98a; }
body.appbuilder-dark .th_lcfoot            { border-top-color:#3a3f47; }
body.appbuilder-dark .th_lcfoot_v          { color:#e6e6ea; }

.th_convbody      { display:flex; gap:16px; align-items:center; }
.th_kv            { display:flex; justify-content:space-between; font-size:11.5px; color:#6b7280; }
.th_kv b          { color:#27251E; }
.th_bar           { height:6px; border-radius:3px; background:#e4e7ec; overflow:hidden; margin-top:3px; }
.th_bar > i       { display:block; height:100%; background:#269DF0; }
.th_bar.is-pos > i{ background:#0f9d76; }
.th_score         { margin-bottom:10px; }
.th_composite     { display:flex; justify-content:space-between; align-items:baseline;
                    margin-top:12px; padding-top:10px; border-top:1px solid #eceff4;
                    font-size:10px; font-weight:600; letter-spacing:0.3px; text-transform:uppercase; color:#9aa0a8; }
.th_composite b   { font-size:17px; color:#27251E; letter-spacing:0; text-transform:none; }
.th_override      { display:flex; gap:7px; align-items:flex-start; font-size:11px; line-height:1.45;
                    padding:8px 12px; background:#eaf1fd; color:#1c53b8; border-top:1px solid #dbe6f9; }

.th_dial_track    { stroke:#e4e7ec; }
.th_dial_arc      { stroke:#269DF0; transition:stroke-dashoffset .5s cubic-bezier(.2,.7,.3,1); }
.th_dial_txt      { fill:#27251E; font-family:'Open Sans', sans-serif; font-weight:600; }

/* Bear Book */
.th_risk          { border:1px solid #e2e5ea; border-radius:5px; padding:9px 11px; margin-bottom:8px; }
.th_risk.is-nokill{ border-left:3px solid #e8a600; }
.th_risk_head     { display:flex; align-items:center; gap:8px; }
.th_risk_rank     { font-size:10px; font-weight:600; color:#9aa0a8; min-width:14px; }
.th_risk_title    { font-size:12.5px; font-weight:600; color:#27251E; flex:1; min-width:0; }
.th_risk_ctl      { display:flex; gap:4px; }
.th_risk_detail   { font-size:11.5px; color:#6b7280; margin-top:5px; line-height:1.5; }
.th_risk_kill     { font-size:11.5px; color:#41506b; margin-top:6px; line-height:1.5;
                    background:#f6f8fa; border-radius:4px; padding:6px 9px; }
.th_risk_kill b   { color:#27251E; }
.th_risk_trig     { color:#6b7280; font-style:italic; }
.th_risk_kill.is-missing { background:#fdf3e3; color:#7a5410; }

/* Skim overlay — pinned under the header, not a modal: it is meant to be read
   while the ladder above it is still visible. */
/* The 60-second skim. A DIALOG, not a card wedged into the header — it is
   something you consult and dismiss, and inline it pushed the whole workspace
   down every time you glanced at it. No border or shadow of its own: the
   popup already provides those. */
.th_skim          { overflow:auto; }
.th_skim_row      { display:flex; gap:16px; align-items:center; margin-bottom:12px; }
.th_skim_k,
.th_skim_sec h4   { margin:0 0 4px; font-size:10px; font-weight:600; letter-spacing:0.4px;
                    text-transform:uppercase; color:#9aa0a8; }
.th_skim_sec      { margin-bottom:13px; }
.th_skim_sec ul   { margin:0; padding-left:16px; font-size:11.5px; color:#41506b; line-height:1.6; }
.th_skim_sec li   { margin-bottom:5px; }
.th_skim_chips    { display:flex; gap:6px; flex-wrap:wrap; margin:0 0 14px; }
/* Confidence, and the "a worry, not a risk" marker: present but subordinate to
   the claim itself. */
.th_skim_conf     { color:#9aa0a8; }

/* Lead entry: the numbers you would actually act on, in a fixed grid so Zone
   and Stop line up under each other rather than reflowing with their length. */
.th_skim_grid     { display:grid; grid-template-columns:1fr 1fr; gap:5px 18px; margin-top:5px; }
.th_skim_cell     { display:flex; align-items:baseline; justify-content:space-between;
                    gap:10px; font-size:11.5px; border-bottom:1px solid #f0f2f5; padding-bottom:3px; }
.th_skim_cell span{ color:#9aa0a8; }
.th_skim_cell b   { color:#27251E; font-variant-numeric:tabular-nums; }

body.appbuilder-dark .theme-panel     { background:#1f2226; }
body.appbuilder-dark .th_head         { background:#26292e; border-bottom-color:#3a3f47; }
body.appbuilder-dark .th_head_name    { color:#e6e6ea; }
body.appbuilder-dark .th_head_tag     { color:#9aa0ac; }
body.appbuilder-dark .th_fav          { color:#565b64; }
body.appbuilder-dark .th_fav:hover    { color:#8b919b; }
body.appbuilder-dark .th_fav.is-on    { color:#f0b400; }
body.appbuilder-dark .th_rung         { color:#8b919b; }
body.appbuilder-dark .th_rung_bar     { background:#3a3f47; }
body.appbuilder-dark .th_rung.is-past > .th_rung_bar { background:#33507d; }
body.appbuilder-dark .th_rung.is-past   { color:#9aa0ac; }
body.appbuilder-dark .th_rung.is-here > .th_rung_bar { background:#4a9eff; }
body.appbuilder-dark .th_rung.is-here   { color:#8ab4f8; }
body.appbuilder-dark .th_rung.is-open > .th_rung_bar { background:#2f5a42; }
body.appbuilder-dark .th_rung.is-open   { color:#7ddb9a; }
body.appbuilder-dark .th_rung.is-locked { color:#565b64; }
body.appbuilder-dark .th_panel        { background:#26292e; border-color:#3a3f47; }
body.appbuilder-dark .th_panel_head   { background:#2b2f35; border-bottom-color:#3a3f47; }
body.appbuilder-dark .th_panel_head h2{ color:#e6e6ea; }
body.appbuilder-dark .th_muted        { color:#8b919b; }
body.appbuilder-dark .th_check        { border-bottom-color:#33373d; }
body.appbuilder-dark .th_check_label  { color:#e6e6ea; }
body.appbuilder-dark .th_check_hint   { color:#8b919b; }
body.appbuilder-dark .th_check_note   { color:#a8bdd4; border-left-color:#4a4f57; }
body.appbuilder-dark .th_check_note i { color:#6b7280; }
body.appbuilder-dark .th_mark         { background:#2b2f35; border-color:#4a4f57; color:#6b7280; }
body.appbuilder-dark .th_mark.is-ok.on   { background:#22392c; border-color:#2f5a42; color:#7ddb9a; }
body.appbuilder-dark .th_mark.is-no.on   { background:#3a2626; border-color:#5e3535; color:#f09a95; }
body.appbuilder-dark .th_mark.is-none.on { background:#33373d; border-color:#565b64; color:#aab2bb; }
body.appbuilder-dark .th_rulebox      { background:#3a3226; border-color:#5e4327; color:#e0b871; }
body.appbuilder-dark .th_kv           { color:#9aa0ac; }
body.appbuilder-dark .th_kv b         { color:#e6e6ea; }
body.appbuilder-dark .th_bar          { background:#3a3f47; }
body.appbuilder-dark .th_composite    { color:#9aa0ac; border-top-color:#3a3f47; }
body.appbuilder-dark .th_composite b  { color:#e6e6ea; }
body.appbuilder-dark .th_override     { background:#1e2c44; color:#8ab4f8; border-top-color:#33507d; }
body.appbuilder-dark .th_dial_track   { stroke:#3a3f47; }
body.appbuilder-dark .th_dial_arc     { stroke:#4a9eff; }
body.appbuilder-dark .th_dial_txt     { fill:#e6e6ea; }
body.appbuilder-dark .th_risk         { border-color:#3a3f47; }
body.appbuilder-dark .th_risk_rank    { color:#8b919b; }
body.appbuilder-dark .th_risk_title   { color:#e6e6ea; }
body.appbuilder-dark .th_risk_detail  { color:#9aa0ac; }
body.appbuilder-dark .th_risk_kill    { background:#2b2f35; color:#a8bdd4; }
body.appbuilder-dark .th_risk_kill b  { color:#e6e6ea; }
body.appbuilder-dark .th_risk_trig    { color:#8b919b; }
body.appbuilder-dark .th_risk_kill.is-missing { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .th_skim_k,
body.appbuilder-dark .th_skim_sec h4  { color:#9aa0ac; }
body.appbuilder-dark .th_skim_sec ul  { color:#c3c8d0; }
body.appbuilder-dark .th_skim_conf    { color:#8b919b; }
body.appbuilder-dark .th_skim_cell    { border-bottom-color:#3a3f47; }
body.appbuilder-dark .th_skim_cell b  { color:#e6e6ea; }

/* ================================================================
   RESEARCH Ship 2 — Value Chain + Evidence tabs.

   Both tabs are a wide main panel plus a fixed-width side panel, which
   is the shape the work has: you scan a list and inspect one item. The
   side panel is a fixed 340px rather than a percentage so the main
   panel absorbs the window width — the claim text and the chain columns
   are what benefit from it.
   ================================================================ */
/* The CONTAINER owns the spacing — `gap` between the halves, `padding` around
   them — exactly as `.th_grid` does on the Canvas tab. Per-panel margins were
   tried first and were the wrong model: each half had to know what sat next to
   it, the two inner margins met at zero, and the panels read as one welded
   block. A container that owns its own gutter cannot get that wrong. */
.th_chainwrap, .th_evwrap {
	display:flex; align-items:flex-start; min-height:100%;
	gap:12px; padding:12px;
}
.th_split_main            { flex:1; min-width:0; }
/* 400px: the side panel carries provenance blocks, entry numbers and score
   breakdowns, all of which wrapped awkwardly at 340. */
.th_nodepanel             { flex:0 0 400px; max-width:400px; }
@media (max-width: 1100px) {
	.th_chainwrap, .th_evwrap { flex-direction:column; }
	.th_nodepanel { flex:1 1 auto; max-width:none; width:100%; }
}

/* ================================================================
   EVIDENCE — two independently scrolling columns.

   Claims and Sources are both long lists that grow without limit, and
   under the shared model (one scroller on `.th_body`) reading to the
   bottom of one meant scrolling the other off the screen, with both
   headers gone. Each column now fills the page and scrolls INSIDE
   itself, so the two headers stay put and the lists move independently.

   Scoped to the evidence tab on purpose: Canvas is a reading surface
   whose panels are meant to flow into one page scroller, and the Value
   Chain's columns are short. Only this tab has the problem.

   AND SCOPED TO THIS WORKSPACE (Ship 6). These rules used to key on
   `.th_body[data-tabbody='evidence']`, and the DOSSIER's tab bodies carry
   `.th_body` too — so the selector matched both workspaces, and the
   dossier's evidence tab had to be named something else to avoid
   inheriting a two-column layout written for this one. `.th_ws_body`
   marks the theme workspace's bodies; the ids are free again on both
   sides, and the next tab either one adds cannot collide by accident.
   ================================================================ */
.th_ws_body[data-tabbody='evidence']            { overflow:hidden; }

/* BORDER-BOX, and it is load-bearing. This stylesheet has no global
   `* { box-sizing: border-box }` — only per-rule declarations — so
   `.th_evwrap`'s `height:100%` was the parent's height PLUS its own 24px of
   padding, and both columns hung exactly that far below the window. The
   symptom looks like a broken flex chain and is arithmetic. */
.th_ws_body[data-tabbody='evidence'],
.th_ws_body[data-tabbody='evidence'] *          { box-sizing:border-box; }

.th_ws_body[data-tabbody='evidence'] .th_evwrap { height:100%; min-height:0; align-items:stretch; }

/* Every link in the chain needs min-height:0 — a flex child's default
   min-height is `auto`, which means "as tall as my content" and silently
   defeats every overflow below it. */
.th_ws_body[data-tabbody='evidence'] .th_split_main,
.th_ws_body[data-tabbody='evidence'] .th_nodepanel {
	display:flex; flex-direction:column; min-height:0;
}
.th_ws_body[data-tabbody='evidence'] .th_panel {
	flex:1 1 auto; display:flex; flex-direction:column; min-height:0;
}
.th_ws_body[data-tabbody='evidence'] .th_panel_head,
.th_ws_body[data-tabbody='evidence'] .th_evfilters { flex:0 0 auto; }
.th_ws_body[data-tabbody='evidence'] .th_panel_body {
	flex:1 1 auto; overflow-y:auto; min-height:0;
}

@media (max-width: 1100px) {
	/* Stacked, the two columns cannot both own the height — fall back to
	   one page scroller rather than two 200px-tall boxes. */
	.th_ws_body[data-tabbody='evidence']            { overflow:auto; }
	.th_ws_body[data-tabbody='evidence'] .th_evwrap { height:auto; }
	.th_ws_body[data-tabbody='evidence'] .th_panel_body { overflow:visible; }
}

/* Value chain: three layer columns. */
.th_chaincols       { display:grid; grid-template-columns:repeat(3, 1fr); gap:10px; }
.th_chaincol        { min-width:0; }
.th_chaincol_h      { display:flex; align-items:center; justify-content:space-between;
                      font-size:10px; font-weight:600; letter-spacing:0.3px; text-transform:uppercase;
                      color:#9aa0a8; margin-bottom:6px; }
.th_chaincol_empty  { font-size:11px; color:#b9bec6; padding:8px 0; }

.th_node {
	display:block; width:100%; text-align:left; cursor:pointer;
	border:1px solid #e2e5ea; border-radius:5px; background:#fff;
	padding:8px 9px; margin-bottom:7px; font-family:'Open Sans', sans-serif;
}
.th_node:hover      { border-color:#9aa0a8; }
/* 2px ring, the same focus clue a field gives — but faked as 1px border + 1px
   INSET shadow rather than an actual 2px border. A real border-width change
   grows the box, so selecting a card would nudge every card below it by a
   pixel. Inset paints inside the existing box and nothing moves. */
.th_node.is-sel     { border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }
/* A choke point is the single most consequential thing on this map, so it
   carries a left rule in the same amber the Bear Book uses for a missing kill
   condition — both mean "look here before you go further". */
.th_node.is-choke   { border-left:3px solid #e8a600; }
/* min-height so a card is the same height with or without the CHOKE chip.
   Without it the row collapses to the name's line box and choke-point cards
   stand ~6px taller, which reads as a layout bug rather than as emphasis.
   21px = the chip's own height (10px x 1.5 line-height + 3px padding twice). */
.th_node_top        { display:flex; align-items:center; justify-content:space-between; gap:6px;
                      min-height:21px; }
.th_node_name       { font-size:12px; font-weight:600; color:#27251E;
                      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.th_node_meta       { display:flex; flex-wrap:wrap; gap:9px; font-size:10px; color:#9aa0a8; margin:4px 0 5px; }
.th_node_meta i     { opacity:0.7; }

.th_nodeev          { margin-top:12px; padding-top:10px; border-top:1px solid #eceff4; }
.th_nodeev h4       { margin:0 0 5px; font-size:10px; font-weight:600; letter-spacing:0.3px;
                      text-transform:uppercase; color:#9aa0a8; }
.th_nodeev ul       { margin:0; padding-left:16px; font-size:11.5px; color:#41506b; line-height:1.55; }

/* Evidence: filter chips reuse the Radar's .rs_fchip so the two filter rows in
   the product look like one control, not two conventions. */
/* A fixed sub-header between the panel title and the scrolling list — NOT a
   sticky element inside the list. Sticky was tried and could not cover the
   scroll container's own top padding, so claims were visible scrolling through
   the band above the chips. */
.th_evfilters       { flex:0 0 auto; display:flex; align-items:center; gap:4px; flex-wrap:wrap;
                      padding:8px 12px; background:#fff; border-bottom:1px solid #eceff4; }
body.appbuilder-dark .th_evfilters { background:#26292e; border-bottom-color:#3a3f47; }

.th_claim           { border:1px solid #e2e5ea; border-radius:5px; padding:9px 11px; margin-bottom:8px;
                      cursor:pointer; }
/* Selection is the SAME treatment as a value-chain node, because it means the
   same thing in both places: this is the row the right panel is describing. */
.th_claim:hover     { border-color:#9aa0a8; }
.th_claim.is-sel    { border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }
/* A rejected claim is kept and dimmed rather than hidden: "we looked at this
   and said no" is a research finding, and a list that silently drops it invites
   the same claim being proposed again next quarter. */
.th_claim.is-rejected { opacity:0.55; }
.th_claim_head      { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.th_claim_ctl       { display:flex; gap:4px; margin-left:auto; }
.th_claim_text      { font-size:12.5px; color:#27251E; margin-top:6px; line-height:1.55; }
.th_claim_meta      { display:flex; flex-wrap:wrap; align-items:center; gap:12px;
                      font-size:10.5px; color:#9aa0a8; margin-top:6px; }
.th_claim_src       { color:#1c53b8; cursor:pointer; }
.th_claim_src:hover { text-decoration:underline; }
.th_conf            { display:inline-flex; align-items:center; gap:6px; }
.th_conf_bar        { display:inline-block; width:52px; height:5px; border-radius:3px;
                      background:#e4e7ec; overflow:hidden; }
.th_conf_bar > b    { display:block; height:100%; background:#269DF0; }
/* THE FALSIFIER, everywhere it appears.
   ================================================================
   Red, with a left edge and its own label line. Not because a
   falsifier is bad — it is the best thing on the card — but because
   it is the KILL LINE: the observation that would end the thesis.
   Giving it the same quiet grey as a note let the eye slide past the
   one sentence on a claim that is supposed to stop you.

   A MISSING falsifier keeps amber. Both states must be legible at a
   glance and they mean opposite things: red is "here is what would
   disprove this", amber is "nobody has said what would". */
.th_fals,
.th_claim_fals      { font-size:11.5px; line-height:1.5; margin-top:7px; padding:7px 10px;
                      color:#7a2620; background:#fdf2f2;
                      border-left:3px solid #c0392b; border-radius:3px; }
/* The label sits on its own line, small and uppercase — it names the
   block without competing with the sentence that matters. */
.th_fals_k,
.th_claim_fals b    { display:block; font-size:9.5px; font-weight:600; letter-spacing:0.5px;
                      text-transform:uppercase; color:#c0392b; margin-bottom:3px; }

/* In the source panel the falsifier is followed by another section head, so it
   needs room under it; in the claims list it is the last thing on the card and
   the card's own padding already provides it. */
.th_fals            { margin-bottom:14px; }

.th_fals.is-missing,
.th_claim_fals.is-missing { color:#7a5410; background:#fdf3e3; border-left-color:#e8a600; }
.th_fals.is-missing .th_fals_k,
.th_claim_fals.is-missing b { color:#a8801f; }

/* Vault documents. */
.th_doc             { border:1px solid #e2e5ea; border-radius:5px; padding:8px 9px; margin-bottom:7px; }
.th_doc_top         { display:flex; align-items:center; justify-content:space-between; gap:6px; }
.th_doc_title       { font-size:11.5px; font-weight:600; color:#27251E;
                      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.th_doc_meta        { display:flex; flex-wrap:wrap; gap:10px; font-size:10px; color:#9aa0a8; margin-top:4px; }
.th_doc_hash        { font-family:Menlo, Consolas, monospace; font-size:9.5px; color:#b9bec6; }

/* The source popup: claim, verbatim quote, provenance. */
.th_srcdlg          { font-family:'Open Sans', sans-serif; }
.th_srcdlg_claim    { font-size:13px; font-weight:600; color:#27251E; line-height:1.5; margin-bottom:10px; }
.th_srcdlg_quote    { margin:0 0 12px; padding:9px 12px; border-left:3px solid #269DF0;
                      background:#f6f8fa; font-size:12px; color:#41506b; line-height:1.6;
                      white-space:pre-wrap; max-height:220px; overflow:auto; }
.th_srcdlg_prov     { border-top:1px solid #eceff4; padding-top:9px; }
.th_srcdlg_prov .th_kv { margin-bottom:4px; }

body.appbuilder-dark .th_chaincol_h    { color:#9aa0ac; }
body.appbuilder-dark .th_chaincol_empty{ color:#6b7280; }
body.appbuilder-dark .th_node          { background:#2b2f35; border-color:#3a3f47; }
body.appbuilder-dark .th_node:hover    { border-color:#6b7280; }
body.appbuilder-dark .th_node.is-sel   { border-color:#4a9eff; box-shadow:0 0 0 1px #4a9eff inset; }
body.appbuilder-dark .th_node.is-choke { border-left-color:#f0b400; }
body.appbuilder-dark .th_node_name     { color:#e6e6ea; }
body.appbuilder-dark .th_node_meta     { color:#8b919b; }
body.appbuilder-dark .th_nodeev        { border-top-color:#3a3f47; }
body.appbuilder-dark .th_nodeev h4     { color:#9aa0ac; }
body.appbuilder-dark .th_nodeev ul     { color:#c3c8d0; }
body.appbuilder-dark .th_claim         { border-color:#3a3f47; }
body.appbuilder-dark .th_claim:hover   { border-color:#6b7280; }
body.appbuilder-dark .th_claim.is-sel  { border-color:#4a9eff; box-shadow:0 0 0 1px #4a9eff inset; }
body.appbuilder-dark .th_claim_text    { color:#e6e6ea; }
body.appbuilder-dark .th_claim_meta    { color:#8b919b; }
body.appbuilder-dark .th_claim_src     { color:#8ab4f8; }
body.appbuilder-dark .th_conf_bar      { background:#3a3f47; }
body.appbuilder-dark .th_fals,
body.appbuilder-dark .th_claim_fals    { background:#33201f; color:#e8b4ae; border-left-color:#c0392b; }
body.appbuilder-dark .th_fals_k,
body.appbuilder-dark .th_claim_fals b  { color:#f0837a; }
body.appbuilder-dark .th_fals.is-missing,
body.appbuilder-dark .th_claim_fals.is-missing { background:#3a3226; color:#e0b871; border-left-color:#e8a600; }
body.appbuilder-dark .th_fals.is-missing .th_fals_k,
body.appbuilder-dark .th_claim_fals.is-missing b { color:#e8c98a; }
body.appbuilder-dark .th_doc           { border-color:#3a3f47; }
body.appbuilder-dark .th_doc_title     { color:#e6e6ea; }
body.appbuilder-dark .th_doc_meta      { color:#8b919b; }
body.appbuilder-dark .th_doc_hash      { color:#6b7280; }
body.appbuilder-dark .th_srcdlg_claim  { color:#e6e6ea; }
body.appbuilder-dark .th_srcdlg_quote  { background:#2b2f35; border-left-color:#4a9eff; color:#c3c8d0; }
body.appbuilder-dark .th_srcdlg_prov   { border-top-color:#3a3f47; }

/* ================================================================
   RESEARCH Ship 3 — Screen, Basket, entry design, timing gate.
   ================================================================ */

/* Screen: a toolbar over a full-height grid. The grid is the screener's own
   w2gridExt, so sorting and selection behave exactly as they do on the
   Screener tab — the Screen IS the screener, scoped to one theme. */
.th_screenwrap   { display:flex; flex-direction:column; height:100%; }
.th_screenbar    { flex:0 0 auto; display:flex; align-items:center; gap:8px; flex-wrap:wrap;
                   padding:10px 12px; border-bottom:1px solid #e2e2e2; background:#fff; }
.th_screenbar_sp { flex:0 0 12px; }
.th_screenhint   { font-size:10.5px; color:#9aa0a8; max-width:520px; line-height:1.4; }
.th_screengrid   { flex:1 1 auto; min-height:320px; }
/* The status line under the bar: what the analytics buttons can do right now,
   and what the last recompute came back with. Hidden while empty. */
.th_screennote   { flex:0 0 auto; display:flex; align-items:flex-start; gap:8px; padding:6px 12px;
                   font-size:11.5px; line-height:1.45; color:#41506b; background:#f7f8fa; border-bottom:1px solid #e2e2e2; }
.th_screennote:empty   { display:none; }
.th_screennote i       { margin-top:2px; color:#7b8496; }
.th_screennote.is-warn { color:#7a4f00; background:#fff7e3; }
.th_screennote.is-warn i { color:#d18a00; }
.th_screennote.is-ok i { color:#2e7d32; }
body.appbuilder-dark .th_screennote         { color:#c9ccd2; background:#23272e; border-bottom-color:#333a46; }
body.appbuilder-dark .th_screennote i       { color:#8b919b; }
body.appbuilder-dark .th_screennote.is-warn { color:#f0c674; background:#332a14; }
body.appbuilder-dark .th_screennote.is-warn i { color:#e0a92a; }
body.appbuilder-dark .th_screennote.is-ok i { color:#8fd19e; }

/* The basket star, in the grid's first column. Deliberately NOT a checkbox:
   the row-selection column sits right beside it and two checkboxes meaning
   different things in adjacent columns is a trap. */
.th_bstar        { cursor:pointer; color:#c8ccd4; font-size:13px; }
.th_bstar:hover  { color:#9aa0a8; }
.th_bstar.is-on  { color:#e8a600; }

/* Keyword-derived purity carries a badge everywhere it is shown. The number is
   a guess, and a screen that cannot say so is the single most dangerous thing
   in this product.

   SHIP 7 ADDED THE OTHER KIND. Purity can now be MEASURED from the name's own
   revenue segments, so the absence of a `kw` badge would otherwise have to
   mean both "measured" and "typed by hand". `rev` is the amber badge's
   opposite: same shape, so the eye reads them as one column of provenance. */
.th_kwbadge {
	display:inline-block; font-size:8.5px; font-weight:700; letter-spacing:0.3px;
	text-transform:uppercase; padding:1px 4px; border-radius:3px; margin-left:4px;
	background:#fdf3e3; color:#9a6a10; vertical-align:middle;
}
.th_kwbadge.is-measured { background:#e6f4ec; color:#116b3a; }
body.appbuilder-dark .th_kwbadge.is-measured { background:#22392c; color:#7ddb9a; }

/* Basket cards: identity row, then the entry design as a fact grid. */
.th_bcard        { border:1px solid #e2e5ea; border-radius:5px; padding:9px 11px; margin-bottom:8px; }
.th_bcard_head   { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.th_bcard_id     { display:flex; flex-direction:column; min-width:0; }
.th_bcard_sym    { font-size:12.5px; font-weight:600; color:#27251E; }
.th_bcard_nm     { font-size:10.5px; color:#9aa0a8; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:220px; }
.th_bcard_ctl    { display:flex; gap:4px; margin-left:auto; }
.th_bcard_trig   { font-size:11.5px; color:#41506b; margin-top:6px; line-height:1.5;
                   background:#f6f8fa; border-radius:4px; padding:5px 9px; }
.th_bcard_trig b { color:#27251E; }

.th_entrygrid    { display:grid; grid-template-columns:repeat(auto-fit, minmax(84px, 1fr));
                   gap:6px 10px; margin-top:8px; }
.th_ei           { min-width:0; }
.th_ei span      { display:block; font-size:9.5px; font-weight:600; letter-spacing:0.3px;
                   text-transform:uppercase; color:#9aa0a8; }
.th_ei b         { display:block; font-size:12px; color:#27251E; margin-top:1px; white-space:nowrap; }

/* The constraints panel's positive state. Green is earned here — every warning
   the checker knows about has been looked at. */
.th_okbox        { display:flex; gap:8px; align-items:flex-start; font-size:11.5px; line-height:1.5;
                   background:#e6f4ec; border:1px solid #bfe3cd; color:#116b3a;
                   border-radius:5px; padding:9px 11px; margin-bottom:10px; }
.th_okbox i      { margin-top:2px; opacity:0.8; }

/* Timing gate. */
.th_gate_banner  { text-align:center; padding:9px; border-radius:5px; margin-bottom:10px;
                   font-size:12px; letter-spacing:0.5px; }
.th_gate_banner.is-open    { background:#e6f4ec; color:#116b3a; border:1px solid #bfe3cd; }
.th_gate_banner.is-shut    { background:#fbeaea; color:#b3261e; border:1px solid #eeb4b0; }
/* UNDETERMINED is its own colour, not a shade of closed. A gate that cannot be
   computed is not a gate that says no, and rendering the two the same way is
   how a theme gets held back by missing data nobody noticed. */
.th_gate_banner.is-unknown { background:#eceff4; color:#6b7280; border:1px solid #d5dae1; }

.th_gateleg      { padding:7px 0; border-bottom:1px solid #f0f2f5; }
.th_gateleg:last-child { border-bottom:0; }
.th_gateleg_top  { display:flex; align-items:center; justify-content:space-between; gap:8px;
                   font-size:11.5px; color:#41506b; }
.th_spark        { margin:2px 0 6px; }
.th_sparksvg     { width:100%; height:70px; display:block; }
.th_spark_line   { stroke:#269DF0; stroke-width:1.6; }
.th_spark_ema    { stroke:#9aa0a8; stroke-width:1.2; }

/* Pine export dialog. */
.th_pinedlg      { font-family:'Open Sans', sans-serif; height:100%; display:flex; flex-direction:column; }
.th_pinedlg_bar  { flex:0 0 auto; display:flex; align-items:center; margin-bottom:9px; }
.th_pinesrc      { flex:1 1 auto; margin:0; overflow:auto; background:#f6f8fa;
                   border:1px solid #e2e5ea; border-radius:5px; padding:11px;
                   font-family:Menlo, Consolas, monospace; font-size:11.5px; line-height:1.55;
                   color:#27251E; white-space:pre; }

body.appbuilder-dark .th_screenbar   { background:#26292e; border-bottom-color:#3a3f47; }
body.appbuilder-dark .th_screenhint  { color:#8b919b; }
body.appbuilder-dark .th_bstar       { color:#565b64; }
body.appbuilder-dark .th_bstar:hover { color:#8b919b; }
body.appbuilder-dark .th_bstar.is-on { color:#f0b400; }
body.appbuilder-dark .th_kwbadge     { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .th_bcard       { border-color:#3a3f47; }
body.appbuilder-dark .th_bcard_sym   { color:#e6e6ea; }
body.appbuilder-dark .th_bcard_nm    { color:#8b919b; }
body.appbuilder-dark .th_bcard_trig  { background:#2b2f35; color:#a8bdd4; }
body.appbuilder-dark .th_bcard_trig b{ color:#e6e6ea; }
body.appbuilder-dark .th_ei span     { color:#9aa0ac; }
body.appbuilder-dark .th_ei b        { color:#e6e6ea; }
body.appbuilder-dark .th_okbox       { background:#22392c; border-color:#2f5a42; color:#7ddb9a; }
body.appbuilder-dark .th_gate_banner.is-open    { background:#22392c; color:#7ddb9a; border-color:#2f5a42; }
body.appbuilder-dark .th_gate_banner.is-shut    { background:#3a2626; color:#f09a95; border-color:#5e3535; }
body.appbuilder-dark .th_gate_banner.is-unknown { background:#33373d; color:#aab2bb; border-color:#4a4f57; }
body.appbuilder-dark .th_gateleg     { border-bottom-color:#33373d; }
body.appbuilder-dark .th_gateleg_top { color:#c3c8d0; }
body.appbuilder-dark .th_spark_line  { stroke:#4a9eff; }
body.appbuilder-dark .th_spark_ema   { stroke:#6b7280; }
body.appbuilder-dark .th_pinesrc     { background:#1f2226; border-color:#3a3f47; color:#d6dae0; }

/* ================================================================
   RESEARCH Ship 4 — the trading bridge.

   Four numbered steps rather than four buttons in a row: the hand-off
   is a SEQUENCE (universe → strategy → evidence → portfolio) and each
   step gates the next. Showing them as a list with their locks visible
   is the same choice the promotion ladder makes on the header.
   ================================================================ */
.th_step         { border:1px solid #e2e5ea; border-radius:6px; padding:11px 13px; margin-bottom:10px; }
.th_step.is-done { border-left:3px solid #0f9d76; }
.th_step.is-blocked { background:#fbfbfc; }
.th_step_head    { display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.th_step_n {
	flex:0 0 auto; width:20px; height:20px; border-radius:50%;
	background:#eceff4; color:#6b7280; font-size:10.5px; font-weight:700;
	display:inline-flex; align-items:center; justify-content:center;
}
.th_step.is-done .th_step_n { background:#e6f4ec; color:#116b3a; }
.th_step_t       { font-size:12.5px; font-weight:600; color:#27251E; }
.th_step_head .pf_btn { margin-left:auto; }
.th_step_blocked { display:flex; gap:7px; align-items:flex-start; font-size:11px; line-height:1.5;
                   color:#7a5410; background:#fdf3e3; border-radius:4px; padding:7px 9px; margin-top:8px; }
.th_step_note    { font-size:11px; color:#9aa0a8; line-height:1.5; margin-top:7px; }

/* What an export produced. The name is a deep link — a watchlist belongs to
   Charts, a backtest to the Lab, a portfolio to Portfolios, and each of those
   screens already does its job better than a copy in here would. */
.th_targets      { margin-top:8px; }
.th_target       { display:flex; align-items:center; gap:8px; font-size:11.5px;
                   padding:5px 0; border-bottom:1px solid #f0f2f5; }
.th_target:last-child { border-bottom:0; }
.th_target i     { color:#9aa0a8; }
.th_target_n     { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.th_target_v     { font-family:Menlo, Consolas, monospace; font-size:10px; color:#6b7280;
                   background:#eceff4; border-radius:3px; padding:1px 5px; }
.th_target_d     { font-size:10px; color:#9aa0a8; }

.th_btlist       { margin-top:8px; }
.th_bt           { border:1px solid #e2e5ea; border-radius:5px; padding:8px 10px; margin-bottom:7px; }
/* The nominated run is the one BACKING the theme's number. It earns a rule. */
.th_bt.is-nom    { border-left:3px solid #269DF0; background:#f7fbff; }
.th_bt_head      { display:flex; align-items:center; gap:7px; flex-wrap:wrap; }
.th_bt_n         { font-size:12px; font-weight:600; color:#27251E; }

body.appbuilder-dark .th_step          { border-color:#3a3f47; }
body.appbuilder-dark .th_step.is-done  { border-left-color:#2f8f6d; }
body.appbuilder-dark .th_step.is-blocked { background:#24272c; }
body.appbuilder-dark .th_step_n        { background:#33373d; color:#aab2bb; }
body.appbuilder-dark .th_step.is-done .th_step_n { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .th_step_t        { color:#e6e6ea; }
body.appbuilder-dark .th_step_blocked  { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .th_step_note     { color:#8b919b; }
body.appbuilder-dark .th_target        { border-bottom-color:#33373d; }
body.appbuilder-dark .th_target i      { color:#6b7280; }
body.appbuilder-dark .th_target_v      { background:#33373d; color:#aab2bb; }
body.appbuilder-dark .th_target_d      { color:#8b919b; }
body.appbuilder-dark .th_bt            { border-color:#3a3f47; }
body.appbuilder-dark .th_bt.is-nom     { border-left-color:#4a9eff; background:#1e2530; }
body.appbuilder-dark .th_bt_n          { color:#e6e6ea; }

/* ================================================================
   RESEARCH Ship 5 — the pipeline panel.

   Reuses the bridge's numbered-step vocabulary (.th_step) on purpose:
   both screens are a SEQUENCE whose steps have state, and giving them
   two visual languages would imply they are different kinds of thing.
   ================================================================ */
.th_runidea {
	font-size:12px; color:#41506b; line-height:1.55;
	background:#f6f8fa; border-left:3px solid #269DF0; border-radius:4px;
	padding:9px 12px; margin-bottom:11px;
}
.th_budget       { margin-bottom:11px; }
/* The cap bar turns red AT the cap rather than past it — the run stops short of
   overshooting, so "full" is the terminal state and there is no over-fill to
   render. */
.th_budget .th_bar.is-over > i { background:#b3261e; }

body.appbuilder-dark .th_runidea { background:#2b2f35; border-left-color:#4a9eff; color:#c3c8d0; }
body.appbuilder-dark .th_budget .th_bar.is-over > i { background:#f09a95; }

/* ================================================================
   RESEARCH Ship 6 — document actions and the document modal.

   The Documents TAB is gone: documents are files in the theme's dataroom,
   browsed with the shared FilesClass. What remains here is the header's
   generate buttons and the modal a freshly generated document opens in.
   ================================================================ */

/* The header's action cluster. Wraps rather than scrolls — on a narrow
   window a second row of buttons is readable; a horizontally scrolling
   toolbar hides the button on the end with nothing to say it is there. */
.th_head_acts {
	display:flex; align-items:center; gap:6px; flex-wrap:wrap; justify-content:flex-end;
}

/* The reference date (Ship 6). Sits under the action cluster rather than
   among the KPIs: it is a fact ABOUT the record, not one OF it, and beside
   three numbers it read as a fourth. Three bands — fresh, ageing, stale or
   past its review cadence — because "how old" is the question, and a bare
   date makes the reader do the arithmetic. */
.th_asof {
	display:flex; align-items:center; justify-content:flex-end; gap:5px;
	margin-top:5px; font-size:10.5px; color:#6b7280;
}
.th_asof b       { font-weight:700; color:#3d8f5e; }
.th_asof .fa     { font-size:10px; }
.th_asof.is-warn b { color:#9a6a10; }
.th_asof.is-shut b,
.th_asof.is-shut .fa-exclamation-triangle { color:#b3261e; }
body.appbuilder-dark .th_asof         { color:#8d949c; }
body.appbuilder-dark .th_asof b       { color:#5fb37f; }
body.appbuilder-dark .th_asof.is-warn b { color:#e8c07a; }
body.appbuilder-dark .th_asof.is-shut b,
body.appbuilder-dark .th_asof.is-shut .fa-exclamation-triangle { color:#f0a49d; }

/* Anchor for the staleness dot. */
.th_genbtn { position:relative; }

/* "The theme has moved since this was last generated."
   A dot rather than a chip: it sits on the button that fixes it, and a
   word would push the three generate buttons onto their own row. */
.th_staledot {
	position:absolute; top:3px; right:3px;
	width:7px; height:7px; border-radius:50%;
	background:#e0a030; box-shadow:0 0 0 2px #fff;
}

/* The document modal. The surround follows the theme; the page inside
   stays white, because it is a printable document and a dark memo would
   print as one. */
/* Column so a caveat banner can sit ABOVE the page without the iframe's
   height:100% pushing it out of the modal. */
.th_docmodal {
	width:100%; height:100%; background:#e9ecf1; padding:14px; overflow:auto;
	box-sizing:border-box; display:flex; flex-direction:column; gap:10px;
}
.th_docmodal iframe {
	display:block; width:100%; flex:1 1 auto; min-height:520px; margin:0 auto;
	max-width:900px; border:0; background:#fff; border-radius:3px;
	box-shadow:0 2px 12px rgba(0,0,0,.13);
}
/* ================================================================
   RESEARCH — the Sources list (Evidence tab).

   One live list, in the panel, replacing the file-browser dialog it
   used to take three clicks and a Refresh to get through. A row shows
   its own state and advances by itself: being read → ready to cite →
   cited, with a claim count.

   Waiting-to-be-cited rows are the OUTSTANDING WORK and are styled
   forward; cited ones are settled and recede.
   ================================================================ */
.th_srcbody   { display:flex; flex-direction:column; }
/* NOT sticky. These are group labels inside the scrolling list, and a sticky
   element cannot cover a scroll container's own padding — the same defect the
   claim filters had. The two groups are already told apart by their rows (one
   carries a + button, the other a ✓), so a scrolling label loses nothing. */
.th_srchead   {
	font-size:9.5px; font-weight:600; letter-spacing:0.4px; text-transform:uppercase;
	color:#9aa0a8; margin:2px 0 6px;
}
/* In the source detail these separate blocks of prose, so they need air above
   them — the first one sat directly on the URL. */
.th_srcdet .th_srchead { margin-top:14px; }
.th_srchead + .th_srchead,
.th_src + .th_srchead { margin-top:14px; }

.th_src {
	display:flex; align-items:center; justify-content:space-between; gap:10px;
	border:1px solid #e2e5ea; border-radius:5px; padding:8px 9px; margin-bottom:6px;
}
.th_src.is-cited { background:#fbfcfd; border-color:#eceff4; }
.th_src.is-busy  { border-color:#f0dcae; background:#fffdf7; }

.th_src_n {
	flex:1 1 auto; min-width:0; font-size:11.5px; color:#27251E;
	overflow:hidden; text-overflow:ellipsis;
}
.th_src_n > .fa   { color:#9aa0a8; }
.th_src_ok        { color:#116b3a; }
.th_src_r         { flex:0 0 auto; display:flex; gap:5px; align-items:center; }
.th_src_m         { display:flex; flex-wrap:wrap; gap:10px; font-size:10px; color:#9aa0a8; margin-top:3px; }
/* A citation with no type is a GAP, not a neutral blank — it is the one
   piece of provenance the one-click path leaves unfilled. */
.th_src_gap       { color:#a8801f; font-style:italic; }

/* The collector running. Documents land underneath it as they arrive, so it
   sits ABOVE the list rather than replacing it. */
.th_srccollect {
	font-size:11.5px; line-height:1.5; color:#41506b;
	background:#f6f8fa; border-left:3px solid #c8ccd4; border-radius:3px;
	padding:9px 11px; margin-bottom:10px;
}
.th_srccollect .fa  { color:#9aa0a8; }
.th_srccollect_h    { font-size:12px; }
.th_srccollect_s    { margin-top:4px; color:#6b7280; font-size:11px; }

/* Progress within the current phase. Deliberately per-PHASE rather than one
   bar for the whole run: searching, fetching and extracting cost wildly
   different amounts of time, so a single bar would crawl and then leap. */
.th_srcbar {
	height:3px; border-radius:2px; background:#e2e5ea; overflow:hidden; margin:7px 0 2px;
}
.th_srcbar i {
	display:block; height:100%; background:#41506b; transition:width .3s ease;
}

/* ---- one source in detail (replaces the list in the right column) ---- */
.th_srcdet_t      { font-size:13px; font-weight:600; color:#27251E; line-height:1.35; }
/* The citation itself, as a link — it is the thing a reader follows to check
   the claim, so it should behave like one.

   LAYOUT ONLY. Colour, cursor and hover come from `.gridurl`, which is the
   product's one link style (#0a66c2 light / #7ab1f0 dark) — see the note at
   its definition, where three competing blues were unified into it. */
.th_srcdet_u      { display:block; font-size:10.5px; margin-top:3px; word-break:break-all; }

/* "Show me what we stored." A quiet link, not a button: neither this nor the
   URL above is urgent enough to shout, and two primary buttons competing at the
   foot of a reading panel is what made it look aggressive. */
.th_srcdet_open   { display:inline-block; margin-top:14px; font-size:11.5px; }
.th_srcdet_claim  { font-size:11.5px; line-height:1.55; color:#27251E; }
.th_srcdet_quote  {
	margin:0; font-size:11px; line-height:1.6; color:#41506b; font-style:italic;
	background:#f8f9fb; border-left:3px solid #d5dae1; border-radius:3px; padding:8px 10px;
}
/* A modifier rather than changing `.th_kv` itself, which a dozen other readouts
   use at their own densities. These rows carry timestamps, hashes and graded
   labels that need room to breathe, and a `gap` so a long value cannot run into
   its label. Shared by Source PROVENANCE and the Canvas node detail so the two
   line up by construction — one definition, not two that drift. */
.th_kvrow { font-size:11px; line-height:1.6; gap:16px; padding:2px 0; }
.th_kvrow b { text-align:right; }
.th_srcdet_prov .th_kv + .th_kv { border-top:1px solid #f0f2f5; }

body.appbuilder-dark .th_srcdet_prov .th_kv + .th_kv { border-top-color:#33373d; }

body.appbuilder-dark .th_srcdet_t     { color:#e6e6ea; }
body.appbuilder-dark .th_srcdet_claim { color:#e6e6ea; }
body.appbuilder-dark .th_srcdet_quote { background:#2b2f35; border-left-color:#4a505a; color:#c3cbd9; }

.th_srcempty      { padding:28px 16px; text-align:center; }
.th_srcempty .fa  { font-size:24px; color:#c8ccd4; }
.th_srcempty_t    { margin-top:11px; font-size:12.5px; font-weight:600; color:#27251E; }
.th_srcempty_s    { margin:6px auto 0; max-width:360px; font-size:11px; line-height:1.55; color:#6b7280; }

body.appbuilder-dark .th_src            { border-color:#3a3f47; }
body.appbuilder-dark .th_src.is-cited   { background:#232629; border-color:#33373d; }
body.appbuilder-dark .th_src.is-busy    { background:#2e2a20; border-color:#574a2e; }
body.appbuilder-dark .th_src_n          { color:#e6e6ea; }
body.appbuilder-dark .th_src_ok         { color:#8fd6ae; }
body.appbuilder-dark .th_src_gap        { color:#e8c98a; }
body.appbuilder-dark .th_srccollect     { background:#2b2f35; border-left-color:#4a505a; color:#c3cbd9; }
body.appbuilder-dark .th_srccollect_s   { color:#9aa0a8; }
body.appbuilder-dark .th_srcbar         { background:#3a3f47; }
body.appbuilder-dark .th_srcbar i       { background:#8fa2c8; }
body.appbuilder-dark .th_srcempty .fa   { color:#4a505a; }
body.appbuilder-dark .th_srcempty_t     { color:#e6e6ea; }
body.appbuilder-dark .th_srcempty_s     { color:#9aa0a8; }



/* ================================================================
   RESEARCH — the review loop.

   One row per falsifier / kill condition, each answered Still holds /
   Breached / Can't tell. The three verdicts are visually distinct
   because the whole point is that "can't tell" must not be mistaken
   for comfort.
   ================================================================ */
.th_review     { display:flex; flex-direction:column; height:100%; }
.th_revhead    { flex:0 0 auto; padding-bottom:8px; border-bottom:1px solid #e2e5ea; }
.th_revlist    { flex:1 1 auto; overflow:auto; min-height:0; margin-top:10px; }

.th_revitem {
	border:1px solid #e2e5ea; border-radius:5px; padding:9px 10px; margin-bottom:8px;
}
.th_revitem_h  { display:flex; align-items:center; gap:7px; font-size:12px; color:#27251E; }
.th_revitem_l  {
	margin-top:5px; font-size:11.5px; line-height:1.5; color:#41506b;
	background:#f6f8fa; border-radius:3px; padding:5px 8px;
}
.th_revitem_d  { margin-top:4px; font-size:10.5px; color:#9aa0a8; }
.th_revitem_v  { display:flex; gap:6px; flex-wrap:wrap; margin-top:7px; }
.th_revnote    { margin-top:6px; width:100%; }

/* The selected verdict is tinted by MEANING, not just "primary" — a
   breach and a clean pass must not look alike at a glance. */
.th_revbtn.is-holds.is-primary    { background:#e6f4ec; border-color:#a9d8bf; color:#116b3a; }
.th_revbtn.is-breached.is-primary { background:#fbeaea; border-color:#e8b4b0; color:#b3261e; }
.th_revbtn.is-unclear.is-primary  { background:#fdf3e3; border-color:#f0dcae; color:#7a5410; }

/* "Nothing here can be reviewed" — the most serious finding the package
   produces, so it gets the whole dialog rather than a quiet line. */
.th_revblocked {
	font-size:12px; line-height:1.55; color:#7a5410;
	background:#fdf3e3; border-left:3px solid #e8a600; border-radius:3px; padding:10px 12px;
}
.th_revsuggest {
	margin-top:10px; font-size:11.5px; line-height:1.55; color:#41506b;
	background:#f6f8fa; border-left:3px solid #c8ccd4; border-radius:3px; padding:9px 11px;
}

body.appbuilder-dark .th_revhead    { border-bottom-color:#3a3f47; }
body.appbuilder-dark .th_revitem    { border-color:#3a3f47; }
body.appbuilder-dark .th_revitem_h  { color:#e6e6ea; }
body.appbuilder-dark .th_revitem_l  { background:#2b2f35; color:#c3cbd9; }
body.appbuilder-dark .th_revitem_d  { color:#8b919b; }
body.appbuilder-dark .th_revblocked { background:#3a3222; border-left-color:#e8a600; color:#e8c98a; }
body.appbuilder-dark .th_revsuggest { background:#2b2f35; border-left-color:#4a505a; color:#c3cbd9; }
body.appbuilder-dark .th_revbtn.is-holds.is-primary    { background:#1e3a2a; border-color:#2f6b48; color:#8fd6ae; }
body.appbuilder-dark .th_revbtn.is-breached.is-primary { background:#3a1f1f; border-color:#7a3630; color:#f0a9a3; }
body.appbuilder-dark .th_revbtn.is-unclear.is-primary  { background:#3a3222; border-color:#7a5410; color:#e8c98a; }

/* The modal while the document is still being written. Same geometry as the
   finished one, so the dialog does not jump when the document arrives. */
.th_docwait { display:flex; align-items:center; justify-content:center; }
.th_docwait_in { max-width:420px; text-align:center; padding:24px; }
.th_docwait_in .fa-spinner { font-size:26px; color:#9aa0a8; }
.th_docwait_bad { font-size:26px; color:#e0a030; }
.th_docwait_t {
	margin-top:14px; font-size:13px; font-weight:600; color:#27251E;
}
.th_docwait_s { margin-top:6px; font-size:11.5px; line-height:1.5; color:#6b7280; }

body.appbuilder-dark .th_docwait_t { color:#e6e6ea; }
body.appbuilder-dark .th_docwait_s { color:#9aa0a8; }

/* "The document exists, but not everything in it worked." */
.th_docnote {
	flex:0 0 auto; max-width:900px; width:100%; margin:0 auto; box-sizing:border-box;
	font-size:11.5px; line-height:1.45; color:#7a5410; background:#fdf3e3;
	border:1px solid #f0dcae; border-radius:4px; padding:8px 10px;
}

body.appbuilder-dark .th_staledot        { box-shadow:0 0 0 2px #2b2f35; }
body.appbuilder-dark .th_docmodal        { background:#1b1e22; }
body.appbuilder-dark .th_docmodal iframe { box-shadow:0 2px 12px rgba(0,0,0,.5); }
body.appbuilder-dark .th_docnote         { color:#e8c98a; background:#3a3222; border-color:#574a2e; }

/* ================================================================
   RESEARCH — UI corrections (2026-08-15, user-reported).
   ================================================================ */

/* (1) FAVOURITES — a package favourite with no logo function now falls back to
   the same monogram every other card on the page uses, and the raw key line is
   opt-in (`showKey`). Themes get a stage + conviction line instead, filled in
   after render. Only the enrichment line needs styling; the card itself is the
   shell's own. */
/* Scoped `.favorites_container`, matching `.fav-sym` / `.fav-quote` beside it —
   the note on those rules warns that the card's text block re-declares font
   properties, so a weaker selector loses. Colour is the same neutral grey they
   use, which reads in both themes; only the conviction figure is lifted. */
/* `display:block` with its own margin, NOT a <br>. The theme name above it is
   block-level (it wraps to two lines), so a <br> was a second break and left an
   empty line between the title and this. A margin is a gap we can size. */
.favorites_container .fav-theme   { display:block; margin-top:3px;
                                    font-weight:normal; font-size:10.5px; line-height:15px; color:#9aa0ac; }
.favorites_container .fav-theme b { font-weight:600; color:#27251E; }
body.appbuilder-dark .favorites_container .fav-theme b { color:#e6e6ea; }

/* A theme NAME wraps to two lines instead of being clipped.
   The card's text block is 148px wide and `white-space:nowrap`, which suits an
   instrument (a short company name over three data lines) but truncated
   "Grid Interconnection Bottleneck" to "Grid Interconnection Bot…". A theme
   card uses only TWO of the four lines an instrument needs, so the vertical
   room is already there — 2 × 16px of name plus one 15px info line still fits
   the 80px block.
   Scoped by `data-fav-open` so this cannot widen or re-wrap any other card
   type; widening the card itself would have moved every recent-object and
   entry-follow card in the app. */
.favorites_container .builder_recentobjects_element[data-fav-open='researchtheme']
	.builder_recentobjects_element_text > span {
	white-space:normal; line-height:16px;
	display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
	overflow:hidden;
}

/* (2) THE LADDER — every rung the same height, bars on one line.
   A <button> centres its content, so the locked rungs (whose lock used to wrap
   onto a second line) sat lower than the open ones. The lock is now inline in
   the label, and the button is an explicit top-aligned column so the bars line
   up regardless of what the label contains. */
.th_rung        { display:flex; flex-direction:column; justify-content:flex-start; }
.th_rung_lbl    { display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.th_rung_lock   { font-size:8.5px; opacity:.6; margin-left:4px; vertical-align:baseline; }

/* (3) HELP vs LABEL — an explanatory line must not read as a field label.
   `.th_kv span` (the label) is 11.5px #6b7280; `.th_check_hint` was 11px
   #9aa0a8, close enough that the two blurred together under a bar. Help is now
   italic, a size smaller and lighter still — the same separation the rest of
   the app draws between a name and a note about it. */
.th_help {
	font-style:italic; font-size:10.5px; line-height:1.45;
	color:#a8adb6; margin-top:3px;
}
body.appbuilder-dark .th_help { color:#7a808c; }

/* An empty state INSIDE a panel body.
   NOT `.anylist_empty` — that one is `position:absolute; left:50%; top:50%;
   transform:translate(-50%,-50%)` at 24px, built to centre a message in a whole
   panel viewport. A `.th_panel` is position:static, so an absolutely-positioned
   child escapes to the nearest positioned ancestor and lands in the middle of
   the screen; "The Vault is empty" floating over the Evidence tab was exactly
   that. This one stays in flow and is sized for the space it actually occupies,
   which may be a 340px side panel. */
.th_empty {
	padding:16px 12px; text-align:center;
	font-size:11.5px; line-height:1.5; color:#9aa0a8;
}
body.appbuilder-dark .th_empty { color:#8b919b; }

/* (4) SPLIT PANELS — see `.th_chainwrap, .th_evwrap` earlier in this file.
   The per-panel margins that used to live here are GONE, not overridden: the
   container now owns the gutter via `gap` + `padding`, the way `.th_grid` does
   on the Canvas tab, and leaving a later margin rule in place would simply add
   itself on top of that padding. */

/* (5) THEME CARD SCORES — two columns, label left, value right, bar below.
   The old single-column `label | bar | value` grid gave the bar whatever width
   the longest label left over, which on "Investability" was almost none. Each
   score now owns a half-width cell and its bar spans it. */
.rs_tcard_scores { display:grid; grid-template-columns:1fr 1fr; gap:9px 14px; margin:4px 0 10px; }
.rs_score        { min-width:0; }
.rs_score_top    { display:flex; align-items:baseline; justify-content:space-between; gap:6px; }
.rs_score_k      { font-size:10px; color:#9aa0a8; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rs_score_v      { font-size:11px; font-weight:600; color:#41506b; flex:0 0 auto; }
.rs_score_bar    { height:5px; border-radius:3px; background:#e4e7ec; overflow:hidden; margin-top:3px; }
.rs_score_bar > i{ display:block; height:100%; background:#269DF0; }

body.appbuilder-dark .rs_score_k   { color:#8b919b; }
body.appbuilder-dark .rs_score_v   { color:#c3c8d0; }
body.appbuilder-dark .rs_score_bar { background:#3a3f47; }

/* ============================================================
   COMPANY RADAR + COMPANY WORKSPACE  (Research ▸ Companies)

   Ships C0/C1/C3 — docs/company-workspace-plan.md.

   Reuses the theme workspace's furniture wherever it exists: .th_panel,
   .th_panel_head, .th_kv/.th_kvrow, .rs_chip, .rs_fchip, .th_rulebox,
   .th_muted, .pf_btn. Only what is genuinely new to this screen is defined
   here — a table that scans, a fair-value bar, a sensitivity heatmap and a
   dot-range.
   ============================================================ */

.co_panel        { font-family:'Open Sans', sans-serif; }

/* The page is a COLUMN that fills its host: head and footer keep their natural
   height, the Coverage panel takes the rest, and the table scrolls inside it.
   Same arrangement `.builder-dashboard-table-wrap` makes — flex:1 + min-height:0
   + overflow:auto — because without the min-height a flex item refuses to
   shrink below its content and the whole page scrolls instead of the rows. */
.co_wrap         { display:flex; flex-direction:column; height:100%; min-height:0;
                   box-sizing:border-box; padding:14px 16px 12px; }
.co_cov          { display:flex; flex-direction:column; flex:1 1 auto; min-height:0; }
.co_cov > .th_panel_head { flex:0 0 auto; }

.co_head         { flex:0 0 auto; display:flex; align-items:flex-start; justify-content:space-between;
                   gap:16px; margin-bottom:12px; flex-wrap:wrap; }
.co_eyebrow      { font-size:10px; font-weight:600; letter-spacing:0.4px; text-transform:uppercase;
                   color:#9aa0a8; }
.co_h1           { margin:2px 0 4px; font-size:19px; font-weight:600; color:#27251E; }
.co_sub          { margin:0; font-size:11.5px; color:#6b7280; max-width:640px; line-height:1.5; }

/* The New-dossier picker's one line of instruction. It sits above a full
   screener inside the popup, so it has to read as a caption rather than as
   another control competing with the filter bar. */
.co_pick_hint {
	font-size:11.5px; color:#6b7280; padding:6px 10px 4px;
	font-family:OpenSans, sans-serif; line-height:1.4;
}
body.appbuilder-dark .co_pick_hint { color:#9aa4b0; }

.co_headmetrics  { display:flex; align-items:flex-start; gap:10px; }
.co_metric       { min-width:96px; border:1px solid #e2e5ea; border-radius:5px; padding:7px 10px;
                   background:#fff; }
.co_metric_l     { font-size:10px; color:#9aa0a8; }
.co_metric_v     { font-size:17px; font-weight:600; color:#27251E; line-height:1.25; }
.co_metric_f     { font-size:10px; color:#9aa0a8; }

.co_filters      { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-left:auto; }
.co_search       { font-family:'Open Sans', sans-serif; font-size:11.5px; height:26px;
                   padding:0 9px; border:1px solid #d5dae1; border-radius:4px; background:#fff;
                   color:#27251E; min-width:210px; box-sizing:border-box; }
.co_search:focus { outline:none; border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }

/* The radar's filter bar — the Screener's own, one panel down from the
   toolbar. NOT wrapping: it sits in a fixed-height w2layout panel, so a second
   row would be clipped rather than push the grid down. The coverage note rides
   the right edge where the two metric cards used to be. */
.co_filterbar    { display:flex; flex-direction:column; justify-content:center; gap:6px;
                   height:100%; padding:0 10px; box-sizing:border-box;
                   border-bottom:1px solid #e2e2e2; background:#fff; }
.co_frow         { display:flex; align-items:center; gap:8px; min-width:0;
                   overflow-x:auto; overflow-y:hidden; }
/* One subgroup: its name, then All and its values. */
.co_fgroup       { display:flex; align-items:center; gap:6px; flex:0 0 auto; }
.co_flabel       { font-size:10px; font-weight:600; letter-spacing:0.3px;
                   text-transform:uppercase; color:#9aa0a8; }
.co_fsep         { width:1px; height:16px; background:#e2e5ea; flex:0 0 auto; margin:0 4px; }
/* A value chip wears its own colour as a dot, so the filter and the pill it
   selects in the column are recognisably the same state. Selected, the chip
   takes that colour rather than the generic blue .on — otherwise every active
   filter in both groups looks identical. */
.co_tonechip     { display:inline-flex; align-items:center; gap:5px; }
.co_dot          { width:7px; height:7px; border-radius:50%; background:#c8cdd3;
                   flex:0 0 auto; }
.co_tonechip.is-draft     > .co_dot { background:#9aa0a8; }
.co_tonechip.is-watchlist > .co_dot { background:#1c53b8; }
.co_tonechip.is-paper     > .co_dot { background:#9a6a10; }
.co_tonechip.is-live      > .co_dot { background:#116b3a; }
.co_tonechip.is-draft.on     { background:#eceff4; border-color:#c8cdd3; color:#41506b; }
.co_tonechip.is-watchlist.on { background:#eaf1fd; border-color:#a8c6f5; color:#1c53b8; }
.co_tonechip.is-paper.on     { background:#fdf3e3; border-color:#e6cb96; color:#9a6a10; }
.co_tonechip.is-live.on      { background:#e6f4ec; border-color:#a5d5bb; color:#116b3a; }
.co_tonechip.is-neg       > .co_dot { background:#b3261e; }
.co_tonechip.is-neg.on       { background:#fdecea; border-color:#f0b4ae; color:#b3261e; }
/* The portfolios' kill switch sits in the band's action slot. */
.co_passacts .pf_kill_wrap   { display:inline-flex; align-items:center; }

/* The revisit date, riding beside its status pill. Quiet by default — a date
   that has not arrived is information, not a task — and marked once it has,
   which is the only moment it asks anything of the reader. */
.co_revisit      { margin-left:6px; font-size:10px; color:#9aa0a8;
                   white-space:nowrap; font-variant-numeric:tabular-nums; }
.co_revisit.is-due { color:#9a6a10; font-weight:600; }

/* Why a proposed claim is still in the tray. Quiet — it is a hint about what
   to check, not a warning about the claim. */
.co_evwhy2       { margin-top:4px; font-size:10.5px; color:#9aa0a8; font-style:italic; }

/* Add-a-source dialog. */
.co_addsrc       { display:flex; flex-direction:column; gap:8px;
                   font-family:'Open Sans', sans-serif; padding:4px 2px; }
.co_srcurl       { font-family:'Open Sans', sans-serif; font-size:12.5px; height:30px;
                   padding:0 9px; border:1px solid #d5dae1; border-radius:4px;
                   background:#fff; color:#27251E; }
.co_srcurl:focus { outline:none; border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }
/* The pasted-text door of Add a source: the URL input's look, taller. */
.co_srctext       { font-family:'Open Sans', sans-serif; font-size:12.5px; min-height:150px; width:100%;
                    resize:vertical; padding:6px 9px; margin-top:6px; border:1px solid #d5dae1; border-radius:4px;
                    background:#fff; color:#27251E; line-height:1.45; }
.co_srctext:focus { outline:none; border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }
body.appbuilder-dark .co_srctext { background:var(--bg-elev, #333); border-color:#4a4f57; color:#e6e6e6; }
.co_srcchk       { font-size:11.5px; color:#41506b; display:flex; align-items:center; }
/* Reserved, so the dialog does not jump when the first message lands. */
.co_srcmsg       { min-height:20px; font-size:11.5px; color:#6b7280; }
.co_srcwarn      { color:#9a6a10; }
/* The state cell reads as a line: state, then what you can do about it, then
   quietly the feed it came from. Wrapping is allowed — a captured call carries
   a chip and two actions — so the column is sized for two and lets three wrap
   rather than clipping one. */
.co_tlchip       { white-space:nowrap; }
/* Only the claim-count chip navigates; the other two state chips are labels.
   Scoped so a chip that does nothing never offers a pointer. */
.co_tlstate      { cursor:pointer; }
.co_tlstate:hover { filter:brightness(0.95); }
.co_tlact        { white-space:nowrap; }
/* The feed name drops to its own line, quiet — it is provenance, not an action,
   and it was competing with the buttons for the eye. */

/* The timeline's explanation. Outside the scroller, so it frames the list
   rather than becoming its first row. */
.co_tlnote       { flex:0 0 auto; padding:8px 12px 10px;
                   border-bottom:1px solid #eceff4;
                   font-size:11px; line-height:1.55; color:#6b7280; }
/* The chip legend, on its own line under the prose. Real chips rather than
   coloured squares: the reader is matching them against the column, and a
   swatch that does not look like the thing it explains makes them do the
   translation themselves. */
.co_tllegend     { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }

/* Web research, previewed: what was asked, then what came back.
   Full height and padded, so the waiting state can centre in the dialog rather
   than sitting in its top-left corner, and the first heading is not welded to
   the frame. */
.co_web          { font-family:'Open Sans', sans-serif; font-size:12px; color:#27251E;
                   display:flex; flex-direction:column; min-height:100%;
                   padding:14px 16px; box-sizing:border-box; }
/* A wait is the ONLY thing in the box while it lasts, so it takes the box.
   `margin:auto` in a flex column centres it on both axes without the parent
   having to switch its own alignment for one transient state. */
.co_web > .pf_explain_wait { margin:auto; text-align:center; }
.co_websec       { display:flex; align-items:center; gap:8px;
                   font-size:10px; font-weight:700; letter-spacing:0.8px;
                   text-transform:uppercase; color:#41506b;
                   margin:12px 0 6px; }
.co_websec:first-child { margin-top:0; }
.co_webpick      { margin-left:auto; display:flex; gap:5px; }
.co_websteps     { display:flex; flex-direction:column; gap:4px; }
/* Chip in the first column, question in the second: a long question wraps
   inside its own column instead of dropping under the chip. */
.co_webstep      { display:grid; grid-template-columns:auto minmax(0,1fr); gap:2px 8px; align-items:start; }
.co_webstep .rs_chip { white-space:nowrap; margin-top:1px; }
.co_webq         { font-size:11.5px; color:#41506b; line-height:1.45; min-width:0; overflow-wrap:anywhere; }
.co_weberr       { grid-column:1 / -1; font-size:10.5px; color:#b3261e; padding-left:2px; }

.co_webrows      { display:flex; flex-direction:column; }
/* A whole-row label, so the tick target is the row rather than a 13px box. */
.co_webrow       { display:flex; align-items:center; gap:10px; cursor:pointer;
                   padding:6px 4px; border-bottom:1px solid #f4f6f9; }
.co_webrow:hover { background:#f7f9fc; }
/* Already held: readable, and visibly not part of what you are choosing. */
.co_webrow.is-have { opacity:0.6; }
.co_webmain      { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; }
.co_webtitle     { font-size:12px; color:#27251E; white-space:nowrap;
                   overflow:hidden; text-overflow:ellipsis; }
.co_weburl       { font-size:10px; color:#9aa0a8; white-space:nowrap;
                   overflow:hidden; text-overflow:ellipsis; }
.co_webtags      { flex:0 0 auto; display:flex; align-items:center; gap:5px; }
/* Reading a page before taking it. Quiet until the row is hovered — it is
   available on every row and wanted on few, and a column of blue arrows would
   compete with the tick that is the actual decision. */
.co_webopen      { color:#9aa0a8; opacity:0.55; padding:2px 4px; text-decoration:none;
                   transition:opacity .12s, color .12s; }
.co_webrow:hover .co_webopen { opacity:1; }
.co_webopen:hover { color:#1a5c9c; }
.co_webnote      { margin:10px 0 0; font-size:10.5px; color:#9aa0a8; line-height:1.55; }
/* The fetching state: centred like the search one, with the per-document
   progress under it rather than in the panel behind. */
.co_webbusy      { margin:auto; text-align:center; max-width:420px; }
.co_webbusy_h    { font-size:13px; color:#3c434a; }
.co_webbusy_s    { margin-top:6px; font-size:11px; color:#9aa0a8; line-height:1.55; }
.co_webbusy .co_openstep { margin:14px auto 0; width:100%; }

/* The brief's provenance line, above the reading it describes. */
.co_briefage     { font-size:11px; color:#9aa0a8; margin-bottom:8px; }
.co_brief_re     { border:1px solid #d5dae1; border-radius:3px; background:#fff;
                   color:#41506b; font:11px 'Open Sans', sans-serif;
                   padding:1px 7px; margin-left:4px; cursor:pointer; }
.co_brief_re:hover { background:#f2f6fb; }
/* The source a timeline chip just jumped to. A brief highlight rather than a
   permanent selection: it answers "which one" and then gets out of the way. */
.co_evdoc.is-flash { animation:co_flash 1.6s ease-out; }
@keyframes co_flash {
	0%   { background:#eaf1fd; }
	100% { background:transparent; }
}
@media (prefers-reduced-motion:reduce) {
	.co_evdoc.is-flash { animation:none; outline:2px solid #a8c6f5; }
}
.co_srctabs      { display:flex; gap:6px; }
.co_srctiers     { display:flex; gap:6px; flex-wrap:wrap; }
/* Scrolls inside itself: a dataroom with forty files must not grow the dialog
   past the screen. */
.co_srcpick      { max-height:150px; overflow-y:auto; border:1px solid #d5dae1;
                   border-radius:4px; padding:4px; background:#fff; }
.co_srcrow       { padding:4px 7px; border-radius:3px; cursor:pointer;
                   font-size:12px; color:#41506b; white-space:nowrap;
                   overflow:hidden; text-overflow:ellipsis; }
.co_srcrow:hover { background:#f2f7fd; }
.co_srcrow.is-on { background:#eaf1fd; color:#1c53b8; font-weight:600; }

/* A source that can be opened LOOKS like it can. The evidence list is read by
   someone deciding whether to trust a claim, and the document is the thing they
   need to reach. */
.co_evdoc_l.gridurl { cursor:pointer; color:#1a5c9c; }
.co_evdoc_l.gridurl:hover { text-decoration:underline; }
.co_fday.gridurl    { cursor:pointer; color:#6b7280; }
.co_fday.gridurl:hover { text-decoration:underline; color:#1a5c9c; }

/* The verdict dialog and the review history. */
.co_verdict      { display:flex; flex-direction:column; gap:6px;
                   font-family:'Open Sans', sans-serif; padding:4px 2px; }
.co_vlbl         { font-size:11px; font-weight:600; color:#41506b; margin-top:4px; }
.co_vnote        { font-family:'Open Sans', sans-serif; font-size:12px; padding:6px 8px;
                   border:1px solid #d5dae1; border-radius:4px; resize:vertical;
                   background:#fff; color:#27251E; }
.co_vdate        { font-family:'Open Sans', sans-serif; font-size:12px; height:28px;
                   padding:0 8px; border:1px solid #d5dae1; border-radius:4px;
                   background:#fff; color:#27251E; align-self:flex-start; width:140px; }
.co_vhint       { font-size:10.5px; color:#9aa0a8; }

.co_revhist      { display:flex; flex-direction:column; gap:8px; padding:2px;
                   font-family:'Open Sans', sans-serif; }
/* A cycle still running reads as an open edge rather than a closed card. */
.co_rev          { border:1px solid #e2e5ea; border-left:3px solid #c8cdd3;
                   border-radius:5px; padding:8px 10px; background:#fff; }
.co_rev.is-open  { border-left-color:#269DF0; }
.co_rev_h        { display:flex; align-items:center; gap:8px; font-size:12px; }
.co_rev_d        { margin-left:auto; font-size:11px; color:#9aa0a8;
                   font-variant-numeric:tabular-nums; }
.co_rev_m        { margin-top:4px; font-size:11px; color:#6b7280;
                   font-variant-numeric:tabular-nums; }
.co_rev_n        { margin-top:6px; font-size:11.5px; color:#41506b;
                   white-space:pre-wrap; line-height:1.5; }

.co_tablewrap    { flex:1 1 auto; min-height:0; overflow:auto; }
.co_table        { width:100%; border-collapse:collapse; font-size:11.5px; }
.co_table thead th { position:sticky; top:0; z-index:1; background:#f7f8fa;
                   text-align:left; font-size:10px; font-weight:600; letter-spacing:0.3px;
                   text-transform:uppercase; color:#9aa0a8; padding:7px 10px;
                   border-bottom:1px solid #e2e5ea; white-space:nowrap; }
.co_th           { cursor:pointer; user-select:none; }
.co_th:hover     { color:#41506b; }
.co_th.is-sorted { color:#269DF0; }
/* The caret occupies its slot on EVERY column, sorted or not — see the comment
   in _Paint. Invisible rather than absent, so sorting never re-flows the header;
   a hover preview shows which way a first click will go. */
.co_th_c         { margin-left:5px; opacity:0; transition:opacity .12s; }
.co_th:hover .co_th_c    { opacity:0.45; }
.co_th.is-sorted .co_th_c{ opacity:1; }
.co_th.num       { text-align:right; }
.co_table td     { padding:7px 10px; border-bottom:1px solid #f0f2f5; vertical-align:middle; }
/* Tabular figures so a column of numbers stays column-aligned and does not
   shimmer as values change width — the same reason the chat answer tables set
   it on their right-aligned cells. */
.co_table .num   { text-align:right; font-variant-numeric:tabular-nums; }
.co_row          { cursor:pointer; }
.co_row:hover td { background:#f2f7fd; }
.co_tick         { font-weight:600; color:#27251E; white-space:nowrap; }
.co_name         { color:#41506b; }
.co_sector       { color:#9aa0a8; font-size:11px; }
.co_tchips       { display:flex; flex-wrap:wrap; gap:4px; }
/* The header row holds either theme chips (~21px: 10px text at 1.5, 2px
   padding, 1px border) or the muted "Not in any theme basket" line (~16px),
   so the header was taller on a name with themes. One minimum height, the
   chip's, and the line centred in it — the header does not move either way. */
.co_hdchips      { min-height:21px; align-items:center; }
/* IN A GRID CELL the chips do not wrap — a w2grid row is a fixed height, so a
   second line is clipped rather than shown. Each name is capped: theme names
   are full sentences, and three uncapped ones need a column wider than the
   screen. The whole name is on the chip's tooltip. Left-aligned like every
   other text column; it is the COLUMN that sits last, not its contents. */
.co_tchips.is-cell        { flex-wrap:nowrap; overflow:hidden; }
.co_tchips.is-cell > .rs_chip { flex:0 1 auto; min-width:0; overflow:hidden; }
.co_tchip_t      { display:inline-block; max-width:130px; overflow:hidden;
                   text-overflow:ellipsis; white-space:nowrap; vertical-align:bottom; }
/* Clear of the sector / country / currency line above, which the chips were
   sitting directly on top of. */
.co_hdchips      { margin-top:6px; }
.co_gap.is-pos   { color:#0f9d76; }
.co_gap.is-neg   { color:#b3261e; }
.co_soon         { color:#9a6a10; font-weight:600; }

/* Conviction: a bar to scan for shape, the number BESIDE it to read for
   precision. The number used to sit on the fill, where its contrast changed
   with the very score it reported — dark on the empty track at 20, light on
   the fill at 90, straddling both at the crossover. Outside it is one colour
   at every score, and the bar is left as a clean shape down the column.
   tabular-nums so the digits line up row to row. */
.co_conv         { display:flex; align-items:center; gap:6px; justify-content:flex-end; }
.co_conv > .co_cbar { flex:1 1 auto; }
.co_conv > b     { flex:0 0 auto; min-width:20px; text-align:right;
                   font-size:10.5px; font-weight:600; color:#27251E;
                   font-variant-numeric:tabular-nums; }
.co_cbar         { position:relative; display:block; height:14px; min-width:40px;
                   border-radius:3px; background:#eceff4; overflow:hidden; }
.co_cbar > i     { position:absolute; left:0; top:0; bottom:0; background:#a8c6f5; }

.co_foot         { flex:0 0 auto; margin-top:9px; font-size:10.5px; color:#9aa0a8; }

/* ---- workspace ---- */

/* Same construction as the theme workspace's `.th_head`: a band with its own
   surface and a rule under it, so the header reads as a fixed frame the tabs
   move inside rather than as the first thing on a scrolling page. */
/* The BAND's own padding is what sets the header's height. The blocks inside it
   are pinned to 82px so their bottom edge lines up with the theme chips in the
   left column — growing them instead breaks that alignment, which is what
   happened the first time this was asked for. */
.co_ws_head      { flex:0 0 auto; padding:12px 16px 8px; background:#fff;
                   border-bottom:1px solid #e2e2e2; }
/* THREE SECTIONS, TWO OF THEM FIXED.
   Identity on the left, actions in the middle, the three readings on the
   right. The two ends size to their content and never shrink; the MIDDLE is
   the only section that gives, and its buttons wrap inside it. That is the
   whole point of the split: with the buttons living in the right-hand column
   the header had two sections, so a few pixels of shortfall had nowhere to go
   but into the readings — and the price/conviction/fair-value row dropped
   below the identity, which is a large break from a tiny overflow.
   `flex-wrap:nowrap` on the row is what forbids that break for good. */
.co_hd           { display:flex; align-items:flex-start; justify-content:space-between;
                   gap:18px; flex-wrap:nowrap; }
/* Fixed end, sized to its content. A max so a long company name or a row of
   theme chips cannot eat the middle instead — past it the title and the
   sub-line wrap, which they are already built to do. */
.co_hd_l         { flex:0 0 auto; min-width:0; max-width:400px; }
/* The give. `min-width:0` so it can be squeezed below its buttons' natural
   row width — without it a flex item refuses to go under its min-content and
   the squeeze lands on its neighbours again. */
.co_hd_c         { flex:1 1 auto; min-width:0; }
.co_hd_h1        { margin:2px 0 4px; font-size:18px; font-weight:600; color:#27251E;
                   display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.co_hd_tk        { font-weight:700; letter-spacing:0.3px; }
/* The other fixed end: three blocks of declared width, side by side, and no
   wrap. Its width is therefore a constant — 130 + 200 + 236 plus two gaps —
   whatever the fair value happens to say. It used to size to its contents,
   so an empty valuation (a sentence) made the header noticeably wider than a
   committed one (a price range). */
.co_hd_r         { flex:0 0 auto; display:flex; align-items:flex-start;
                   gap:12px; flex-wrap:nowrap; }
/* THE BUTTONS ARE WHAT WRAPS.
   This header sits within a handful of pixels of fitting, and opening a modal
   is enough to tip it: w2popup locks body scroll while it is up, so the
   scrollbar goes and comes back and the available width changes with it.
   Absorbing that inside this row — a second line of buttons — is invisible;
   absorbing it by moving a whole section is not.
   `justify-content:flex-end` keeps the row against the readings it belongs
   beside, so the slack shows as a gap after the title rather than a drift. */
.co_hd_acts      { display:flex; gap:5px; flex-wrap:wrap;
                   justify-content:flex-end; align-content:flex-start; }
.co_thchip       { cursor:pointer; border:none; font-family:'Open Sans', sans-serif; }
.co_thchip:hover { filter:brightness(0.96); }
/* β sits BEHIND the purity figure in weight. Purity is what the chip is for;
   the beta is a second reading riding along on it, and if both were bold the
   chip would have two headlines and no answer. */
.co_thbeta       { opacity:0.72; font-size:10px; letter-spacing:0.2px;
                   padding-left:1px; }

/* THE THREE HEADER BLOCKS — price, conviction, fair value.
   One height, one padding, one vertical centring. They used to be three
   independently-sized things that happened to sit in a row: the price had no
   frame, the dial no box, and the fair value a border of its own, so the row
   read as a number, a circle and a card rather than as three readings of the
   same company. */
/* 82px, so the blocks bottom out level with the theme chips in the left-hand
   column. The two sides of this header are independent stacks — a title, a
   sub-line and chips against three fixed-height blocks — and nothing aligns
   them automatically; the height is what makes the row square off. */
.co_hdblock      { box-sizing:border-box; min-height:82px;
                   display:flex; align-items:center; gap:12px;
                   padding:9px 14px; border:1px solid #e2e5ea;
                   border-radius:6px; background:#fff; }

.co_dialbox      { width:200px; }
.co_dialbox > div{ min-width:100px; }
/* The dial's own rows shed the row height they carry elsewhere: three of them
   inside an 80px block is what made this one taller than its neighbours. */
.co_dialbox .th_kvrow { padding:1px 0; line-height:1.45; }

/* The last price, at the dial's weight. Sized to the DIAL (84px) rather than to
   its own text so the header reads as two equal blocks instead of a circle with
   a caption beside it. */
/* The price block stacks rather than sitting in a row like its two neighbours. */
.co_pricebox     { width:130px; flex-direction:column; align-items:flex-start;
                   justify-content:center; gap:2px; }
.co_pricebox_v   { font-size:24px; font-weight:600; line-height:1.1;
                   font-variant-numeric:tabular-nums; }
.co_pricebox_d   { font-size:13px; font-weight:600; font-variant-numeric:tabular-nums; }
/* NO colour declared on `.co_pricebox` itself, deliberately.
   `.instr_up` / `.instr_down` sit on that same element and colour it; a
   neutral default here would out-specify them (both are one class, and this
   rule comes later in the file) and repaint the price plain again — which is
   exactly what turned it white. With nothing set, a toned block gets the
   instrument's red or green and an untoned one inherits the header's text
   colour. Both lines then follow. */
.co_pricebox_v, .co_pricebox_d { color:inherit; }

/* Autosave state, in the panel head beside the title. */
/* Popup footer buttons need air between them.
   w2ui centres them in the footer with no gap, so a Cancel and a Save render
   as one two-tone slab and the destructive half is a pixel from the safe one.
   Adjacent-sibling, so a single-button footer is not indented off-centre. */
.w2ui-popup .w2ui-popup-buttons .pf_btn + .pf_btn,
.w2ui-popup .w2ui-popup-buttons button + button { margin-left:8px; }

.co_savestate    { margin-left:auto; font-size:10.5px; color:#9aa0a8; }
.co_savestate.is-saved  { color:#0f9d76; }
.co_savestate.is-failed { color:#b3261e; font-weight:600; }
.co_fvbox_none   { font-size:11.5px; color:#9aa0a8; }

/* WIDTH, not min-width. A minimum let the block grow to whatever it held, and
   the empty state holds a sentence — so a name with no committed valuation
   rendered a header block half again as wide as a name with one. Fixed, the
   sentence wraps inside it and the header is the same shape either way. */
.co_fvbox        { width:236px; flex-direction:column; align-items:stretch;
                   justify-content:center; gap:0; }
/* Top-aligned when empty: two lines of grey centred in an 82px box float in
   the middle of it with no relation to the blocks either side. */
.co_fvbox.is-empty { justify-content:flex-start; padding-top:12px; }
.co_fvbox_hint   { margin-top:3px; font-size:10.5px; line-height:1.45; color:#6b7280; }
.co_fvbar        { position:relative; height:8px; border-radius:4px; background:#eceff4;
                   margin:7px 0 5px; }
.co_fv_band      { position:absolute; top:0; bottom:0; background:rgba(232,166,0,.28);
                   border-radius:4px; }
.co_fv_mid       { position:absolute; top:-2px; width:2px; height:12px; background:#e8a600; }
.co_fv_px        { position:absolute; top:-3px; width:3px; height:14px; background:#269DF0;
                   border-radius:2px; }
.co_fv_f         { display:flex; justify-content:space-between; font-size:10.5px; color:#6b7280; }
.co_fv_f b       { color:#27251E; }
.co_fv_f .is-pos, .co_fv_f .is-pos b { color:#0f9d76; }
.co_fv_f .is-neg, .co_fv_f .is-neg b { color:#b3261e; }

/* The gutter belongs to the TAB BODY, not to one layout inside it.
   It used to live on `.co_split`, so the two tabs built from a split were
   inset and the four built from plain panels ran flush to the frame. Moving it
   up means every tab is inset identically and no tab has to remember to ask. */
.co_ws_body      { padding:12px 16px 20px; }
.co_split        { display:grid; grid-template-columns:1fr 400px; gap:12px; }
@media (max-width: 1200px) { .co_split { grid-template-columns:1fr; } }

.co_kpis         { display:grid; grid-template-columns:repeat(4, 1fr); gap:10px; margin-top:12px; }
@media (max-width: 900px) { .co_kpis { grid-template-columns:repeat(2, 1fr); } }
.co_kpi          { border:1px solid #e2e5ea; border-radius:5px; padding:8px 10px; background:#fff; }
.co_kpi_l        { font-size:10px; color:#9aa0a8; }
.co_kpi_v        { font-size:17px; font-weight:600; color:#27251E; line-height:1.3; }
.co_kpi_u        { font-size:10.5px; font-weight:400; color:#9aa0a8; margin-left:2px; }
.co_kpi_f        { font-size:10px; color:#9aa0a8; overflow:hidden; text-overflow:ellipsis;
                   white-space:nowrap; }

/* ---- verdict ---- */

.co_verdict_hash { margin-left:auto; font-size:10px; color:#9aa0a8;
                   font-variant-numeric:tabular-nums; }
.co_stance       { display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
.co_stance_tag   { flex:0 0 auto; font-size:11px; font-weight:700; letter-spacing:0.6px;
                   padding:7px 13px; border-radius:4px; }
.co_stance_tag.is-bull { background:#e6f4ec; color:#116b3a; }
.co_stance_tag.is-bear { background:#fbeaea; color:#b3261e; }
.co_stance_tag.is-neut { background:#fdf3e3; color:#9a6a10; }
.co_stance_h     { flex:1 1 320px; min-width:0; font-size:12.5px; line-height:1.6;
                   color:#41506b; }
.co_stance_c     { flex:0 0 auto; display:grid; grid-template-columns:auto auto;
                   align-items:center; gap:2px 8px; min-width:190px; }
.co_stance_cl    { font-size:9.5px; letter-spacing:0.5px; color:#9aa0a8; }
.co_stance_c > b { font-size:17px; font-weight:600; color:#27251E; text-align:right;
                   font-variant-numeric:tabular-nums; }
.co_stance_bar   { grid-column:1 / -1; display:block; height:4px; border-radius:2px;
                   background:#eceff4; overflow:hidden; }
.co_stance_bar > b { display:block; height:100%; background:#e8a600; }
.co_stance_cf    { grid-column:1 / -1; font-size:10px; color:#9aa0a8; }

/* The read and the signals, EQUAL halves below the stance strip.
   Neither is the subordinate one: the table is the evidence, the prose is what
   it adds up to, and a reader goes back and forth between them. `minmax(0,1fr)`
   twice rather than `1fr 1fr` because the table's evidence column would
   otherwise push its half wider than the other. */
.co_vsplit       { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
                   gap:18px; margin-top:16px; padding-top:14px;
                   border-top:1px solid #eceff4; }
@media (max-width: 1180px) { .co_vsplit { grid-template-columns:1fr; } }

.co_read_p       { margin:0 0 11px; font-size:12.5px; line-height:1.72; color:#41506b; }
.co_read_p:last-child { margin-bottom:0; }

/* The table sits in its own frame so the two halves read as two objects
   rather than as prose that happens to have a grid next to it. */
.co_sigbox       { border:1px solid #e2e5ea; border-radius:5px; overflow:hidden;
                   align-self:start; background:#fff; }
.co_sigbox .co_tbl { margin:0; }

/* The bear case. Red rule on the left, its own ground — it is the one block
   here that is quoted rather than composed, and it should not read as another
   paragraph of the same voice. */
.co_bear         { margin-top:14px; border-left:2px solid #b3261e; border-radius:0 4px 4px 0;
                   background:#fbeaea; padding:9px 12px 10px; }
.co_bear_h       { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;
                   font-size:9.5px; font-weight:700; letter-spacing:0.7px; color:#b3261e; }
.co_bear_h > span { font-weight:400; letter-spacing:0.3px; color:#a5675f; }
.co_bear_p       { margin:5px 0 0; font-size:12px; line-height:1.62; color:#5d3b38; }
.co_bear_p > b   { color:#8f231d; }
.co_bear_k       { margin:6px 0 0; font-size:11.5px; line-height:1.55; color:#8a6360; }
.co_bear_k > b   { color:#8f231d; font-variant-numeric:tabular-nums; }

/* ---- top claims / top risks ---- */
/* Side by side, equal, and never stacked above 1100px. What a name is believed
   to be and what would break it are read TOGETHER; putting one under the other
   is how a thesis gets read without its bear case. */
.co_cr           { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
                   gap:12px; margin-top:12px; }
@media (max-width: 1100px) { .co_cr { grid-template-columns:1fr; } }
.co_cr > .th_panel { min-width:0; }

.co_crc          { border:1px solid #e2e5ea; border-radius:5px; padding:9px 11px;
                   margin-bottom:8px; background:#fff; }
.co_crc:last-child { margin-bottom:0; }
.co_crc_t        { font-size:12px; line-height:1.55; color:#27251E; font-weight:500; }
.co_crc_d        { font-size:11px; line-height:1.55; color:#6b7280; margin-top:3px; }
.co_crc_m        { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-top:6px; }
.co_crc_m > i    { font-style:normal; font-size:10px; color:#9aa0a8; }
.co_crc_st       { text-transform:capitalize; }

/* The falsifier — or the kill condition — gets its own band. It is the point of
   the row, not a third chip on it. */
.co_crc_f        { margin-top:7px; padding:6px 9px; border-radius:4px;
                   background:#fbeaea; border-left:2px solid #b3261e;
                   font-size:10.5px; line-height:1.55; color:#5d3b38; }
.co_crc_f > b    { color:#8f231d; }
.co_crc_f.is-missing { background:#fdf3e3; border-left-color:#e8a600; color:#9a6a10; }

/* ---- company evidence ---- */
.co_evacts       { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.co_evacts .th_muted { font-size:11px; max-width:520px; line-height:1.5; }

/* NO TOP RULE. This carried a 12px margin, a border and 10px of padding from
   when it followed other content inside the old Evidence panel and needed
   separating from it. It is now the only thing in the Sources scroller, so all
   three rendered as an empty band under a line that divided nothing. */
/* NO PADDING HERE. The inset belongs to the ROW and to the group heading,
   exactly as the Filings Timeline does it — padding on the container indents
   the row borders and the heading band with the text, which is what left every
   separator floating short of the panel edge. */
.co_evdocs       { padding:0; }
/* Origin groups reuse the timeline's .co_fy / .co_fy_h — see the note at the
   markup. Nothing is defined here on purpose. */
/* The per-prompt chips: a result you can click to run again. */
.co_srun         { cursor:pointer; }
.co_srun > b     { font-weight:600; }
.co_srcacts      { display:flex; align-items:center; gap:6px; flex-wrap:wrap;
                   justify-content:flex-end; }
/* THE HEADER IS AS TALL AS ITS TALLEST CHILD, and both panels share
   .th_panel_head — so the two heads differ only because the Filings Timeline
   fills its with filter CHIPS (10.5px, 3px padding) and Sources with BUTTONS
   (12px, 5px). Matching the chips' vertical metrics makes the two headers the
   same height without either panel needing a hard-coded one.

   Scoped to this row: pf_btn is the app's button everywhere else and should not
   shrink. Both families, because this row mixes them — Build the evidence is a
   w2ui-btn (it is the primary action) and the rest are pf_btn, and matching only
   one would leave the other setting the height, which is the whole problem. */
.co_srcacts .pf_btn {
	font-size:11px; line-height:1.4; padding:4px 10px;
	min-height:0; height:auto; white-space:nowrap;
}
/* EVERY DECLARATION !important, and the selector carries the element.
   The builder pins every dialog button globally — `button.w2ui-btn` with
   height, padding, line-height, min-width, margin and font-size ALL marked
   !important (search "Dialog / popup buttons"). A plain `.co_srcacts .w2ui-btn`
   loses to that whatever its specificity, which is why two rounds of tuning
   font and padding here changed nothing at all: the rule was never in the
   running. `.charts_applybtn` above solves the same problem the same way and
   says so.
   The result is Build the evidence sized exactly like the pf_btn beside it —
   it keeps its blue (that comes from w2ui-btn-blue, also !important, and is
   the one difference worth keeping). */
button.w2ui-btn.co_srcbtn {
	height:auto !important; min-height:0 !important;
	padding:4px 10px !important; min-width:0 !important; margin:0 !important;
	font-size:11px !important; line-height:1.4 !important;
	border-radius:4px !important; font-weight:400 !important;
}
/* A prompt never run against this document. Present, so the reader can see
   which of the three is missing rather than counting the ones that are there. */
/* A prompt never run: outline, and faded, so the three read as 'two done, one
   not' at a glance rather than needing to be counted. */
.co_srun_none    { cursor:pointer; opacity:0.5; }
.co_srun_none:hover { opacity:1; }
/* ONE LINE per source: the name on the left, every fact about it as a chip on
   the right. min-width:0 on the name is what lets a long title ellipsis rather
   than push the chips off the end. */
.co_evdoc        { display:flex; align-items:center; justify-content:space-between;
                   gap:12px; padding:6px 12px; border-bottom:1px solid #f4f6f9; }
.co_srcname      { flex:1 1 auto; min-width:0; font-size:12px; color:#1a5c9c;
                   cursor:pointer; white-space:nowrap; overflow:hidden;
                   text-overflow:ellipsis; }
.co_srcname:hover { text-decoration:underline; }
.co_srcchips     { flex:0 0 auto; display:flex; align-items:center; gap:5px;
                   flex-wrap:wrap; justify-content:flex-end; }
.co_evdoc:last-child { border-bottom:0; }

/* A running extraction takes over its own button. Same width family as the
   idle label so the row does not jump when it starts, and disabled because
   pressing it again would start a second pass over the same text. */
.pf_btn.is-busy  { opacity:0.85; cursor:default; font-variant-numeric:tabular-nums; }

/* What has already been run against this document. Small and stacked under the
   title — it is history, not an action, and it answers the one question the
   buttons above cannot: have I done this already. */

/* The claim TYPE, on the source cell. Three prompts over one document put
   three sets of claims in one list, and the chip is what separates them. */
.co_evdoc_l      { font-size:10.5px; color:#41506b; line-height:1.45; }

/* FIXED LAYOUT, so the widths below are OBEYED. Left to auto, the browser
   sizes columns by content, and a register whose claims run long and whose
   falsifiers run short always resolves the same way: the claim swallows the
   table. Only the claims table takes this — .co_tbl is shared. */
.co_cltbl        { table-layout:fixed; }
/* Fixed layout will not widen a column for a word that does not fit, so a long
   ticker chain or URL in a claim would run out over its neighbour. */
.co_cltbl td     { vertical-align:top; overflow-wrap:anywhere; }
.co_cltbl td.co_clacts { overflow-wrap:normal; }
/* COLUMN WIDTHS, declared rather than left to the browser.
   The claim ran two thirds of the table and the falsifier was squeezed into a
   column narrower than its own sentences — but they are a PAIR, read against
   each other: this is what we believe, this is what would prove it wrong. A
   reader comparing them should not have to compare a paragraph with a sliver.
   Percentages on the two flexible columns, fixed pixels on the three that hold
   chips, a name and buttons — those have a natural size and taking more of it
   only starves the pair that matter. */
.co_th_st        { width:110px; }
/* Direction sits beside Status as its own rail — same chip, same footprint. */
.co_th_dir       { width:80px; }
.co_evdircell    { white-space:nowrap; }
.co_th_cl        { width:36%; }
.co_th_fa        { width:30%; }
.co_th_sr        { width:160px; }
.co_th_ac        { width:120px; }
.co_evtext       { color:#27251E; line-height:1.55; }
.co_evfals       { color:#6b7280; font-size:10.5px; line-height:1.5; }
.co_evsrc        { font-size:10.5px; color:#6b7280; }
/* THE THREE ACTIONS STAY ON ONE LINE. They wrapped to a second, which made
   every row in the register a different height and the column a ragged edge.
   nowrap plus a width that fits three of them is the whole fix. */
.co_clacts       { white-space:nowrap; }
.co_clacts .pf_btn { padding:4px 7px; margin-left:2px; }
/* Equal boxes for unequal glyphs: fa-check, fa-times, fa-crosshairs and
   fa-undo all have different advance widths, so without this the three
   buttons come out three different sizes and the column looks unaligned. */
.co_clacts .pf_btn i { display:inline-block; width:12px; text-align:center; }

/* The claim filters, under the title: the Coverage filter bar's own shape. */
.co_clfilters    { flex:0 0 auto; display:flex; align-items:center; gap:8px;
                   flex-wrap:wrap; padding:8px 12px;
                   border-bottom:1px solid #eceff4; }

/* A claim with no falsifier cannot be accepted, so the row says so rather than
   leaving the reader to discover it by pressing a button that fails. */
.co_evwarn       { color:#b3261e; }
.co_evrow_nf td  { background:rgba(179,38,30,.035); }

/* The quoted span is the evidence, and it is usually a whole paragraph. Folded
   away by default; opening it is the actual act of reviewing a claim. */
.co_evspan       { margin-top:4px; }
.co_evspan > summary { font-size:10px; color:#9aa0a8; cursor:pointer; }
.co_evspan blockquote { margin:5px 0 0; padding:6px 9px; border-left:2px solid #e2e5ea;
                   background:#f7f8fa; font-size:10.5px; line-height:1.55; color:#41506b; }
.co_evnospan     { font-size:10px; color:#c0392b; margin-top:3px; }
.co_evdiff       { margin:6px 0 0; padding-left:18px; font-size:12px; line-height:1.7; }

/* Why a proposed claim sits where it does. Quiet — it explains the order, it
   is not part of the claim. The reason itself is on the tooltip, because a
   sentence per row would double the height of the queue. */
.co_evwhy        { font-size:9.5px; color:#9aa0a8; margin-top:3px; cursor:help; }

/* ---- extraction quality ---- */
.co_evalbody     { padding:14px 16px; }
.co_evalnote     { margin:0 0 14px; font-size:11.5px; line-height:1.6; color:#41506b; }
.co_evalgrp      { margin-bottom:16px; }
.co_evalgrp_h    { display:flex; align-items:baseline; gap:8px; margin-bottom:4px;
                   font-size:11px; font-weight:700; letter-spacing:0.6px;
                   text-transform:uppercase; color:#41506b; }
.co_evalgrp_h > i { font-style:normal; font-weight:400; letter-spacing:0;
                   text-transform:none; font-size:10px; color:#9aa0a8; margin-left:auto; }
.co_evmlab       { font-size:11.5px; color:#27251E; }
.co_evmwhat      { font-size:10px; color:#9aa0a8; margin-top:1px; line-height:1.45; }
/* The interval sits WITH the number and in the same weight family, because a
   rate shown alone invites a decision its sample cannot support. */
.co_evlci        { font-style:normal; font-size:10.5px; color:#6b7280; }
.co_evln         { font-style:normal; font-size:10px; color:#9aa0a8; }
.co_evmcav       { font-size:10.5px; line-height:1.55; color:#9a6a10;
                   background:#fdf3e3; padding:5px 9px; }

/* ---- risk factor changes ---- */
.co_rdsum        { font-size:11.5px; color:#41506b; margin-bottom:10px; }
.co_rdsum > b    { color:#27251E; font-variant-numeric:tabular-nums; }

.co_rdgrp        { margin-bottom:12px; }
.co_rdgrp:last-of-type { margin-bottom:0; }
.co_rdgrp_h      { display:flex; align-items:baseline; gap:8px; margin-bottom:5px; }
.co_rdgrp_h > i  { font-style:normal; font-size:10px; color:#9aa0a8; }

/* Each risk factor folds. The list is what you scan; the paragraph is what you
   read once something on it catches. Forty open paragraphs is not a panel. */
.co_rd           { border-bottom:1px solid #f0f2f5; }
.co_rd:last-child { border-bottom:0; }
.co_rd > summary { padding:5px 2px; font-size:11.5px; line-height:1.5; color:#27251E;
                   cursor:pointer; display:flex; align-items:baseline; gap:8px; }
.co_rd > summary:hover { background:#f2f7fd; }
.co_rdsim        { font-style:normal; font-size:10px; color:#9aa0a8; margin-left:auto;
                   flex:0 0 auto; }

.co_rdnow, .co_rdwas { margin:4px 0 8px; padding:7px 10px; font-size:11px;
                   line-height:1.6; border-left:2px solid #e2e5ea; background:#f7f8fa;
                   color:#41506b; }
/* The prior wording is set BACK, not beside: the new text is the claim and the
   old one is the evidence that it changed. */
.co_rdwas        { opacity:0.75; }
.co_rdwas_l      { font-size:9.5px; letter-spacing:0.4px; color:#9aa0a8;
                   text-transform:uppercase; }

/* ---- consensus revisions ---- */
/* The percentage is the reading and the absolute move is the check on it, so
   the absolute sits under it, smaller — one cell, two magnitudes, no ambiguity
   about which is being asserted. */
.co_revlab       { font-weight:600; color:#27251E; white-space:nowrap; }
.co_revabs       { font-size:10px; color:#9aa0a8; margin-top:1px;
                   font-variant-numeric:tabular-nums; }

/* ---- filings timeline ---- */
/* The panel fills the tab and the LIST scrolls inside it, so the filter bar and
   the footnote hold still while two hundred rows move under them.

   Built exactly like the Evidence tab above, which solved this first:

     - `overflow:hidden` on the tab body, taking the scroller OFF it. Left as
       `auto` (from `.th_body`) the page scrolls as one and the inner scroller
       never engages.
     - `box-sizing:border-box` on the subtree. This stylesheet has NO global
       border-box rule — only per-rule declarations — so `.co_ws_body`'s 12/16px
       padding would otherwise be added to a `height:100%` child and hang it
       exactly that far below the fold. It looks like a broken flex chain and is
       arithmetic.
     - `min-height:0` at every link. A flex child defaults to `min-height:auto`,
       meaning "as tall as my content", which silently defeats every overflow
       below it.

   `.co_cov` and `.co_tablewrap` are the radar's Coverage pattern, reused. */
.co_ws_body[data-tabbody='filings']   { overflow:hidden; display:flex;
                                        flex-direction:column; min-height:0; }
.co_ws_body[data-tabbody='filings'],
.co_ws_body[data-tabbody='filings'] * { box-sizing:border-box; }
.co_ws_body[data-tabbody='filings'] .co_insider_f { flex:0 0 auto; }

/* SOURCES AND CLAIMS, the same way. Every note above applies verbatim — the
   scroller comes OFF the tab body, box-sizing is declared on the subtree
   because this stylesheet has no global rule, and min-height:0 appears at every
   link because a flex child's `auto` minimum silently defeats the overflow
   under it.
   Listed beside filings rather than merged into one selector list: these are
   three tabs that happen to want the same layout, and a shared rule would make
   changing one of them a change to all three. */
.co_ws_body[data-tabbody='cosources'],
.co_ws_body[data-tabbody='coclaims'],
.co_ws_body[data-tabbody='coexposure'] { overflow:hidden; display:flex;
                                         flex-direction:column; min-height:0; }
.co_ws_body[data-tabbody='cosources'],
.co_ws_body[data-tabbody='cosources'] *,
.co_ws_body[data-tabbody='coclaims'],
.co_ws_body[data-tabbody='coclaims'] *  { box-sizing:border-box; }
/* The exposure tab: no padding of its own — the panel brings its strip and
   its card, and fills the body. */
.co_ws_body[data-tabbody='coexposure'] { padding:0; }
.co_ws_body[data-tabbody='coclaims'] .co_insider_f { flex:0 0 auto; }
/* The theme's Sources and Claims are the dossier's tabs, painted by the same
   code, so they need the same fill-the-tab geometry under the theme's own
   body marker. */
.th_ws_body[data-tabbody='cosources'],
.th_ws_body[data-tabbody='coclaims']   { overflow:hidden; display:flex;
                                         flex-direction:column; min-height:0; padding:12px 16px 20px; }
.th_ws_body[data-tabbody='cosources'],
.th_ws_body[data-tabbody='cosources'] *,
.th_ws_body[data-tabbody='coclaims'],
.th_ws_body[data-tabbody='coclaims'] *  { box-sizing:border-box; }
.th_ws_body[data-tabbody='coclaims'] .co_insider_f { flex:0 0 auto; }

/* THE BEAR BOOK IS CAPPED, not free. It sits above the register at its natural
   height, which for a theme with twenty risks would leave the claims list a
   sliver — the panel below it flexes, so whatever this takes it takes first.
   Two fifths, with its own scroll past that, keeps the register the majority of
   the tab it is the subject of.

   flex-shrink MUST BE 0, and the reason is the `overflow` on the next line. A
   flex item's automatic minimum size — the thing that normally stops a flex
   child being crushed below its content — applies only while `overflow` is
   `visible`. Making this scrollable sets that minimum to zero, so any shrink at
   all collapsed the whole panel to a few pixels of horizontal scrollbar. The
   cap is what limits it; shrinking was never wanted.

   overflow-y only, for the same episode: an `auto` on both axes gave the
   collapsed strip a horizontal bar it had no content to justify. */
.co_ws_body[data-tabbody='coclaims'] > .th_panel:first-child {
	flex:0 0 auto; max-height:40%; overflow-y:auto; overflow-x:hidden;
}

/* THE COLUMN HEADS STAY PUT while the register scrolls under them. Four
   columns of claim text are unreadable once the labels have gone.

   Scoped to a table INSIDE a scroller: sticky positions against the nearest
   scrolling ancestor, so the same rule on a table that is not in one would pin
   the head to the page and follow you around the tab.

   The rule under the heads is a BOX-SHADOW, not the border it replaces. With
   `border-collapse:collapse` a cell's border belongs to the collapsed grid
   rather than to the cell, and does not travel with a sticky element — the
   heads would float over the first row with nothing between them. An inset
   shadow is painted by the cell itself and stays. */
.co_tablewrap .co_tbl thead th {
	position:sticky; top:0; z-index:2;
	background:#fff; border-bottom:0;
	box-shadow:inset 0 -1px 0 #e2e5ea;
}

/* The year headings scroll WITH the rows but stick to the top of the viewport
   as you pass them, so you always know which year you are looking at 200 rows
   down. */
.co_fy           { border-top:1px solid #eceff4; }
.co_fy:first-child { border-top:0; }
.co_fy_h         { display:flex; align-items:baseline; justify-content:space-between;
                   padding:7px 12px 5px; background:#f7f8fa;
                   position:sticky; top:0; z-index:1; }
.co_fy_h > span  { font-size:11px; font-weight:700; letter-spacing:0.8px; color:#41506b;
                   font-variant-numeric:tabular-nums; }
.co_fy_n         { font-style:normal; font-size:10px; color:#9aa0a8; }

/* The FISCAL quarter leads; the exact date sits under it, quieter. The quarter
   is what a reader thinks in, the date is what they check. */
.co_fdate        { width:88px; white-space:nowrap; font-variant-numeric:tabular-nums; }
.co_fdate > b    { font-size:11px; font-weight:600; color:#27251E; }
.co_fday         { font-size:10px; color:#9aa0a8; margin-top:1px; }
.co_fform        { width:92px; white-space:nowrap; }
.co_fwhat        { color:#27251E; }
.co_fper         { font-size:10.5px; color:#9aa0a8; margin-top:1px; }
/* WIDER, and wrapping allowed. This cell used to hold one icon; it now holds a
   state chip and up to two labelled actions, and `nowrap` at 104px would clip
   whichever came last — silently, which is the worst way to lose a button.
   Right-aligned still, so the column reads as one edge down the list. */
/* ONE LINE: state chip, action, feed name. Wide enough for all three, and
   `nowrap` so it cannot try to stack them — a row that folds into three
   fragments reads as three facts when it is one statement about one filing.
   Right-aligned, so the column is a single edge down the list. */
.co_fsrc         { width:290px; text-align:right; white-space:nowrap;
                   font-size:10px; color:#9aa0a8; }
/* The actions were icons hidden until the row was hovered, on the theory that a
   column of download arrows competed with the filings. It did — but
   invisible-until-hover is also why nobody could tell what a row offered, or
   that it offered anything at all. They are labelled words now, always visible,
   and the state chip beside them carries the weight the icons fought over.

   NOT `.co_fact` — that class already belongs to the About panel's facts list,
   and sharing it made these buttons quietly inherit its font size. */
.co_tlact        { margin-left:5px; }

/* Only rows that HAVE something to open look openable. An affordance on a row
   that does nothing is worse than no affordance. */
.co_tlrow_open        { cursor:pointer; }
.co_tlrow_open:hover td { background:#f2f7fd; }

/* Count inside a filter chip. Lighter than the label — it says how much, not
   what, and two equal weights in one chip read as two labels. */
.co_fcn          { font-style:normal; margin-left:5px; opacity:0.6;
                   font-variant-numeric:tabular-nums; }
/* Between the topic chips and the source chips: they filter different things
   and a single run of eight chips reads as one list of eight equals. */
.co_fsep         { width:1px; height:16px; background:#e2e5ea; margin:0 3px; }

/* Busy markers. Deliberately quiet — a refresh is not an error and not an
   achievement, and the panel under it is still perfectly readable. The eyebrow
   one names what is refreshing; the panel ones just mark where. */
.co_busy         { margin-left:6px; color:#9aa0a8; font-size:11px; }
.co_busy_hd      { color:#9aa0a8; }
.co_busy_hd .fa  { margin-right:3px; }

.co_sig_k        { font-weight:600; color:#27251E; white-space:nowrap; }
.co_sig_e        { color:#6b7280; line-height:1.55; }
/* A signal with no inputs is dimmed, never coloured — it has no reading, and
   giving it one would put it in the count. */
.co_sig_off      { opacity:0.55; }

/* ---- falsifier watchlist ---- */

.co_watch_f      { max-width:340px; color:#27251E; font-weight:600; }
.co_watch_c      { font-size:10.5px; font-weight:400; color:#9aa0a8; margin-top:3px;
                   line-height:1.45; }
.co_watch_m      { color:#6b7280; line-height:1.5; max-width:400px; }
/* A tripped row is not decoration — it says a claim is broken on its own terms,
   which is the loudest thing this screen can say. */
.co_watch_hot td { background:rgba(179,38,30,.07); }
/* Distance to firing. Nearly-full is nearly-tripped. */
.co_watch_bar    { display:block; width:52px; height:3px; margin-top:4px;
                   border-radius:2px; background:#eceff4; overflow:hidden; }
.co_watch_bar > b{ display:block; height:100%; background:#e8a600; }
.co_bindpick     { display:flex; flex:0 0 220px; }

/* ---- the scorecard's thesis checklist ---- */

.co_lines        { margin-top:12px; padding-top:10px; border-top:1px solid #eceff4; }
.co_lines_h      { font-size:10px; font-weight:600; letter-spacing:0.3px;
                   text-transform:uppercase; color:#9aa0a8; margin-bottom:7px; }
.co_line         { padding:7px 0; border-bottom:1px solid #f0f2f5; }
.co_line:last-of-type { border-bottom:none; }
.co_line_t       { font-size:11.5px; line-height:1.5; color:#41506b; }
.co_line_v       { display:flex; gap:5px; margin-top:5px; }
/* The three answers behave as ONE control: unselected chips are washed out so
   the row reads as a single choice rather than three independent buttons. */
.co_line_b       { cursor:pointer; border:none; font-family:'Open Sans', sans-serif;
                   opacity:0.42; filter:grayscale(0.6); transition:opacity .12s; }
.co_line_b:hover { opacity:0.8; }
.co_line_b.on    { opacity:1; filter:none; font-weight:600; }
.co_lines_f      { margin-top:8px; font-size:10.5px; line-height:1.5; color:#9aa0a8; }

/* ---- profile / news ---- */

.co_about        { margin:0; font-size:12.5px; line-height:1.65; color:#41506b; }
.co_facts        { display:flex; flex-wrap:wrap; gap:8px 22px; margin-top:12px;
                   padding-top:10px; border-top:1px solid #eceff4; }
.co_fact         { font-size:11.5px; }
.co_fact > span  { color:#9aa0a8; margin-right:6px; }
.co_fact > b     { color:#27251E; }

.co_news         { display:flex; align-items:flex-start; gap:9px; padding:8px 12px;
                   border-bottom:1px solid #f0f2f5; }
.co_news:last-child { border-bottom:none; }
/* A DOT, not a label: the provider's sentiment is noisy, so it earns a hint of
   colour and no more. Grey when the feed sent none — which is not neutral. */
.co_news_dot     { flex:0 0 auto; width:7px; height:7px; margin-top:5px;
                   border-radius:50%; background:#c8ccd2; }
.co_news_dot.is-pos { background:#0f9d76; }
.co_news_dot.is-neg { background:#b3261e; }
.co_news_b       { min-width:0; font-size:12px; line-height:1.5; }
.co_news_d       { font-size:10.5px; color:#9aa0a8; margin-top:2px; }

.co_axis         { display:flex; align-items:center; gap:10px; font-size:11.5px; color:#6b7280;
                   /* An explicit row height, not just a margin: the label is a
                      single line and the bar is 6px, so without it the rows sit
                      closer than the text inside them and read as one block. */
                   min-height:22px; margin-top:7px; }
.co_axis > span  { flex:0 0 96px; line-height:1.3; }
.co_axis > .th_bar { flex:1; }
.co_axis > b     { flex:0 0 26px; text-align:right; color:#27251E; }

/* Wider label column for rows whose names are phrases rather than words —
   "Capital expenditure" wrapped to two lines at 96px and cut against the bar.
   A modifier rather than widening `.co_axis` for everyone: the conviction
   breakdown's labels are single words and would just lose bar to whitespace. */
/* Tighter than the base row, not looser. These labels no longer wrap — that
   was the original complaint and the wider column fixed it — so the extra
   height was buying nothing and only spreading three rows over the panel. */
.co_axis.is-wide          { min-height:18px; margin-top:3px; }
.co_axis.is-wide > span   { flex:0 0 148px; white-space:nowrap; overflow:hidden;
                            text-overflow:ellipsis; }
.co_axis.is-wide > b      { flex:0 0 34px; }

/* ---- price chart ---- */

.co_pxsvg        { width:100%; height:200px; display:block; }
.co_pxline       { fill:none; stroke:#269DF0; stroke-width:1.6; vector-effect:non-scaling-stroke; }
.co_fvband       { fill:rgba(232,166,0,.12); }
.co_fvmidline    { stroke:#e8a600; stroke-width:1.1; stroke-dasharray:5 4;
                   vector-effect:non-scaling-stroke; }
.co_pin line     { stroke:rgba(148,163,184,.35); stroke-width:1; vector-effect:non-scaling-stroke; }
.co_pin polygon  { fill:#9aa0a8; }
.co_pin polygon.is-pos { fill:#0f9d76; }
.co_pin polygon.is-neg { fill:#b3261e; }
.co_pxfoot       { display:flex; justify-content:space-between; font-size:10px; color:#9aa0a8;
                   margin-top:2px; }

/* Last close: a dotted rule across to a dot and a priced tag on the right edge,
   the same arrangement the instrument chart uses. */
.co_lastrule     { stroke:#c8ccd2; stroke-width:1; stroke-dasharray:3 4;
                   vector-effect:non-scaling-stroke; }
/* Each tag matches the SERIES it labels, not the day's move: one line and no
   comparison on this chart, so a red tag on a blue line asked the reader to
   find a relationship that is not there. */
.co_lastdot      { fill:#269DF0; }
.co_pxtag.is-px  { fill:#269DF0; }
.co_pxtag.is-fv  { fill:#e8a600; }
.co_pxtagtxt     { font-family:'Open Sans', sans-serif; font-size:11px; font-weight:600;
                   fill:#fff; }

.co_synth_how    { margin-top:8px; padding-top:8px; border-top:1px solid #eceff4;
                   font-size:10.5px; line-height:1.55; color:#9aa0a8; }

/* ---- valuation ---- */

.co_valgrid      { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@media (max-width: 1100px) { .co_valgrid { grid-template-columns:1fr; } }

.co_assume       { display:grid; grid-template-columns:repeat(3, 1fr); gap:10px 16px; }
@media (max-width: 900px) { .co_assume { grid-template-columns:repeat(2, 1fr); } }
.co_assume_f     { display:block; min-width:0; }
.co_assume_l     { display:block; font-size:10.5px; color:#9aa0a8; margin-bottom:3px; }
.co_assume_l i   { margin-left:4px; opacity:0.6; }
/* The field itself is a plain w2ui number input (the app's one number-field
   pattern). Nothing about it is restyled here; this only lays it out beside
   its unit, at the panel's smaller type. */
.co_assume_in    { display:flex; align-items:center; gap:5px; }
.co_assume_in > input.w2ui-input { flex:1 1 auto; min-width:0; box-sizing:border-box; font-size:11.5px; }
.co_assume_in b  { font-size:10.5px; color:#9aa0a8; flex:0 0 auto; }
/* Spans the assumption grid, so the provenance note sits under the fields it
   describes rather than in the panel head where it read as a title. */
.co_assume_f2    { grid-column:1 / -1; font-size:10.5px; color:#9aa0a8; }

/* The DCF build, as a second body under the assumptions that drive it. The
   rule is what separates inputs from output inside one panel. */
.co_dcfbody      { border-top:1px solid #eceff4; }

/* The DCF answer. Neutral until there is a price to judge it against — the
   colour is a comparison, not decoration, so an uncomparable number stays grey
   rather than defaulting to green. */
.co_dcfval       { display:inline-flex; align-items:baseline; gap:6px;
                   font-weight:600; color:#41506b; font-variant-numeric:tabular-nums; }
.co_dcfval i     { font-style:normal; font-size:0.72em; opacity:0.85; }
.co_dcfval.is-big{ font-size:19px; }
.co_dcfval.is-pos{ color:#0f9d76; }
.co_dcfval.is-neg{ color:#b3261e; }

/* ONE header style across every table in the workspace.
   `.co_tbl` used to right-align every header, so "Holder", "Date" and "Name"
   sat over left-aligned text — and it was sentence case while `.co_table` (the
   radar and the peer bench) was uppercase, so the two halves of the same screen
   disagreed. The rule is now the same as `.co_table thead th`: uppercase,
   tracked, left by default, and RIGHT only where the column is numeric — which
   the markup already declares with `class=num`. */
.co_tbl          { width:100%; border-collapse:collapse; font-size:11px; }
.co_tbl th       { text-align:left; font-size:10px; font-weight:600; letter-spacing:0.3px;
                   text-transform:uppercase; color:#9aa0a8;
                   padding:6px 8px; border-bottom:1px solid #e2e5ea; white-space:nowrap; }
.co_tbl th.num   { text-align:right; }
.co_tbl td       { padding:5px 8px; border-bottom:1px solid #f0f2f5; color:#41506b; }
.co_tbl .num     { text-align:right; font-variant-numeric:tabular-nums; }
/* Signed figures in PLAIN colour, no fill — a background here would compete
   with the BEAT/MISS chip two columns over, and the move is a magnitude to
   read rather than a verdict to spot.
   Scoped to `td` and `b` deliberately: the chip span in the same row also
   carries `is-neg`, and a looser selector would repaint the chip's text. */
.co_tbl td.is-pos, .th_kvrow b.is-pos { color:#0f9d76; }
.co_tbl td.is-neg, .th_kvrow b.is-neg { color:#b3261e; }
.co_dcf_sum      { margin-top:9px; padding-top:8px; border-top:1px solid #eceff4; }

/* SEPARATE cells, not a ruled table: each is a discrete scenario, and the gaps
   are what let a block of green read as a block. */
.co_heat         { width:100%; border-collapse:separate; border-spacing:3px; font-size:11px; }
.co_heat th      { text-align:right; font-size:10px; font-weight:600; color:#9aa0a8; padding:4px 6px; }
.co_heat td      { border-radius:4px; cursor:pointer; color:#fff !important;
                   font-weight:600; transition:filter .12s; }
.co_heat td:hover           { filter:brightness(1.18); }
.co_heat td.is-undef        { background:transparent; cursor:default; color:#b9bec6 !important;
                              font-weight:400; }
.co_heat td.is-undef:hover  { filter:none; }
/* The row-header column shrinks to its content. `width:1%` on a table cell is
   the standard way to say "as narrow as the text allows" — without it the
   column claimed an equal share and squeezed the grid the panel is about. */
.co_heat_c       { width:1%; white-space:nowrap; }
.co_heat td      { padding:6px; text-align:right; }
/* The live assumption set, ringed in the workspace's amber rather than its blue:
   blue is the SELECTION colour on claims and chain nodes, and this cell is not
   selected — it is where the model currently stands. An INSET ring so the cell
   does not change size and shift the grid. */
.co_h.is-cur     { box-shadow:0 0 0 2px #e8a600 inset; }

.co_rev          { text-align:center; padding:6px 0 10px; }
.co_rev_big      { font-size:30px; font-weight:600; color:#27251E; line-height:1.1; }
.co_rev_big span { font-size:15px; color:#9aa0a8; margin-left:2px; }
.co_rev_lbl      { font-size:10.5px; color:#9aa0a8; }

/* A dot-range: where today's multiple sits inside its own decade. */
.co_dr           { margin-bottom:13px; }
.co_dr_h         { display:flex; justify-content:space-between; align-items:baseline;
                   font-size:11.5px; color:#6b7280; }
.co_dr_h b       { color:#27251E; }
.co_dr_h b.is-pos{ color:#0f9d76; }
.co_dr_h b.is-neg{ color:#b3261e; }
.co_dr_t         { position:relative; height:8px; border-radius:4px; margin:6px 0 4px;
                   background:#eceff4; }
.co_dr_fill      { position:absolute; left:0; right:0; top:0; bottom:0; border-radius:4px;
                   background:linear-gradient(90deg,#e4e7ec,#cdd3db); }
.co_dr_med       { position:absolute; top:-2px; width:2px; height:12px; background:#9aa0a8; }
.co_dr_cur       { position:absolute; top:-3px; width:3px; height:14px; background:#269DF0;
                   border-radius:2px; }
/* A hoverable target around a 2px mark. The tooltip is useless if the only way
   to trigger it is to land the pointer on a hairline, so each marker carries an
   invisible box roughly a finger wide. Drawn on the marker itself so it tracks
   the same `left`. */
.co_dr_med, .co_dr_cur { cursor:default; }
.co_dr_med::after,
.co_dr_cur::after { content:""; position:absolute; left:-6px; right:-6px;
                    top:-4px; bottom:-4px; }
.co_dr_f         { display:flex; justify-content:space-between; font-size:10px; color:#9aa0a8; }

.co_method       { border-bottom:1px solid #f0f2f5; padding:6px 0; }
.co_method:last-child { border-bottom:none; }
.co_method_h     { display:flex; justify-content:space-between; gap:10px; font-size:11.5px;
                   color:#41506b; }
.co_method_h b   { color:#27251E; }
.co_method_f     { font-size:10px; color:#9aa0a8; margin-top:2px; }
.co_synth        { margin-top:9px; padding-top:8px; border-top:1px solid #eceff4; }

.co_ta           { width:100%; box-sizing:border-box; font-family:'Open Sans', sans-serif;
                   font-size:12px; line-height:1.55; padding:9px 10px; border:1px solid #d5dae1;
                   border-radius:4px; background:#fff; color:#27251E; resize:vertical; }
.co_ta:focus     { outline:none; border-color:#269DF0; box-shadow:0 0 0 1px #269DF0 inset; }

.co_scorerow     { display:flex; align-items:center; gap:10px; margin-bottom:9px; font-size:12px;
                   color:#41506b; }
.co_scorerow > span     { flex:1; }
.co_scorerow .co_scorenum { flex:0 0 96px; display:flex; }

/* ---- fundamentals ---- */

/* The ten-year table scrolls SIDEWAYS on its own. Twelve year columns plus a
   metric label do not fit a narrow window, and letting the page scroll instead
   would take the row labels off-screen with them. */
.co_fundwrap    { overflow-x:auto; padding:0; }
.co_fund        { width:100%; border-collapse:collapse; font-size:11px; }
.co_fund th     { text-align:right; font-size:10px; font-weight:600; color:#9aa0a8;
                  padding:6px 8px; border-bottom:1px solid #e2e5ea; white-space:nowrap; }
.co_fund thead th:first-child,
.co_fund .co_fund_k { text-align:left; }
.co_fund td     { padding:5px 8px; border-bottom:1px solid #f0f2f5; color:#41506b;
                  white-space:nowrap; }
.co_fund .num   { text-align:right; font-variant-numeric:tabular-nums; }
/* The metric column stays put while the years scroll under it — losing the row
   label is what makes a wide table unreadable. */
.co_fund_k      { position:sticky; left:0; z-index:1; background:#fff;
                  font-weight:600; color:#27251E; font-size:11px; }
.co_fund_d      { font-weight:600; color:#27251E; }
/* The tint has to survive being read at 11px against a panel background, which
   the first pass at .10/.09 did not — it was visible only if you already knew
   where to look, and in dark mode the two were near-indistinguishable. */
.co_fund td.is-best  { background:rgba(15,157,118,.18); }
.co_fund td.is-worst { background:rgba(179,38,30,.16); }
.co_sparkcell   { width:80px; }
.co_spark       { width:76px; height:20px; display:block; }
.co_spark polyline { fill:none; stroke-width:1.3; stroke-linejoin:round; stroke-linecap:round;
                  vector-effect:non-scaling-stroke; }
.co_spark.is-pos polyline { stroke:#0f9d76; }
.co_spark.is-neg polyline { stroke:#b3261e; }

/* ---- peers / ownership ---- */

/* Hover WITHOUT a pointer: the row is nine columns wide and the highlight is
   what lets you read across it, but only the ticker is clickable now, so a
   pointer over the whole row would promise a click that does nothing. */
.co_peerrow:hover td { background:#f2f7fd; }
/* Best-in-column. Deliberately the SAME green as the ten-year record's best
   year — one "this is the winner" colour across the workspace rather than a
   second one to learn. Ordered after the hover rule so passing the mouse over
   a row does not wipe out the marks the reader is comparing. */
.co_table td.is-best,
.co_peerrow:hover td.is-best { background:rgba(15,157,118,.18); font-weight:600; }
.co_selfrow td  { background:#f2f7fd; font-weight:600; }
/* The bench's own line, set off as a summary rather than another peer: a
   heavier top rule and no hover, because it is not a row you can open. */
.co_medianrow td { background:#f7f8fa; font-weight:600;
                   border-top:2px solid #e2e5ea; border-bottom:none; }
.co_medianrow .co_name { font-weight:400; color:#9aa0a8; }
.co_insider_t   { font-size:10px; color:#9aa0a8; }
.co_insider_f   { padding:8px 12px; font-size:10.5px; line-height:1.5; color:#9aa0a8;
                  border-top:1px solid #f0f2f5; }

/* Insider net activity: monthly bars around a zero line. */
.co_isvg        { width:100%; height:130px; display:block; }
.co_ibar        { cursor:default; }
.co_izero       { stroke:#d5dae1; stroke-width:1; vector-effect:non-scaling-stroke; }
.co_iaxis       { font-family:'Open Sans', sans-serif; font-size:11px; fill:#9aa0a8; }
.co_ibar.is-buy  { fill:#3fbf8f; }
.co_ibar.is-sell { fill:#e2544f; }
.co_ifoot       { display:flex; justify-content:space-between; font-size:10px; color:#9aa0a8;
                  margin-top:2px; padding:0 10px; }

/* The bench chip strip. `.charts_tag*` are the Charts screen's own classes,
   reused rather than restyled — this only positions the strip and the add
   button inside the panel head area. */
.co_peerbar     { padding:8px 12px; border-bottom:1px solid #eceff4; }
.co_peerbar .charts_tags { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
/* The count travels WITH the + button, at the right-hand end.
   With `margin-left:auto` on the button alone, the count stayed where the chips
   happened to end and the button jumped to the far edge — "7/12" stranded
   mid-row, reading as another chip rather than as a caption on the control it
   describes.
   Flex GROWTH rather than a second auto margin: two auto margins split the free
   space equally between them, which would have left the count halfway again. */
.co_peerbar .charts_tags_count { flex:1 1 auto; text-align:right; }
/* Same job in the empty state, but the message keeps its natural left edge —
   it is a prompt to read, not a caption on the button. */
.co_peerbar .charts_tags_empty { flex:1 1 auto; }

/* The verdict reads as PROSE, not as a data row — it is the one place on the
   tab that says what the numbers mean together, and 11px muted body text would
   bury it under the table it is summarising. */
.co_verdict     { margin:0; font-size:12.5px; line-height:1.6; color:#41506b; }
.co_verdict_f   { margin-top:9px; padding-top:8px; border-top:1px solid #eceff4;
                  font-size:11px; line-height:1.5; color:#9aa0a8; }

/* ---- segment editor ---- */

.co_segdlg      { min-width:0; }
.co_segtbl      { width:100%; border-collapse:collapse; font-size:11.5px; }
.co_segtbl th   { text-align:left; font-size:10px; font-weight:600; letter-spacing:0.3px;
                  text-transform:uppercase; color:#9aa0a8;
                  padding:4px 6px; border-bottom:1px solid #e2e5ea; }
.co_segtbl td   { padding:4px 6px; vertical-align:middle; }
.co_segtbl input[type=number].w2ui-input { min-width:78px; width:100%; box-sizing:border-box; font-size:11.5px; }
.co_seg_n       { width:100%; box-sizing:border-box; font-family:'Open Sans', sans-serif;
                  font-size:11.5px; height:26px; padding:0 8px;
                  border:1px solid #d8d6d2; border-radius:3px; background:#fff; color:#333; }
.co_seg_n:focus { outline:none; border-color:#2F9EEE; box-shadow:0 0 0 1px #2F9EEE inset; }
.co_seggap      { margin-top:8px; font-size:11px; color:#9aa0a8; }
.co_seggap.is-warn { color:#9a6a10; font-weight:600; }

/* ---- dark ---- */

body.appbuilder-dark .co_fund_k,
body.appbuilder-dark .co_fund_d        { color:#e6e6ea; }
body.appbuilder-dark .co_fund_k        { background:#22262b; }
body.appbuilder-dark .co_fund th       { color:#8b919b; border-bottom-color:#3a3f47; }
body.appbuilder-dark .co_fund td       { color:#c3c8d0; border-bottom-color:#33373d; }
/* Dark needs MORE alpha, not less: a translucent tint over #22262b lands much
   closer to the background than the same alpha over white, which is why the
   two read as almost the same grey at .14. */
body.appbuilder-dark .co_fund td.is-best  { background:rgba(95,211,171,.28); }
body.appbuilder-dark .co_fund td.is-worst { background:rgba(239,154,154,.26); }
body.appbuilder-dark .co_spark.is-pos polyline { stroke:#5fd3ab; }
body.appbuilder-dark .co_spark.is-neg polyline { stroke:#ef9a9a; }
body.appbuilder-dark .co_peerrow:hover td { background:var(--bg-hover); }
body.appbuilder-dark .co_table td.is-best,
body.appbuilder-dark .co_peerrow:hover td.is-best { background:rgba(95,211,171,.28); }
body.appbuilder-dark .co_selfrow td    { background:#2f3a45; }
body.appbuilder-dark .co_medianrow td  { background:#262a30; border-top-color:#3a3f47; }
body.appbuilder-dark .co_medianrow .co_name { color:#8b919b; }
body.appbuilder-dark .co_peerbar       { border-bottom-color:#3a3f47; }
body.appbuilder-dark .co_verdict       { color:#c3c8d0; }
body.appbuilder-dark .co_verdict_f     { color:#8b919b; border-top-color:#33373d; }
body.appbuilder-dark .co_about,
body.appbuilder-dark .co_stance_h,
body.appbuilder-dark .co_sig_e,
body.appbuilder-dark .co_news_b        { color:#c3c8d0; }
body.appbuilder-dark .co_sig_k,
body.appbuilder-dark .co_watch_f,
body.appbuilder-dark .co_stance_c > b  { color:#e6e6ea; }
body.appbuilder-dark .co_watch_c,
body.appbuilder-dark .co_lines_h,
body.appbuilder-dark .co_lines_f,
body.appbuilder-dark .co_watch_m       { color:#8b919b; }
body.appbuilder-dark .co_line_t        { color:#c3c8d0; }
body.appbuilder-dark .co_lines         { border-top-color:#33373d; }
body.appbuilder-dark .co_line          { border-bottom-color:#33373d; }
body.appbuilder-dark .co_watch_hot td  { background:rgba(239,154,154,.10); }
body.appbuilder-dark .co_watch_bar     { background:#3a3f47; }
body.appbuilder-dark .co_verdict_hash,
body.appbuilder-dark .co_stance_cl,
body.appbuilder-dark .co_stance_cf     { color:#8b919b; }
body.appbuilder-dark .co_stance_bar    { background:#3a3f47; }
body.appbuilder-dark .co_vsplit        { border-top-color:#33373d; }
body.appbuilder-dark .co_crc           { background:#2a2a2a; border-color:#33373d; }
body.appbuilder-dark .co_crc_t         { color:#e6e6ea; }
body.appbuilder-dark .co_crc_d         { color:#c3c8d0; }
body.appbuilder-dark .co_crc_m > i     { color:#8b919b; }
body.appbuilder-dark .co_crc_f         { background:rgba(239,154,154,.09);
                                         border-left-color:#ef9a9a; color:#cbb8b6; }
body.appbuilder-dark .co_crc_f > b     { color:#ef9a9a; }
body.appbuilder-dark .co_crc_f.is-missing { background:rgba(240,180,0,.10);
                                         border-left-color:#f0b400; color:#e0c07a; }
body.appbuilder-dark .co_evwhy,
body.appbuilder-dark .co_evdoc_l       { color:#c3c8d0; }
body.appbuilder-dark .co_evalnote,
body.appbuilder-dark .co_evalgrp_h     { color:#c3c8d0; }
body.appbuilder-dark .co_evmlab        { color:#e6e6ea; }
body.appbuilder-dark .co_evmwhat,
body.appbuilder-dark .co_evln          { color:#8b919b; }
body.appbuilder-dark .co_evlci         { color:#c3c8d0; }
body.appbuilder-dark .co_evmcav        { background:#3a3223; color:#f0b400; }
body.appbuilder-dark .co_rdsum         { color:#c3c8d0; }
body.appbuilder-dark .co_rdsum > b     { color:#e6e6ea; }
body.appbuilder-dark .co_rdgrp_h > i,
body.appbuilder-dark .co_rdsim,
body.appbuilder-dark .co_rdwas_l       { color:#8b919b; }
body.appbuilder-dark .co_rd            { border-bottom-color:#33373d; }
body.appbuilder-dark .co_rd > summary  { color:#e6e6ea; }
body.appbuilder-dark .co_rd > summary:hover { background:var(--bg-hover); }
body.appbuilder-dark .co_rdnow,
body.appbuilder-dark .co_rdwas         { background:#2f2f2f; border-left-color:#3a3f47;
                                         color:#c3c8d0; }
body.appbuilder-dark .co_evdoc         { border-bottom-color:#33373d; }
body.appbuilder-dark .co_srcname       { color:#8ab4f8; }
/* The sticky head is OPAQUE by necessity: rows scroll underneath it, and a
   transparent head would show them through the labels. */
body.appbuilder-dark .co_tablewrap .co_tbl thead th {
	background:var(--bg-panel, #2b2b2b); box-shadow:inset 0 -1px 0 #3a3f47;
}
body.appbuilder-dark .co_evtext        { color:#e6e6ea; }
body.appbuilder-dark .co_evfals,
body.appbuilder-dark .co_evsrc         { color:#8b919b; }
body.appbuilder-dark .co_evwarn        { color:#ef9a9a; }
body.appbuilder-dark .co_evrow_nf td   { background:rgba(239,154,154,.07); }
body.appbuilder-dark .co_evspan blockquote { background:#2f2f2f; border-left-color:#3a3f47;
                                             color:#c3c8d0; }
body.appbuilder-dark .co_evnospan      { color:#ef9a9a; }
body.appbuilder-dark .co_revlab        { color:#e6e6ea; }
body.appbuilder-dark .co_revabs        { color:#8b919b; }
body.appbuilder-dark .co_fy            { border-top-color:#33373d; }
body.appbuilder-dark .co_fy_h          { background:#2f2f2f; }
body.appbuilder-dark .co_fy_h > span   { color:#c3c8d0; }
body.appbuilder-dark .co_fy_n,
body.appbuilder-dark .co_fday,
body.appbuilder-dark .co_fsrc,
body.appbuilder-dark .co_fper          { color:#8b919b; }
body.appbuilder-dark .co_fwhat,
body.appbuilder-dark .co_fdate > b     { color:#e6e6ea; }
body.appbuilder-dark .co_tlrow_open:hover td { background:var(--bg-hover); }
body.appbuilder-dark .co_fsep          { background:#3a3f47; }
body.appbuilder-dark .co_read_p        { color:#c3c8d0; }
body.appbuilder-dark .co_sigbox        { background:#2a2a2a; border-color:#33373d; }
/* The bear block goes DARKER than its surroundings, not lighter. A pale red
   card on a dark page glares and pulls the eye off everything else; the point
   is that it is set apart, not that it shouts. */
body.appbuilder-dark .co_bear          { background:rgba(239,154,154,.09);
                                         border-left-color:#ef9a9a; }
body.appbuilder-dark .co_bear_h        { color:#ef9a9a; }
body.appbuilder-dark .co_bear_h > span { color:#a98a8a; }
body.appbuilder-dark .co_bear_p        { color:#cbb8b6; }
body.appbuilder-dark .co_bear_p > b,
body.appbuilder-dark .co_bear_k > b    { color:#ef9a9a; }
body.appbuilder-dark .co_bear_k        { color:#a98a8a; }
body.appbuilder-dark .co_stance_tag.is-bull { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .co_stance_tag.is-bear { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .co_stance_tag.is-neut { background:#3a3223; color:#f0b400; }
body.appbuilder-dark .co_fact > b      { color:#e6e6ea; }
body.appbuilder-dark .co_facts         { border-top-color:#33373d; }
body.appbuilder-dark .co_news          { border-bottom-color:#33373d; }
body.appbuilder-dark .co_news_dot      { background:#4a5058; }
body.appbuilder-dark .co_news_dot.is-pos { background:#5fd3ab; }
body.appbuilder-dark .co_news_dot.is-neg { background:#ef9a9a; }
body.appbuilder-dark .co_fact > span,
body.appbuilder-dark .co_news_d,
body.appbuilder-dark .co_insider_t,
body.appbuilder-dark .co_insider_f,
body.appbuilder-dark .co_iaxis,
body.appbuilder-dark .co_ifoot,
body.appbuilder-dark .co_seggap        { color:#8b919b; }
body.appbuilder-dark .co_iaxis         { fill:#8b919b; }
body.appbuilder-dark .co_izero         { stroke:#3a3f47; }
body.appbuilder-dark .co_insider_f     { border-top-color:#33373d; }
body.appbuilder-dark .co_seggap.is-warn{ color:#f0b400; }
body.appbuilder-dark .co_segtbl th     { color:#8b919b; border-bottom-color:#3a3f47; }
body.appbuilder-dark .co_seg_n         { background:#1f2124; border-color:#3f4348; color:#e6e6e6; }
body.appbuilder-dark .co_seg_n:focus   { border-color:#7ab1f0; box-shadow:0 0 0 1px #7ab1f0 inset; }

body.appbuilder-dark .co_h1,
body.appbuilder-dark .co_hd_h1,
body.appbuilder-dark .co_tick,
body.appbuilder-dark .co_metric_v,
body.appbuilder-dark .co_kpi_v,
body.appbuilder-dark .co_rev_big,
body.appbuilder-dark .co_conv > b,
body.appbuilder-dark .co_dr_h b,
body.appbuilder-dark .co_method_h b,
body.appbuilder-dark .co_fv_f b,
body.appbuilder-dark .co_heat td,
body.appbuilder-dark .co_axis > b      { color:#e6e6ea; }

body.appbuilder-dark .co_sub,
body.appbuilder-dark .co_name,
body.appbuilder-dark .co_tbl td,
body.appbuilder-dark .co_method_h,
body.appbuilder-dark .co_dr_h,
body.appbuilder-dark .co_fv_f,
body.appbuilder-dark .co_axis,
body.appbuilder-dark .co_scorerow      { color:#c3c8d0; }

body.appbuilder-dark .co_eyebrow,
body.appbuilder-dark .co_sector,
body.appbuilder-dark .co_metric_l,
body.appbuilder-dark .co_metric_f,
body.appbuilder-dark .co_kpi_l,
body.appbuilder-dark .co_kpi_u,
body.appbuilder-dark .co_kpi_f,
body.appbuilder-dark .co_assume_l,
body.appbuilder-dark .co_assume_f2,
body.appbuilder-dark .co_assume_in b,
body.appbuilder-dark .co_rev_lbl,
body.appbuilder-dark .co_dr_f,
body.appbuilder-dark .co_method_f,
body.appbuilder-dark .co_pxfoot,
body.appbuilder-dark .co_foot,
body.appbuilder-dark .co_tbl th,
body.appbuilder-dark .co_heat th       { color:#8b919b; }

/* The KPI tiles need `border-color`, not `border-bottom-color`.
   They used to share a rule with `.co_fvbox`; replacing that line with the
   header band left them attached to a selector list whose declaration only
   repaints the BOTTOM edge, so three sides of every tile kept the light-mode
   grey and the panel grew white boxes. */
body.appbuilder-dark .co_metric,
body.appbuilder-dark .co_kpi,
body.appbuilder-dark .co_hdblock       { background:#2b2f35; border-color:#3a3f47; }
body.appbuilder-dark .co_fvbox_hint    { color:#8d949c; }
body.appbuilder-dark .co_ws_head       { background:#26292e; border-bottom-color:#3a3f47; }
body.appbuilder-dark .co_savestate,
body.appbuilder-dark .co_synth_how,
body.appbuilder-dark .co_fvbox_none    { color:#8b919b; }
body.appbuilder-dark .co_savestate.is-saved,
body.appbuilder-dark .co_dcfval.is-pos { color:#5fd3ab; }
body.appbuilder-dark .co_savestate.is-failed,
body.appbuilder-dark .co_dcfval.is-neg { color:#ef9a9a; }
body.appbuilder-dark .co_synth_how     { border-top-color:#33373d; }
body.appbuilder-dark .co_dcfval        { color:#c3c8d0; }
body.appbuilder-dark .co_lastrule      { stroke:#4a5058; }
/* The number fields are NOT listed here — they are plain w2ui inputs, whose
   dark palette, focus ring and stepper come from the global input rules. */
body.appbuilder-dark .co_search,
body.appbuilder-dark .co_ta            { background:#22262b; border-color:#3a3f47; color:#e6e6ea; }
body.appbuilder-dark .co_search:focus,
body.appbuilder-dark .co_ta:focus      { border-color:#4a9eff; box-shadow:0 0 0 1px #4a9eff inset; }

body.appbuilder-dark .co_table thead th { background:#2b2f35; border-bottom-color:#3a3f47; }
body.appbuilder-dark .co_table td       { border-bottom-color:#33373d; }
/* --bg-hover, the theme's own hover surface, not a bespoke near-black. The
   first attempt (#252b33) was DARKER than the row it sat on and read as a
   shadow rather than as a highlight; this is a clear step up from the panel. */
body.appbuilder-dark .co_row:hover td   { background:var(--bg-hover); }
body.appbuilder-dark .co_th.is-sorted   { color:#4a9eff; }
body.appbuilder-dark .co_cbar,
body.appbuilder-dark .co_fvbar,
body.appbuilder-dark .co_dr_t           { background:#3a3f47; }
body.appbuilder-dark .co_cbar > i       { background:#3d6ea8; }
body.appbuilder-dark .co_dr_fill        { background:linear-gradient(90deg,#3a3f47,#4a5058); }
body.appbuilder-dark .co_dr_cur,
body.appbuilder-dark .co_fv_px          { background:#4a9eff; }
body.appbuilder-dark .co_pxline         { stroke:#4a9eff; }
body.appbuilder-dark .co_h.is-cur       { box-shadow:0 0 0 2px #f0b400 inset; }
body.appbuilder-dark .co_heat td.is-undef { color:#6b7280 !important; }
body.appbuilder-dark .co_dcfbody,
body.appbuilder-dark .co_tbl th,
body.appbuilder-dark .co_tbl td,
body.appbuilder-dark .co_dcf_sum,
body.appbuilder-dark .co_synth,
body.appbuilder-dark .co_method         { border-color:#33373d; }
body.appbuilder-dark .co_filterbar      { background:var(--bg-panel); border-bottom-color:var(--border); }
body.appbuilder-dark .co_clfilters      { border-bottom-color:var(--border); }
body.appbuilder-dark .co_flabel         { color:#8d949c; }
body.appbuilder-dark .co_fsep           { background:var(--border); }
body.appbuilder-dark .co_dot            { background:#4a4f57; }
body.appbuilder-dark .co_tonechip.is-draft     > .co_dot { background:#8d949c; }
body.appbuilder-dark .co_tonechip.is-watchlist > .co_dot { background:#8ab4f8; }
body.appbuilder-dark .co_tonechip.is-paper     > .co_dot { background:#f0b400; }
body.appbuilder-dark .co_tonechip.is-live      > .co_dot { background:#5fd3ab; }
body.appbuilder-dark .co_tonechip.is-neg       > .co_dot { background:#ff8a80; }
body.appbuilder-dark .co_tonechip.is-neg.on       { background:#3a2323; border-color:#6b3a3a; color:#ff8a80; }
body.appbuilder-dark .co_tonechip.is-draft.on     { background:#2c2f33; border-color:#4a4f57; color:#c3cad2; }
body.appbuilder-dark .co_tonechip.is-watchlist.on { background:#1e2c44; border-color:#33507d; color:#8ab4f8; }
body.appbuilder-dark .co_tonechip.is-paper.on     { background:#3a2f1a; border-color:#6b5520; color:#f0b400; }
body.appbuilder-dark .co_tonechip.is-live.on      { background:#17301f; border-color:#2c5a3c; color:#5fd3ab; }
body.appbuilder-dark .co_revisit        { color:#8d949c; }
body.appbuilder-dark .co_revisit.is-due { color:#f0b400; }
body.appbuilder-dark .co_evwhy2         { color:#8d949c; }
body.appbuilder-dark .co_tlnote         { color:#a8b0b9; border-bottom-color:var(--border); }
body.appbuilder-dark .co_web            { color:#e6e6e6; }
body.appbuilder-dark .co_websec         { color:#c3cad2; }
body.appbuilder-dark .co_webq           { color:#c3cad2; }
body.appbuilder-dark .co_weberr         { color:#ef9a9a; }
body.appbuilder-dark .co_webrow         { border-bottom-color:#33373d; }
body.appbuilder-dark .co_webrow:hover   { background:var(--bg-hover, #3a3a3a); }
body.appbuilder-dark .co_webtitle       { color:#e6e6e6; }
body.appbuilder-dark .co_weburl,
body.appbuilder-dark .co_webnote,
body.appbuilder-dark .co_webbusy_s      { color:#8d949c; }
body.appbuilder-dark .co_webbusy_h      { color:#c8cfd6; }
body.appbuilder-dark .co_webopen:hover  { color:#8ab4f8; }
body.appbuilder-dark .co_briefage       { color:#8d949c; }
body.appbuilder-dark .co_brief_re       { background:var(--bg-elev, #333);
                                          border-color:var(--border-strong, #505050);
                                          color:#c3cad2; }
body.appbuilder-dark .co_brief_re:hover { background:var(--bg-hover, #3a3a3a); }
body.appbuilder-dark .co_srcurl         { background:var(--bg-elev, #333);
                                          border-color:var(--border-strong, #505050);
                                          color:var(--fg, #e6e6e6); }
body.appbuilder-dark .co_srcchk         { color:#c3cad2; }
body.appbuilder-dark .co_srcmsg         { color:#aab2bb; }
body.appbuilder-dark .co_srcwarn        { color:#f0b400; }
body.appbuilder-dark .co_evdoc.is-flash { animation:co_flash_dark 1.6s ease-out; }
@keyframes co_flash_dark {
	0%   { background:#1e2c44; }
	100% { background:transparent; }
}
body.appbuilder-dark .co_srcpick        { background:var(--bg-elev, #333);
                                          border-color:var(--border-strong, #505050); }
body.appbuilder-dark .co_srcrow         { color:#c3cad2; }
body.appbuilder-dark .co_srcrow:hover   { background:var(--bg-hover, #3a3a3a); }
body.appbuilder-dark .co_srcrow.is-on   { background:#1e2c44; color:#8ab4f8; }
body.appbuilder-dark .co_evdoc_l.gridurl      { color:#8ab4f8; }
body.appbuilder-dark .co_fday.gridurl:hover   { color:#8ab4f8; }
body.appbuilder-dark .co_vlbl           { color:#c3cad2; }
body.appbuilder-dark .co_vnote,
body.appbuilder-dark .co_vdate          { background:var(--bg-elev, #333);
                                          border-color:var(--border-strong, #505050);
                                          color:var(--fg, #e6e6e6); }
body.appbuilder-dark .co_vhint          { color:#8d949c; }
body.appbuilder-dark .co_rev            { background:var(--bg-panel);
                                          border-color:var(--border);
                                          border-left-color:#4a4f55; }
body.appbuilder-dark .co_rev.is-open    { border-left-color:#4a9eff; }
body.appbuilder-dark .co_rev_d,
body.appbuilder-dark .co_rev_m          { color:#8d949c; }
body.appbuilder-dark .co_rev_n          { color:#c3cad2; }
body.appbuilder-dark .co_gap.is-pos     { color:#5fd3ab; }
body.appbuilder-dark .co_gap.is-neg     { color:#ef9a9a; }
body.appbuilder-dark .co_tbl td.is-pos,
body.appbuilder-dark .th_kvrow b.is-pos { color:#5fd3ab; }
body.appbuilder-dark .co_tbl td.is-neg,
body.appbuilder-dark .th_kvrow b.is-neg { color:#ef9a9a; }
body.appbuilder-dark .co_soon           { color:#f0b400; }

/* ---- Funds segment -------------------------------------------------
   Morningstar stars in the grid. Drawn as glyphs rather than printed as a
   number because the rating is scanned down a column — "4" does not read at
   a glance the way four filled stars do. The unearned stars stay in place at
   low opacity rather than being omitted, so every cell is the same width and
   a 2-star fund reads as 2-of-5 rather than as a short row. */
.fund_stars     { color: #f5a623; letter-spacing: 1px; font-size: 12px; white-space: nowrap; }
.fund_stars_off { opacity: 0.22; }
body.appbuilder-dark .fund_stars { color: #ffb733; }

/* The peer-comparison bar: the fill is the fund, the tick is the Morningstar
   category average. `position:relative` is what lets the tick sit at an
   absolute offset along the same scale as the fill — the two MUST share a
   scale, or a 40% weight and a 40% category average would land in different
   places, which would make the card actively misleading. */
.fund_peer_track { position: relative; }
.fund_peer_tick {
	position: absolute; top: -2px; bottom: -2px; width: 2px;
	transform: translateX(-50%);
	background: var(--scr-fg-muted); opacity: 0.85;
	border-radius: 1px; pointer-events: none;
}
body.appbuilder-dark .fund_peer_tick { background: #e6e9ef; opacity: 0.7; }

/* The delta against the peer group, as a signed number. Over/under the
   category is NOT good/bad — a fund underweight technology is not losing —
   so this deliberately does NOT reuse .instr_up / .instr_down's green and
   red. Neutral weights with a subtle lean instead. */
.fund_peer_d {
	flex: 0 0 auto; min-width: 38px; text-align: right;
	font-size: 11px; font-variant-numeric: tabular-nums;
	color: var(--scr-fg-muted);
}
.fund_peer_d.is-over  { color: var(--scr-accent); }
.fund_peer_d.is-under { color: var(--scr-fg-muted); opacity: 0.75; }

/* ---- Screener: Apply filters is the primary action ------------------
   Accented so the one button that re-runs the query is distinguishable from
   Reset and More filters beside it, which only change the form.

   Uses --scr-accent rather than the app's w2ui-btn-blue for two reasons: that
   class is scoped to <button>/<input> and a w2toolbar item renders as a <div>,
   so it would not apply at all; and the token is the same one the active
   segment tab uses, so the panel's "this is the live thing" colour stays a
   single value rather than two near-identical blues.

   !important throughout, and at the full toolbar specificity, because the
   base theme already claims .w2ui-tb-button.over / .checked / .down with
   !important in BOTH schemes — without matching that, the button would revert
   to grey the moment it was hovered. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply {
	background-color: var(--scr-accent) !important;
	border-color: var(--scr-accent) !important;
	border-radius: 4px;
}
/* The label and the glyph are separate children and inherit the toolbar's
   grey, so the colour has to be set on them, not just on the box.

   NOTE THE `> span`. .w2ui-tb-icon is only a WRAPPER div; w2ui renders the
   glyph as <div class="w2ui-tb-icon"><span class="fa fa-search"></span></div>
   and w2ui.css colours that inner span DIRECTLY:

       .w2ui-tb-button .w2ui-tb-icon > span { color: #8D99A7 }

   A colour declared on the span beats anything inherited from its parent, so
   colouring the wrapper alone left the magnifier grey on the blue fill. The
   span has to be named explicitly. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-text,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon > span,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon .fa,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-text,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon > span,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply .w2ui-tb-icon .fa {
	color: #fff !important;
}

/* Hover / active. w2ui swaps .over on hover and .down while pressed. */
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.over,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply:hover,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.over,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply:hover {
	background-color: #1F84C6 !important;
	border-color: #1F84C6 !important;
}
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.down,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.checked,
.w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply:active,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.down,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply.checked,
body.appbuilder-dark .w2ui-toolbar .w2ui-scroll-wrapper .w2ui-tb-button.scr_apply:active {
	background-color: #1268A6 !important;
	border-color: #1268A6 !important;
}

/* ============================================================================
   Discretionary mandates (Portfolio ▸ Mandates)

   A mandate is read as a STATE, not a row of figures: how much of the intended
   position is built, and whether the price is currently somewhere the mandate
   will act. So each one is a card with a fill bar and a band readout rather
   than a grid line — a table of eight numeric columns answered neither question
   without the reader doing arithmetic.
   ========================================================================= */
.pf_mand { display:flex; flex-direction:column; min-height:0; }
.pf_mand_list { display:flex; flex-direction:column; gap:10px; padding:2px 0 12px; }

.pf_mand_row {
	border:1px solid #e3e6ec; background:#fff; border-radius:10px;
	padding:12px 14px; transition:border-color .12s, box-shadow .12s;
}
.pf_mand_row:hover { border-color:#c9d4e4; box-shadow:0 1px 4px rgba(20,30,50,.07); }
/* An entry band that cannot be resolved stops the portfolio starting, so it is
   flagged on the card that can fix it rather than only at Start. */
.pf_mand_row.is-broken { border-color:#eaa9a2; background:#fdf8f7; }

.pf_mand_head { display:flex; align-items:center; gap:10px; margin-bottom:10px; }
.pf_mand_sym  { font-family:OpenSans; font-weight:700; font-size:13px; color:#1f2937; }
.pf_mand_actions { margin-left:auto; display:flex; gap:4px; }
/* The card opens the mandate; the corner keeps Buy a slice and Remove. */
.pf_mand_row { cursor:pointer; }
/* PAUSED: the analyst's switch. Grey like At cap (a resting state, not a fault),
   and the figures recede so a paused mandate reads as set aside at a glance. */
.pf_mand_status.is-paused { background:#eceff4; border-color:#d5dae1; color:#6b7280; }
.pf_mand_row.is-paused .pf_mand_grid, .pf_mand_row.is-paused .pf_mand_research { opacity:.55; }
body.appbuilder-dark .pf_mand_status.is-paused { background:#2c2f35; border-color:#41454e; color:#9aa0ac; }

.pf_mand_status {
	font-size:10px; font-weight:600; letter-spacing:.2px; text-transform:uppercase;
	padding:2px 7px; border-radius:10px; border:1px solid transparent;
}
.pf_mand_status.is-working { background:#e8f5ec; border-color:#c3e3cf; color:#1d6b3a; }
/* "At cap" is a RESTING state, not a problem — the mandate did what it was told
   and is waiting for room. Grey, not amber: amber would read as a fault. */
.pf_mand_status.is-dormant { background:#eef0f3; border-color:#dcdfe5; color:#5b6472; }
.pf_mand_status.is-expired { background:#fdf7ec; border-color:#f0dcb4; color:#7a5b1a; }

.pf_mand_grid {
	display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:12px;
}
.pf_mand_cell { display:flex; flex-direction:column; gap:3px; min-width:0; }
.pf_mand_cell > label {
	font-size:10px; text-transform:uppercase; letter-spacing:.3px; color:#8a94a6; font-weight:600;
}
.pf_mand_cell > span { font-family:OpenSans; font-size:12.5px; color:#1f2937; }
.pf_mand_cell > span.is-broken { color:#a01a12; font-style:italic; }
.pf_mand_sub { font-size:10.5px; color:#8a94a6; }

/* Progress toward the cap. Deliberately calm — a mandate filling up is the
   plan working, not an alert. */
.pf_mand_bar { height:4px; border-radius:3px; background:#eceff3; overflow:hidden; margin-top:3px; }
.pf_mand_bar > i { display:block; height:100%; background:#4a90d9; border-radius:3px; }

/* Green only when the price is somewhere the mandate would actually buy. */
.pf_mand_in  { color:#1d6b3a; font-weight:600; }
.pf_mand_out { color:#5b6472; }

.pf_mand_note {
	margin-top:10px; padding-top:9px; border-top:1px solid #eef0f3;
	font-size:11.5px; color:#5b6472; line-height:1.5; font-style:italic;
}

.pf_btn.pf_btn_icon { padding:3px 8px; line-height:1.4; }

/* ---- dark ------------------------------------------------------------- */
body.appbuilder-dark .pf_mand_row { background:#24262b; border-color:#3a3d45; }
body.appbuilder-dark .pf_mand_row:hover { border-color:#4a4f5a; box-shadow:0 1px 4px rgba(0,0,0,.35); }
body.appbuilder-dark .pf_mand_row.is-broken { background:#2c2422; border-color:#6b3a34; }
body.appbuilder-dark .pf_mand_sym { color:#e4e7ee; }
body.appbuilder-dark .pf_mand_cell > label { color:#8b93a3; }
body.appbuilder-dark .pf_mand_cell > span { color:#d7dbe3; }
body.appbuilder-dark .pf_mand_cell > span.is-broken { color:#e88178; }
body.appbuilder-dark .pf_mand_sub { color:#8b93a3; }
body.appbuilder-dark .pf_mand_bar { background:#33363d; }
body.appbuilder-dark .pf_mand_bar > i { background:#5a9fe0; }
body.appbuilder-dark .pf_mand_in  { color:#6cc48d; }
body.appbuilder-dark .pf_mand_out { color:#9aa0ac; }
body.appbuilder-dark .pf_mand_note { border-top-color:#33363d; color:#9aa0ac; }
body.appbuilder-dark .pf_mand_status.is-working { background:#1e3226; border-color:#2f5a3c; color:#7fd39c; }
body.appbuilder-dark .pf_mand_status.is-dormant { background:#2c2f35; border-color:#41454e; color:#9aa0ac; }
body.appbuilder-dark .pf_mand_status.is-expired { background:#33301f; border-color:#5a5232; color:#d8c07a; }

/* The research on a mandate's row: stage, conviction, fair value, the dossier. */
.pf_mand_name { font-size:11.5px; color:#8a94a6; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.pf_mand_sym .pf_sym { font-weight:700; }
.pf_mand_research {
	display:flex; align-items:center; flex-wrap:wrap; gap:6px 16px;
	margin-top:10px; padding-top:9px; border-top:1px solid #eef0f3;
	font-size:11.5px; color:#5b6472;
}
.pf_mand_research b { color:#1f2937; font-weight:600; }
.pf_mand_research .gridurl { margin-left:auto; }
body.appbuilder-dark .pf_mand_name { color:#8b93a3; }
body.appbuilder-dark .pf_mand_research { border-top-color:#33363d; color:#9aa0ac; }
body.appbuilder-dark .pf_mand_research b { color:#e4e7ee; }

/* =========================================================================
   THE HELD BOOK — Overview, Positions, and the long Performance / Risk pieces.
   Everything here reuses the portfolio shell (pf_fillcol / pf_card / pf_bl /
   pf_conc) and the Orders period strip; these are only the gaps.
   ========================================================================= */
/* Sections never touch: a card that is followed by another section keeps the
   shell's 12px under it. (.pf_perf spaces its cards with `gap` instead.) */
.pf_fillcol:not(.pf_perf) > .pf_card:not(.is-fill):not(:last-child) { margin-bottom:12px; }

/* A card header that carries a note and the period chips on its right. */
.pf_card_h.pf_ov_charth { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.pf_ov_period { font-size:11.5px; font-weight:400; color:#737485; letter-spacing:0; text-transform:none; }
.pf_period_bar.ac_orders_bar { margin:0 0 0 auto; font-weight:400; letter-spacing:0; text-transform:none; }
.pf_ddchart { width:100%; height:170px; }
.pf_bar > i.is-cash { background:#c2c7ce; }
body.appbuilder-dark .pf_ov_period { color:#9aa0ac; }
body.appbuilder-dark .pf_bar > i.is-cash { background:#4a4f57; }
/* A link in the narrow name column must not be clipped to nothing. */
.pf_conc_n .pf_sym { display:inline-block; max-width:100%; overflow:hidden; text-overflow:ellipsis; vertical-align:bottom; }

/* Positions: the card is a tab strip over ONE table that fills and scrolls. */
.pf_card.pf_book { padding-top:4px; }
.pf_book > .pf_tabbar { flex:0 0 auto; margin:0 -14px 10px; }
.pf_book > .ac_empty { flex:1 1 auto; }
.pf_pos_name { max-width:220px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#737485; }
.pf_pos_acts { white-space:nowrap; }
.pf_pos_mand { display:flex; align-items:center; gap:6px; min-width:96px; }
.pf_pos_mand .pf_mand_bar { flex:1 1 auto; margin-top:0; }
.pf_pos_mand > span { font-size:11px; color:#737485; flex:0 0 auto; }
body.appbuilder-dark .pf_pos_name, body.appbuilder-dark .pf_pos_mand > span { color:#9aa0ac; }

/* Monthly returns: years down, months across, tinted by size. */
.pf_month_wrap { overflow-x:auto; }
.pf_month { width:100%; border-collapse:separate; border-spacing:3px; font-family:OpenSans; font-size:11px; }
.pf_month th { font-weight:600; color:#8a94a6; text-align:center; padding:2px 4px; font-size:10px; text-transform:uppercase; letter-spacing:.3px; }
.pf_month tbody th { text-align:left; color:#41506b; font-size:11px; }
.pf_month_c { text-align:center; padding:6px 4px; border-radius:4px; color:#27251E; min-width:44px; background:#f4f5f7; }
.pf_month_c.pf_month_y { font-weight:700; }
body.appbuilder-dark .pf_month th { color:#8b93a3; }
body.appbuilder-dark .pf_month tbody th { color:#c5cbd6; }
body.appbuilder-dark .pf_month_c { color:#e4e7ee; background:#2c2f35; }

/* The long Risk panel ends on the kill switch, under the filling feed. */
.pf_fillcol > .pf_card.is-fill + .pf_kill { margin-top:12px; margin-bottom:0; }

/* ================================================================
   MEDIA PLAYER — a recording read as well as heard.

   Transcript left, controls right. The proportions are the point: the
   text is the wide half because it is the half you read, and the rail
   is fixed at 300px because everything in it is a control and controls
   do not benefit from being wider.

   THE WHOLE THING SCROLLS IN ONE PLACE — inside .dz_script. The shell
   gets `.has-player`, which stops the modal's own scroll, so the
   player stays put while the transcript moves under it. Without that
   the pause button scrolls off the screen during playback, which is
   the one thing a player must never do.

   Mounted by Builder_MediaPlayer for any media file in any dataroom.
   ================================================================ */

.th_docmodal.has-player { overflow:hidden; padding:0; gap:0; }

.dz_host { flex:1 1 auto; min-height:0; display:flex; }
.dz_wrap {
	flex:1 1 auto; min-height:0; width:100%; display:flex;
	font-family:OpenSans, sans-serif; background:#fff;
}

/* ---- left: the transcript ---- */

.dz_script {
	flex:1 1 auto; min-width:0; overflow-y:auto; overflow-x:hidden;
	padding:16px 20px 40px 20px; box-sizing:border-box;
}
.dz_plain {
	white-space:pre-wrap; font-size:13px; line-height:1.7; color:#2b3038;
}
.dz_none { font-size:12px; color:#9aa0a8; padding:20px 2px; }

.dz_sec {
	font-size:11px; font-weight:700; letter-spacing:.7px; text-transform:uppercase;
	color:#7a828c; margin:18px 0 8px 0; padding-bottom:5px;
	border-bottom:1px solid #e3e7ed;
}
.dz_sec:first-child { margin-top:0; }

.dz_seg {
	padding:9px 11px; margin-bottom:3px; border-radius:4px; cursor:pointer;
	border-left:3px solid transparent; transition:background .12s ease;
}
.dz_seg:hover { background:#f3f6fa; }
/* The live turn. A left bar as well as a wash, so it is findable at a
   glance when the transcript is scrolling under you. */
.dz_seg.is-on { background:#eef4ff; border-left-color:#3b6fd4; }

.dz_seg_h { display:flex; align-items:center; gap:7px; flex-wrap:wrap; margin-bottom:4px; }
.dz_seg_n { font-size:12px; font-weight:600; color:#2b3038; }
.dz_seg_t { font-size:11px; color:#7a828c; }
.dz_seg_ts {
	margin-left:auto; font-size:11px; color:#9aa0a8;
	font-variant-numeric:tabular-nums;
}
.dz_seg_b { font-size:13px; line-height:1.7; color:#2b3038; }

.dz_play {
	flex:0 0 auto; width:20px; height:20px; padding:0; border-radius:50%;
	border:1px solid #cfd6df; background:#fff; color:#5b6470; cursor:pointer;
	font-size:9px; line-height:1; display:inline-flex;
	align-items:center; justify-content:center;
}
.dz_play:hover { background:#3b6fd4; border-color:#3b6fd4; color:#fff; }
/* Optical centring — a play triangle's mass sits left of its box. A pause
   bar is symmetrical and wants none of it. */
.dz_play i { margin-left:1px; }
.dz_play.is-playing i { margin-left:0; }

/* The live transport. Filled, so the one button that will stop the audio is
   findable without reading the icons — which at 20px is asking a lot. */
.dz_play.is-playing {
	background:#3b6fd4; border-color:#3b6fd4; color:#fff;
}
.dz_play.is-playing:hover { background:#2d5cb8; border-color:#2d5cb8; }

/* The spoken word. Deliberately a wash and not a colour change: the
   text must stay as readable mid-highlight as it is either side of it. */
.dz_w { border-radius:2px; }
.dz_w.is-on { background:#ffe08a; box-shadow:0 0 0 1px #ffe08a; }

/* ---- right: the controls ---- */

.dz_side {
	flex:0 0 300px; box-sizing:border-box; overflow-y:auto;
	border-left:1px solid #dfe4ea; background:#f5f7fa;
	padding:14px; display:flex; flex-direction:column; gap:14px;
}

.dz_now {
	background:#fff; border:1px solid #e3e7ed; border-radius:4px; padding:9px 11px;
}
.dz_now_w {
	font-size:10px; font-weight:700; letter-spacing:.6px; text-transform:uppercase;
	color:#9aa0a8; margin-bottom:3px;
}
.dz_now_n { font-size:12px; font-weight:600; color:#2b3038; line-height:1.45; }

.dz_audio { width:100%; display:block; }

.dz_rate { display:flex; gap:4px; }
.dz_rbtn {
	flex:1 1 0; padding:4px 0; font-size:11px; font-family:OpenSans, sans-serif;
	border:1px solid #cfd6df; background:#fff; color:#5b6470;
	border-radius:3px; cursor:pointer;
}
.dz_rbtn:hover { border-color:#3b6fd4; color:#3b6fd4; }
.dz_rbtn.is-on { background:#3b6fd4; border-color:#3b6fd4; color:#fff; font-weight:600; }

.dz_spk { display:flex; flex-direction:column; gap:5px; }
.dz_spk_h {
	font-size:10px; font-weight:700; letter-spacing:.6px; text-transform:uppercase;
	color:#9aa0a8;
}
.dz_spkb {
	display:grid; grid-template-columns:auto 1fr auto; gap:3px 7px; align-items:center;
	width:100%; text-align:left; padding:7px 9px; cursor:pointer;
	font-family:OpenSans, sans-serif;
	border:1px solid #e3e7ed; border-radius:4px; background:#fff;
}
.dz_spkb:hover { border-color:#3b6fd4; background:#f4f8ff; }
/* EVERY CELL PLACED EXPLICITLY. Mixing positioned and auto-placed items
   in one grid lets the auto ones land wherever the cursor happens to be,
   which here means a speaker whose title is missing shuffles the chip
   into the name's cell. */
.dz_spkb > i          { grid-column:1; grid-row:1 / span 2; font-size:9px; color:#5b6470; }
.dz_spkb:hover > i    { color:#3b6fd4; }
.dz_spkb_n            { grid-column:2; grid-row:1; font-size:12px; font-weight:600; color:#2b3038; }
.dz_spkb_t {
	grid-column:2; grid-row:2; font-size:10px; color:#7a828c;
	overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.dz_spkb_c            { grid-column:3; grid-row:2; font-size:10px; color:#9aa0a8; }
.dz_spkb .rs_chip     { grid-column:3; grid-row:1; }

.dz_note {
	font-size:11px; line-height:1.5; color:#8a6d1f;
	background:#fdf6e3; border:1px solid #efe0b4; border-radius:4px; padding:8px 10px;
}

/* ---- dark ---- */

body.appbuilder-dark .dz_wrap    { background:#22262b; }
body.appbuilder-dark .dz_plain,
body.appbuilder-dark .dz_seg_b,
body.appbuilder-dark .dz_seg_n,
body.appbuilder-dark .dz_now_n,
body.appbuilder-dark .dz_spkb_n  { color:#d6dae0; }
body.appbuilder-dark .dz_sec     { color:#8b939d; border-bottom-color:#333a41; }
body.appbuilder-dark .dz_seg:hover { background:#282d33; }
body.appbuilder-dark .dz_seg.is-on { background:#26313f; border-left-color:#5b8ae0; }
body.appbuilder-dark .dz_seg_t,
body.appbuilder-dark .dz_spkb_t  { color:#8b939d; }
body.appbuilder-dark .dz_seg_ts,
body.appbuilder-dark .dz_now_w,
body.appbuilder-dark .dz_spk_h,
body.appbuilder-dark .dz_spkb_c,
body.appbuilder-dark .dz_none    { color:#767e88; }

body.appbuilder-dark .dz_play {
	background:#2b3037; border-color:#3d444c; color:#a8b0b9;
}
body.appbuilder-dark .dz_play:hover { background:#5b8ae0; border-color:#5b8ae0; color:#fff; }
body.appbuilder-dark .dz_play.is-playing {
	background:#5b8ae0; border-color:#5b8ae0; color:#fff;
}
body.appbuilder-dark .dz_play.is-playing:hover { background:#7ba2e8; border-color:#7ba2e8; }

/* Dimmer than the light wash and dark text on it — a saturated yellow
   at this size on a dark ground vibrates. */
body.appbuilder-dark .dz_w.is-on {
	background:#7a6420; color:#fff6dd; box-shadow:0 0 0 1px #7a6420;
}

body.appbuilder-dark .dz_side { background:#1e2226; border-left-color:#333a41; }
body.appbuilder-dark .dz_now,
body.appbuilder-dark .dz_spkb { background:#272c32; border-color:#363d45; }
body.appbuilder-dark .dz_spkb:hover { background:#2c3541; border-color:#5b8ae0; }
body.appbuilder-dark .dz_spkb > i { color:#a8b0b9; }
body.appbuilder-dark .dz_spkb:hover > i { color:#5b8ae0; }
body.appbuilder-dark .dz_rbtn {
	background:#272c32; border-color:#3d444c; color:#a8b0b9;
}
body.appbuilder-dark .dz_rbtn:hover { border-color:#5b8ae0; color:#5b8ae0; }
body.appbuilder-dark .dz_rbtn.is-on { background:#5b8ae0; border-color:#5b8ae0; color:#fff; }
body.appbuilder-dark .dz_note { color:#e8c98a; background:#3a3222; border-color:#574a2e; }

/* The native transport is a light-mode widget everywhere; asking the UA
   for the dark one is the only way to keep it from glowing white. */
body.appbuilder-dark .dz_audio { color-scheme:dark; }

/* ======================================================================
 * CLOSING THINGS — exactly TWO patterns, app-wide
 *
 * The affordances had drifted apart: the popup used a solid red flash, the
 * replay bar a pink-bordered button, the chart header a bare colour change
 * with no dark-mode rule at all, and the dashboard widget and task chip two
 * slightly different tints. Five looks for one verb.
 *
 * LOUD — solid red, white cross, on HOVER only.
 *   `.w2ui-popup-close` (see the popup rules above). Reserved for dismissing
 *   a DIALOG: it is a modal escape, there is one per window, and it is the
 *   only close that can discard unsaved work.
 *
 * QUIET — `.cv_close_x` below. Everything that closes something INSIDE the
 *   page: a chart cell, a replay session, a dashboard widget, a status chip.
 *   Muted at rest, a soft red tint on hover. These sit next to content and
 *   often several at once, so a red flash per row would be noise. Modelled on
 *   the dashboard widget's delete handle, which in turn matches w2ui's own
 *   closeable-tab ✕ — deliberately left alone as the reference.
 *
 * Adding a third pattern is the thing this block exists to prevent. A new
 * close either dismisses a dialog (loud) or it does not (quiet).
 * ====================================================================== */
.cv_close_x,
.charts_cell_x,
.builder-dashboard-delete-handle,
.task-chip-close,
.screener_detail_close,
.custompanel_subpanel_bar_close,
.builder-chatbot-moreinfo div[close] {
	border-radius: 3px;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease;
}
/* Bare glyphs need a box before a tint has anything to fill. The padded
   ones already carry their own. */
.cv_close_x,
.charts_cell_x { padding: 2px 4px; }

.cv_close_x:hover,
.charts_cell_x:hover,
.charts_replay_btn.is-close:hover,
.builder-dashboard-delete-handle:hover,
.task-chip-close:hover,
.screener_detail_close:hover,
.custompanel_subpanel_bar_close:hover,
.builder-chatbot-moreinfo div[close]:hover {
	background: #fdecec;
	color: #d62728;
	font-weight: inherit;
}
.cv_close_x:active,
.charts_cell_x:active,
.charts_replay_btn.is-close:active,
.builder-dashboard-delete-handle:active,
.task-chip-close:active,
.screener_detail_close:active,
.custompanel_subpanel_bar_close:active,
.builder-chatbot-moreinfo div[close]:active { background: #f9d8d8; }

body.appbuilder-dark .cv_close_x:hover,
body.appbuilder-dark .charts_cell_x:hover,
body.appbuilder-dark .charts_replay_btn.is-close:hover,
body.appbuilder-dark .builder-dashboard-delete-handle:hover,
body.appbuilder-dark .task-chip-close:hover,
body.appbuilder-dark .screener_detail_close:hover,
body.appbuilder-dark .custompanel_subpanel_bar_close:hover,
body.appbuilder-dark .builder-chatbot-moreinfo div[close]:hover {
	background: rgba(214, 39, 40, 0.18) !important;
	color: #ff6b6b !important;
}
body.appbuilder-dark .cv_close_x:active,
body.appbuilder-dark .charts_cell_x:active,
body.appbuilder-dark .charts_replay_btn.is-close:active,
body.appbuilder-dark .builder-dashboard-delete-handle:active,
body.appbuilder-dark .task-chip-close:active,
body.appbuilder-dark .screener_detail_close:active,
body.appbuilder-dark .custompanel_subpanel_bar_close:active,
body.appbuilder-dark .builder-chatbot-moreinfo div[close]:active {
	background: rgba(214, 39, 40, 0.30) !important;
}

/* ---- Charts chat: the context strip ---------------------------------
   One line above the transcript saying what the assistant can see. It exists
   because the envelope is otherwise invisible: an answer about the symbol you
   just switched away from reads exactly like an answer that is simply wrong,
   and there was no way to tell them apart. */
.charts_chat_ctx {
	flex:0 0 auto; display:flex; align-items:center; gap:6px;
	padding:5px 8px; border-bottom:1px solid #eceff3; background:#f7f9fb;
	font-family:OpenSans; font-size:10.5px; color:#6b727a;
	white-space:nowrap; overflow:hidden;
}
.charts_chat_ctx > .fa { font-size:10px; color:#9aa0a8; flex:0 0 auto; }
.charts_chat_ctx_main { font-weight:600; color:#3c434a; cursor:help; }
.charts_chat_ctx_more { overflow:hidden; text-overflow:ellipsis; }
.charts_chat_ctx_none { font-style:italic; }
.charts_chat_ctx_warn {
	flex:0 0 auto; margin-left:auto; padding:0 5px; border-radius:8px;
	background:#fdf3e6; border:1px solid #e8d3ae; color:#8a6216;
	font-size:9px; font-weight:600; text-transform:uppercase;
}
body.appbuilder-dark .charts_chat_ctx {
	background:#1c2025; border-bottom-color:#2a2e34; color:#8a929b;
}
body.appbuilder-dark .charts_chat_ctx > .fa { color:#6b727b; }
body.appbuilder-dark .charts_chat_ctx_main { color:#c8cfd6; }
body.appbuilder-dark .charts_chat_ctx_warn {
	background:#33291a; border-color:#584a2e; color:#e0b877;
}


/* The docked chat's streaming bubble — plain text while tokens arrive
   (markdown renders once, at finalize). Inherits the answer bubble look. */
.charts_stream_partial { white-space:pre-wrap; }

/* Pine table.* — corner-anchored readout rendered as a DOM overlay on the
   chart cell (position set inline per spec.position). Colors from the
   script win via inline styles; these are the fallbacks. */
.charts_pine_table {
	position:absolute; z-index:6; pointer-events:none;
	border-collapse:separate; border-spacing:0;
	background:rgba(255,255,255,0.92); border:1px solid #d6dade;
	border-radius:4px; overflow:hidden;
	font-family:OpenSans; font-size:10.5px; color:#3c434a;
	box-shadow:0 1px 4px rgba(0,0,0,0.08);
}
.charts_pine_table td {
	padding:2px 7px; border-bottom:1px solid rgba(0,0,0,0.05);
	white-space:nowrap; font-variant-numeric:tabular-nums;
}
.charts_pine_table tr:last-child td { border-bottom:none; }
body.appbuilder-dark .charts_pine_table {
	background:rgba(28,32,37,0.92); border-color:#3a4048; color:#c8cfd6;
	box-shadow:0 1px 4px rgba(0,0,0,0.35);
}
body.appbuilder-dark .charts_pine_table td { border-bottom-color:rgba(255,255,255,0.06); }

/* ---- Charts: ticker typeahead ---------------------------------------
   An inline input inside the instrument box: type, pick, charted. The
   dropdown is absolutely positioned under the box; rows show logo,
   symbol, name. */
/* The input is part of the box, not a field of its own: borderless,
   transparent, flexing to fill whatever the chips leave — so the caret
   lands right after the last chip and the box reads as ONE control.
   Focus shows as a caret, never a ring (the box's border is the field).
   Doubly-qualified selector + appearance reset: a global input rule was
   painting a bordered rectangle inside the box on the first live test. */
.charts_tags.charts_tags_inline { flex:0 1 auto; }
.charts_tags.charts_tags_inline:empty { padding:0; }
.charts_field_box input.charts_symbol_input,
.charts_field_box input.charts_symbol_input:focus,
.charts_field_box input.charts_symbol_input:focus-visible {
	-webkit-appearance:none; appearance:none;
	border:none !important; outline:none !important; box-shadow:none !important;
	background:transparent !important; border-radius:0 !important;
	font-family:OpenSans; font-size:12px; color:#3c434a;
	flex:1 1 60px; min-width:52px; padding:2px 4px; height:100%;
}
.charts_symbol_input::placeholder { color:#a8aeb6; }
/* Hosted on document.body and positioned FIXED by JS — inside the
   instrument box it was clipped by the box's overflow:hidden. */
.charts_symbol_drop {
	z-index:10040;
	min-width:260px; max-height:320px; overflow-y:auto;
	background:#fff; border:1px solid #d5d9df; border-radius:6px;
	box-shadow:0 8px 24px rgba(20,24,30,.16); padding:4px;
}
/* Rows mirror the Recently Viewed popup — same 32px logo/monogram (the
   shared Builder_PackageRowLogo helper renders them), symbol bold with
   the company underneath. One look for "a row naming an instrument". */
.charts_symrow {
	display:flex; align-items:center; gap:10px; padding:7px 10px;
	border-radius:4px; cursor:pointer; font-family:OpenSans; font-size:12px;
	color:#3c434a; white-space:nowrap;
}
.charts_symrow.is-active, .charts_symrow:hover { background:#eef3fa; }
.charts_symrow img,
.charts_symbol_drop .pkgrow_logo,
.charts_symbol_drop .pkgrow_mono {
	width:32px; height:32px; border-radius:50%; flex:0 0 auto;
	object-fit:contain; background:#fff;
}
/* Monograms carry their own disc colour — don't wash it out with white. */
.charts_symbol_drop .pkgrow_mono { background:transparent; }
.charts_symrow_txt { display:flex; flex-direction:column; min-width:0; line-height:1.3; }
.charts_symrow_txt b { font-size:12.5px; }
.charts_symrow_txt span { color:#8a929b; font-size:11.5px; overflow:hidden; text-overflow:ellipsis; }
body.appbuilder-dark .charts_field_box input.charts_symbol_input { color:#c8cfd6; }
body.appbuilder-dark .charts_symbol_input::placeholder { color:#5b616b; }
body.appbuilder-dark .charts_symbol_drop {
	background:#22262e; border-color:#343a44; box-shadow:0 8px 24px rgba(0,0,0,.5);
}
body.appbuilder-dark .charts_symrow { color:#c8cfd6; }
body.appbuilder-dark .charts_symrow.is-active, body.appbuilder-dark .charts_symrow:hover { background:#2a3140; }

/* ---- Metric help (the explain() primitive) --------------------------
   A definition card opened by clicking any data-metric term. The
   deterministic definition leads; the optional AI reading appends under
   an explicit label. One card at a time, fixed-positioned by JS. */
.mh_term { cursor: help; }
.mh_term .mh_q { font-size: 9px; margin-left: 4px; opacity: .45; }
.mh_term:hover .mh_q { opacity: .9; }
.mh_card {
	position: fixed; z-index: 10050;
	background: #fff; border: 1px solid #d5d9df; border-radius: 8px;
	box-shadow: 0 8px 28px rgba(20,24,30,.18);
	padding: 14px 16px; font-family: OpenSans; font-size: 12.5px;
	line-height: 1.5; color: #3c434a;
}
.mh_name { font-size: 13.5px; font-weight: 700; color: #1f242a; margin-bottom: 6px; }
.mh_name .mh_close { float: right; cursor: pointer; opacity: .5; padding: 2px; }
.mh_name .mh_close:hover { opacity: 1; }
.mh_what { margin-bottom: 8px; }
.mh_sec {
	font-size: 10px; font-weight: 700; letter-spacing: .08em;
	text-transform: uppercase; color: #8a929b; margin: 8px 0 2px;
}
.mh_caveat { color: #8a6216; }
.mh_actions { margin-top: 10px; }
.mh_actions .w2ui-btn { font-size: 11.5px; }
.mh_reading { margin-top: 10px; border-top: 1px dashed #d5d9df; padding-top: 8px; }
.mh_reading .mh_ai {
	display: inline-block; font-size: 9.5px; font-weight: 700;
	letter-spacing: .06em; text-transform: uppercase;
	background: #e4ebfa; color: #2d5fc4; border-radius: 3px;
	padding: 1px 6px; margin-right: 6px; vertical-align: 1px;
}
body.appbuilder-dark .mh_card {
	background: #22262e; border-color: #343a44; color: #c8cfd6;
	box-shadow: 0 8px 28px rgba(0,0,0,.5);
}
body.appbuilder-dark .mh_name { color: #e8e7e2; }
body.appbuilder-dark .mh_sec { color: #7c818a; }
body.appbuilder-dark .mh_caveat { color: #d9a54a; }
body.appbuilder-dark .mh_reading { border-top-color: #343a44; }
body.appbuilder-dark .mh_reading .mh_ai { background: #1e2a45; color: #7aa1ee; }

/* ---- Charts chat: the session boundary ------------------------------
   One quiet row above the transcript. "New conversation" archives the
   transcript server-side and starts clean — the session boundary this
   chat never had. Deliberately understated: it is furniture, not a
   feature. */
.charts_chat_newconv {
	flex:0 0 auto; display:flex; justify-content:flex-end; gap:6px;
	padding:4px 8px; border-bottom:1px solid #eceff3; background:#fcfdfe;
}
.charts_chat_newconv .pf_btn { font-size:10.5px; padding:2px 8px; }
body.appbuilder-dark .charts_chat_newconv {
	background:#191d22; border-bottom-color:#2a2e34;
}

/* ---- Charts chat: the range card ------------------------------------
   A clarification card wearing a range's clothes. It inherits the framework's
   card box, its option chips, its free-text row and — the part that matters —
   its staling: when the next message lands the card fades and locks, becoming
   the read-only record of what the answer was about. Only the range-specific
   summary is styled here. */
.charts_rangecard { border-left:3px solid #8b5cf6; }
.charts_rc_head { display:flex; align-items:baseline; gap:6px; margin-bottom:1px; }
.charts_rc_ico  { color:#8b5cf6; font-size:11px; align-self:center; }
.charts_rc_title { font-weight:700; font-size:12.5px; color:#2f3439; }
.charts_rc_tf   { font-size:11px; color:#78808a; }
.charts_rc_bars {
	margin-left:auto; padding:0 6px; border-radius:8px;
	background:#ece5fd; color:#5b3fa8; font-size:9px; font-weight:600;
	text-transform:uppercase; align-self:center;
}
.charts_rc_when { font-size:10px; color:#78808a; margin-bottom:6px; }
/* Two columns of label/value, labels aligned so the numbers form a column of
   their own — the first version let each row size itself and the figures
   staggered across the card. */
.charts_rc_grid { display:grid; grid-template-columns:1fr 1fr; gap:1px 14px; }
.charts_rc_row  { display:flex; align-items:baseline; gap:6px; min-width:0; font-size:11px; }
.charts_rc_k    { flex:0 0 54px; color:#78808a; }
.charts_rc_v    { font-weight:600; color:#2f3439; white-space:nowrap; }
.charts_rc_v .is-up { color:#1f7a43; }
.charts_rc_v .is-dn { color:#c0392b; }
.charts_rc_at   { font-size:9px; color:#9aa0a8; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.charts_rc_list { margin-top:5px; font-size:10px; line-height:1.35; }
.charts_rc_list > span { color:#78808a; }
.charts_rc_list > div  { color:#3c434a; }
.charts_rc_note { margin-top:5px; font-size:9.5px; font-style:italic; color:#8a6216; }
.charts_rc_asks { margin-top:8px; }

body.appbuilder-dark .charts_rc_title { color:#e6e9ee; }
body.appbuilder-dark .charts_rc_tf,
body.appbuilder-dark .charts_rc_when,
body.appbuilder-dark .charts_rc_k,
body.appbuilder-dark .charts_rc_list > span { color:#8a929b; }
body.appbuilder-dark .charts_rc_bars { background:#332a4d; color:#c7b6f5; }
body.appbuilder-dark .charts_rc_v { color:#e6e9ee; }
body.appbuilder-dark .charts_rc_v .is-up { color:#7fc79b; }
body.appbuilder-dark .charts_rc_v .is-dn { color:#ef9a9a; }
body.appbuilder-dark .charts_rc_at { color:#6b727b; }
body.appbuilder-dark .charts_rc_list > div { color:#c8cfd6; }
body.appbuilder-dark .charts_rc_note { color:#e0b877; }

/* An answered range card keeps its FIGURES and loses its questions: the
   question is now in the transcript above it, and a row of chips that no
   longer does anything is worse than no chips. The framework's stale class
   already fades and locks the card; this removes what has become noise. */
.chat_clarify_card_stale .charts_rc_asks,
.chat_clarify_card_stale .chat_clarify_other { display:none; }
/* ...and the card stops looking disabled, because it is not: it is a record,
   and its one live control is "show me that range again". */
.charts_rangecard.chat_clarify_card_stale { opacity:1; pointer-events:auto; }
.charts_rc_show {
	flex:0 0 auto; margin-left:6px; padding:2px 4px; border-radius:3px;
	font-size:11px; color:#9aa0a8; cursor:pointer; align-self:center;
}
.charts_rc_show:hover { background:#ece5fd; color:#5b3fa8; }

/* The verdict's conclusion, kept beside the reasoning it belongs to. */
.charts_stance {
	display:inline-block; margin:0 0 6px; padding:1px 9px; border-radius:10px;
	font-family:OpenSans; font-size:10px; font-weight:700; text-transform:uppercase;
	letter-spacing:0.03em;
}
.charts_stance.is-buy     { background:#e8f6ed; border:1px solid #b9e0c8; color:#1f7a43; }
.charts_stance.is-sell    { background:#fdecec; border:1px solid #f3c3c3; color:#c0392b; }
.charts_stance.is-neutral { background:#eef1f5; border:1px solid #d3d9e0; color:#5a636c; }

body.appbuilder-dark .charts_rc_show:hover { background:#332a4d; color:#c7b6f5; }
body.appbuilder-dark .charts_stance.is-buy {
	background:#16301f; border-color:#2c5a3c; color:#7fc79b;
}
body.appbuilder-dark .charts_stance.is-sell {
	background:#331b1b; border-color:#5a2c2c; color:#ef9a9a;
}
body.appbuilder-dark .charts_stance.is-neutral {
	background:#23272d; border-color:#3a4048; color:#a8b0b9;
}

/* ---- Charts chat: an offer that outlives the conversation -----------
   The other half of the destructiveness split. A view change is already done
   by the time you read about it; an alert waits for a press, because it fires
   into a chat window tomorrow when nobody is watching. */
.charts_propcard { border-left:3px solid #2F9EEE; }
.charts_prop_head {
	display:flex; align-items:center; gap:6px; margin-bottom:6px;
	font-size:12px; font-weight:600; color:#2f3439;
}
.charts_prop_head > .fa { color:#2F9EEE; }
.charts_prop_row {
	display:flex; align-items:center; gap:8px; padding:3px 0;
	font-size:11px; color:#3c434a;
}
.charts_prop_what { flex:1 1 auto; min-width:0; }
.charts_prop_note { display:block; font-size:10px; color:#78808a; }
.charts_prop_go { flex:0 0 auto; font-size:11px; }
.charts_prop_foot { margin-top:5px; font-size:9.5px; font-style:italic; color:#78808a; }
/* Armed. The card stays as the record — a button that vanishes leaves the
   reader wondering whether the press worked. */
.charts_prop_done .charts_prop_go { display:none; }
/* The footer swaps with the state: an armed card must not still be telling
   the reader that nothing is watching until they press a button that is no
   longer there. */
.charts_prop_foot_done { display:none; }
.charts_prop_done .charts_prop_foot { display:none; }
.charts_prop_done .charts_prop_foot_done { display:block; color:#1f7a43; font-style:normal; }
body.appbuilder-dark .charts_prop_done .charts_prop_foot_done { color:#7fc79b; }
.charts_prop_done .charts_prop_row::after {
	content:"\f00c"; font-family:FontAwesome; color:#1f7a43; font-size:11px;
}
body.appbuilder-dark .charts_prop_head { color:#e6e9ee; }
body.appbuilder-dark .charts_prop_row  { color:#c8cfd6; }
body.appbuilder-dark .charts_prop_note,
body.appbuilder-dark .charts_prop_foot { color:#8a929b; }
body.appbuilder-dark .charts_prop_done .charts_prop_row::after { color:#7fc79b; }

/* ---- Scripts front door (P4-1) ------------------------------------- */
/* The empty list sells the one action that matters; the toolbar button
   repeats it once scripts exist. Sized against .anylist_empty's 24px. */
.ts_firstrun { max-width: 560px; }
.ts_firstrun > .fa { font-size: 40px; color: #b39ddb; display: block; margin-bottom: 12px; }
.ts_firstrun_t { font-size: 24px; margin-bottom: 10px; }
.ts_firstrun_s { font-size: 14px; color: #737485; margin-bottom: 18px; line-height: 1.5; }
.ts_firstrun .w2ui-btn { font-size: 14px; padding: 8px 18px; }
.ts_describe_btn { margin-right: 8px; white-space: nowrap; }
.ts_describe_btn .fa { color: #7e57c2; }

body.appbuilder-dark .ts_firstrun_t { color: #e6e9ee; }
body.appbuilder-dark .ts_firstrun_s { color: #9aa0ac; }
body.appbuilder-dark .ts_firstrun > .fa { color: #9575cd; }

/* ---- Test-tab parity line (P4-2) ------------------------------------ */
.ts_parity {
	font-size: 12px;
	color: #737485;
	padding: 6px 10px;
	margin: 0 0 10px 0;
	border: 1px solid #e4e2de;
	border-radius: 6px;
	background: #faf9f7;
}
.ts_parity .fa { color: #7e57c2; margin-right: 4px; }
body.appbuilder-dark .ts_parity {
	color: #9aa0ac;
	border-color: #3a3a44;
	background: #26262d;
}

/* ---- backtest trade log (P4-3) --------------------------------------- */
.bt_trades_wrap { overflow-x: auto; }
.bt_trades_t td, .bt_trades_t th { white-space: nowrap; }
.bt_trades_pager {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 8px;
	font-size: 12px;
	color: #737485;
}
body.appbuilder-dark .bt_trades_pager { color: #9aa0ac; }

/* ================================================================
   COVERAGE: what a dossier is still missing, and who filled the rest.

   Four groups in a grid rather than one column of fourteen: the answer
   a reader wants is not "how many" but WHICH, and a list that long
   reads as a wall while four short lists read as four questions.
   ================================================================ */
.co_cvpanel      { margin-top:12px; }
.co_cvscore      { font-size:12px; font-weight:600; color:#41506b;
                   font-variant-numeric:tabular-nums; margin-left:8px; }
.co_cvaichip     { margin-left:6px; }

/* The bar is a summary, not the content — thin, and directly under the
   heading so it is read as belonging to the count beside it. */
.co_cvbar        { height:5px; border-radius:3px; background:#eceff4; overflow:hidden; }
.co_cvbar > i    { display:block; height:100%; background:#269DF0; border-radius:3px; }
.co_cvhelp       { margin:8px 0 10px; font-size:11px; line-height:1.5; color:#6b7280; }

.co_cvgrid       { display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr));
                   gap:10px 18px; }
.co_cvgroup      { min-width:0; }
.co_cvgh         { font-size:9.5px; font-weight:600; letter-spacing:0.4px;
                   text-transform:uppercase; color:#9aa0a8;
                   padding-bottom:4px; margin-bottom:4px;
                   border-bottom:1px solid #eceff4; }

.co_cvrow        { display:flex; align-items:center; gap:7px; min-height:24px;
                   font-size:11.5px; color:#41506b; }
/* A GAP IS DIMMED, NOT RED. Missing is the normal state of a dossier
   nobody has finished, and colouring it as a fault would paint a new
   name in alarms for doing nothing wrong. */
.co_cvrow.is-gap { color:#9aa0a8; }
.co_cvok         { color:#0f9d76; font-size:11px; }
.co_cvno         { color:#c8ccd4; font-size:11px; }
.co_cvlbl        { flex:1 1 auto; min-width:0; overflow:hidden;
                   text-overflow:ellipsis; white-space:nowrap; }
.co_cvby         { flex:0 0 auto; font-size:9.5px; color:#9aa0a8;
                   text-transform:uppercase; letter-spacing:0.3px; }

/* The AI marker. A wand rather than a badge saying "AI": it sits inside
   a row of fourteen and a word would be wider than the label it marks. */
.co_cvai         { color:#8b5cf6; font-size:10px; }

/* Smaller than a normal pf_btn — fourteen rows tall, this column would
   otherwise set the height of the whole panel. */
.co_cvfill       { flex:0 0 auto; padding:2px 8px !important; font-size:10.5px !important; }

body.appbuilder-dark .co_cvscore      { color:#c9ccd2; }
body.appbuilder-dark .co_cvbar        { background:#3a3f47; }
body.appbuilder-dark .co_cvgh         { color:#8d949c; border-bottom-color:var(--border); }
body.appbuilder-dark .co_cvrow        { color:#c9ccd2; }
body.appbuilder-dark .co_cvrow.is-gap { color:#8d949c; }
body.appbuilder-dark .co_cvno         { color:#4a4f57; }
body.appbuilder-dark .co_cvai         { color:#a78bfa; }
body.appbuilder-dark .co_cvhelp       { color:#8d949c; }

/* ---- the fill dialog ---- */

.co_fillbody     { padding:14px 16px; }
/* Centred, because the dialog has nothing else in it while it waits —
   a spinner in the top-left corner of an empty box reads as a page that
   failed to load rather than one that is working. */
.co_fillwait     { display:flex; flex-direction:column; align-items:center;
                   justify-content:center; gap:8px; min-height:260px;
                   text-align:center; font-size:13px; color:#41506b; }
.co_fillwait .fa { font-size:22px; color:#269DF0; }

.co_fillnote     { padding:8px 11px; margin-bottom:12px; border-radius:5px;
                   background:#f4f7fb; border-left:2px solid #269DF0;
                   font-size:11.5px; line-height:1.5; color:#41506b; }
/* A REFUSAL IS A RESULT, and it is tinted as a caution rather than an
   error: the model did not fail, the platform declined what it returned. */
.co_fillnote.is-warn { background:#fdf3e3; border-left-color:#e8a600; color:#9a6a10; }

.co_filltbl      { margin-bottom:12px; }
.co_fill_ck      { width:26px; }
.co_fillwhy      { font-size:10.5px; color:#6b7280; line-height:1.5;
                   overflow-wrap:anywhere; }

/* One value, when there is only one to show. */
.co_fillone      { text-align:center; padding:18px 0 10px; }
.co_fillone_v    { font-size:26px; font-weight:600; color:#27251E; line-height:1.15;
                   font-variant-numeric:tabular-nums; }
.co_fillone_k    { font-size:10px; font-weight:600; letter-spacing:0.4px;
                   text-transform:uppercase; color:#9aa0a8; margin-bottom:12px; }

/* THE SOURCES ARE PART OF THE ANSWER, so they are shown, not linked to
   from a footnote. A value whose source a reader cannot see in one
   glance is a value they have to take on trust, which is the thing
   this whole feature is built to avoid. */
.co_fillcites    { padding-top:10px; border-top:1px solid #eceff4; }
.co_fillcitesh   { font-size:9.5px; font-weight:600; letter-spacing:0.4px;
                   text-transform:uppercase; color:#9aa0a8; margin-bottom:5px; }
.co_fillcite     { display:inline-flex; align-items:center; gap:5px;
                   max-width:100%; margin:0 8px 5px 0; font-size:10.5px;
                   color:#1c53b8; text-decoration:none;
                   overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.co_fillcite:hover { text-decoration:underline; }

.co_fillacts     { display:flex; align-items:center; gap:12px;
                   padding-top:12px; margin-top:12px;
                   border-top:1px solid #eceff4; }
.co_fillacts .th_muted { font-size:10.5px; }

body.appbuilder-dark .co_fillwait     { color:#c9ccd2; }
body.appbuilder-dark .co_fillnote     { background:#22303f; color:#c9ccd2; }
body.appbuilder-dark .co_fillnote.is-warn { background:#3a2f1c; color:#e8c07a; }
body.appbuilder-dark .co_fillone_v    { color:#e6e6ea; }
body.appbuilder-dark .co_fillcites,
body.appbuilder-dark .co_fillacts     { border-top-color:var(--border); }
body.appbuilder-dark .co_fillcite     { color:#8ab4f8; }

/* ================================================================
   CLAIM QUALIFICATION (Ship 3).

   The register used to draw a checkable claim and an unfalsifiable
   one identically. These rules are the difference: a quantity line
   under the claim, a tint on the rows the record already refutes,
   and the machine's recommendation kept visibly apart from the
   status it is not.
   ================================================================ */

/* The two controls that empty the queue, in the panel head. */
.co_clacts_hd    { margin-left:auto; display:flex; align-items:center; gap:6px; }
button.w2ui-btn.co_qualbtn,
.co_qualbtn      { padding:4px 10px !important; font-size:11px !important; }

/* THE QUANTITY. Indented under the claim it was read out of, and set
   in the muted size — it is a restatement of the sentence above,
   not a second claim. */
.co_evq          { margin-top:5px; font-size:10.5px; line-height:1.5; color:#6b7280;
                   display:flex; align-items:baseline; gap:5px; flex-wrap:wrap; }
.co_evq > .fa    { color:#9aa0a8; font-size:9.5px; }
.co_evq b        { color:#41506b; font-weight:600; font-variant-numeric:tabular-nums; }
.co_evq_no       { color:#c8ccd4; font-style:italic; }

/* A number nothing here measures. Dashed, because it is a real
   quantity that is deliberately NOT armed — arming it against the
   nearest of eleven metrics would silently measure something else. */
.co_evq.is-loose { border-left:2px dashed #d8d6d2; padding-left:7px; }

/* CONTRADICTED. The strongest thing this screen says, so it is the
   only place in the register that takes the alarm colour. */
.co_evq.is-contra b { color:#b3261e; }
.co_evq_x        { color:#b3261e !important; letter-spacing:0.3px; font-size:9.5px; }
.co_evrow_x td   { background:rgba(179,38,30,.055); }
/* The no-falsifier tint and the contradicted tint would otherwise
   stack into a third colour that means neither. Contradicted wins:
   it is a fact about the world, the other is a fact about the form. */
.co_evrow.co_evrow_nf.co_evrow_x td { background:rgba(179,38,30,.055); }

.co_evq_dup      { color:#9a6a10; }
.co_evq_arm      { color:#0f9d76; font-size:9.5px; }

/* The machine's verdict, under the status chip and never replacing
   it. Two facts, kept two: what the register records, and what a
   model recommended. */
.co_evverd       { margin-top:4px; font-size:9px; letter-spacing:0.2px; }

/* The proposed falsifier, in the cell that says one is missing —
   which is the whole point: the largest dead-end bucket in the
   register becomes one click of reviewable material. */
.co_evfprop      { margin-top:6px; padding:6px 8px; border-radius:4px;
                   background:#f3f0fb; border-left:2px solid #8b5cf6;
                   font-size:10.5px; line-height:1.5; color:#4c3d7a;
                   display:flex; align-items:flex-start; gap:6px; }
.co_evfprop > .fa { color:#8b5cf6; margin-top:2px; }
.co_evfprop .pf_btn { margin-left:auto; padding:1px 7px; font-size:10px; flex:0 0 auto; }

body.appbuilder-dark .co_evq        { color:#8d949c; }
body.appbuilder-dark .co_evq b      { color:#c9ccd2; }
body.appbuilder-dark .co_evq_no     { color:#5a6068; }
body.appbuilder-dark .co_evq.is-loose { border-left-color:#4a4f57; }
body.appbuilder-dark .co_evq.is-contra b,
body.appbuilder-dark .co_evq_x      { color:#f0837a !important; }
body.appbuilder-dark .co_evrow_x td { background:rgba(240,131,122,.08); }
body.appbuilder-dark .co_evrow.co_evrow_nf.co_evrow_x td { background:rgba(240,131,122,.08); }
body.appbuilder-dark .co_evq_dup    { color:#e8c07a; }
body.appbuilder-dark .co_evq_arm    { color:#4fd1a5; }
body.appbuilder-dark .co_evfprop    { background:#2b2740; border-left-color:#a78bfa; color:#c9c2e4; }
body.appbuilder-dark .co_evfprop > .fa { color:#a78bfa; }

/* The one-pass button, in the Coverage head. Smaller than a body button:
   it shares the row with a count and a chip, and at full size it would be
   the loudest thing in a panel that is mostly a checklist. */
.co_cvall        { margin-left:auto; padding:3px 10px !important; font-size:10.5px !important; }
/* The outcome column of the fill report. */
.co_fill_st      { width:78px; }

/* ================================================================
   THE WRITTEN CASE (Ship 4).

   It sits directly under the scripted verdict and has to read as
   its PEER — same stance strip, same width, same weight — because
   the whole value of the pair is that a reader compares them. Made
   visibly softer or smaller, it would read as a footnote to the
   arithmetic instead of a second opinion about it.
   ================================================================ */
button.w2ui-btn.co_memobtn,
.co_memobtn      { margin-left:auto; padding:3px 10px !important; font-size:10.5px !important; }

/* THE DISAGREEMENT, above everything. A model arguing against the
   arithmetic is the single most valuable thing this screen shows,
   and it is only a signal because the arithmetic was computed
   independently — so it gets the width of the panel, not a chip. */
.co_memodis      { display:flex; gap:9px; align-items:flex-start;
                   padding:10px 12px; margin-bottom:12px; border-radius:5px;
                   background:#fdf3e3; border-left:3px solid #e8a600;
                   font-size:11.5px; line-height:1.55; color:#7a5410; }
.co_memodis > .fa { color:#e8a600; font-size:14px; margin-top:1px; }
.co_memodis b    { color:#5c3f0c; }

/* Agreement is stated too, quietly. Two independent routes to the
   same stance is worth knowing — and a panel that only ever spoke
   up to disagree would leave silence meaning two different things. */
.co_memoagr      { display:flex; gap:7px; align-items:center;
                   margin-bottom:12px; font-size:10.5px; color:#0f9d76; }

.co_memosec      { margin-top:14px; }
.co_memoh        { font-size:9.5px; font-weight:600; letter-spacing:0.4px;
                   text-transform:uppercase; color:#9aa0a8;
                   padding-bottom:4px; margin-bottom:6px;
                   border-bottom:1px solid #eceff4; }

.co_memothesis,
.co_memolist     { margin:0; padding-left:20px; }
.co_memothesis li,
.co_memolist li  { font-size:12px; line-height:1.6; color:#27251E; margin-bottom:5px; }
/* The kill conditions read in the bear tone, and the open questions
   in the muted one: three lists of identical bullets would make a
   reader parse the headings to know which was which. */
.co_memolist.is-bear li { color:#7a2f2a; }
.co_memolist.is-gap li  { color:#6b7280; font-size:11px; }

/* THE CITATION, as a numeral you can press. A count alone would be a
   claim about grounding; this goes to the claims themselves, which
   is the grounding. */
.co_memocite     { border:1px solid #d8d6d2; border-radius:9px; background:#fff;
                   color:#6b7280; font:9.5px OpenSans, sans-serif;
                   padding:0 5px; margin-left:4px; cursor:pointer;
                   font-variant-numeric:tabular-nums; vertical-align:1px; }
.co_memocite:hover { border-color:#269DF0; color:#1c53b8; }

.co_memoaxes     { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr));
                   gap:6px 16px; }
.co_memoax       { display:flex; align-items:baseline; gap:8px; min-width:0;
                   font-size:11px; line-height:1.5; }
.co_memoax_k     { flex:0 0 96px; color:#6b7280; }
.co_memoax_v     { flex:0 0 30px; text-align:right; font-weight:600; color:#27251E;
                   font-variant-numeric:tabular-nums; }
.co_memoax_w     { flex:1 1 auto; min-width:0; color:#9aa0a8; font-size:10.5px;
                   overflow-wrap:anywhere; }

/* Said every time the axes are shown, never once in a tooltip: they
   feed the blend the verdict weights, and a reader has to be able to
   tell whether the number in the header came from here. */
.co_memonote     { margin-top:9px; padding:7px 10px; border-radius:4px;
                   background:#f4f7fb; font-size:10.5px; line-height:1.5;
                   color:#41506b; display:flex; align-items:center; gap:10px;
                   flex-wrap:wrap; }
.co_memonote .pf_btn { padding:2px 9px; font-size:10.5px; flex:0 0 auto; }

.co_memofoot     { margin-top:14px; padding-top:9px; border-top:1px solid #eceff4;
                   font-size:10px; line-height:1.5; color:#9aa0a8; }

body.appbuilder-dark .co_memodis    { background:#3a2f1c; color:#e8c07a; border-left-color:#e8a600; }
body.appbuilder-dark .co_memodis b  { color:#f5dfae; }
body.appbuilder-dark .co_memoagr    { color:#4fd1a5; }
body.appbuilder-dark .co_memoh      { color:#8d949c; border-bottom-color:var(--border); }
body.appbuilder-dark .co_memothesis li,
body.appbuilder-dark .co_memolist li { color:#e6e6ea; }
body.appbuilder-dark .co_memolist.is-bear li { color:#f0a49d; }
body.appbuilder-dark .co_memolist.is-gap li  { color:#8d949c; }
body.appbuilder-dark .co_memocite   { background:#2b2f35; border-color:#4a4f57; color:#9aa0ac; }
body.appbuilder-dark .co_memocite:hover { border-color:#4a9eff; color:#8ab4f8; }
body.appbuilder-dark .co_memoax_k   { color:#8d949c; }
body.appbuilder-dark .co_memoax_v   { color:#e6e6ea; }
body.appbuilder-dark .co_memoax_w   { color:#7b8189; }
body.appbuilder-dark .co_memonote   { background:#22303f; color:#c9ccd2; }
body.appbuilder-dark .co_memofoot   { color:#7b8189; border-top-color:var(--border); }

/* ---- the overnight pass (Ship 5) ---- */

/* Pushed to the right of the filter row: these two act on the whole
   filtered set rather than narrowing it, so they must not read as two
   more filter chips in the same run. */
.co_passacts     { margin-left:auto; display:flex; align-items:center; gap:6px; flex:0 0 auto; }
.rs_fchip.is-run { border-color:#a8c6f5; background:#eaf1fd; color:#1c53b8; font-weight:600; }
.rs_fchip.is-run:hover { border-color:#7fa9ee; }

.co_pass_st      { width:78px; }
.co_pass_pct     { font-size:9.5px; color:#0f9d76; font-variant-numeric:tabular-nums; }
/* The counts, as chips that skim. Zero is drawn as NOTHING rather than
   as "0" — a row of zeros is harder to scan past than a blank one. */
.co_pass_n       { font-size:10px; line-height:1.7; }
.co_pass_n span  { display:inline-block; padding:1px 6px; margin:0 4px 3px 0;
                   border-radius:9px; background:#eef1f5; color:#41506b;
                   border:1px solid #dbe0e8; white-space:nowrap; }
.co_pass_n .is-arm    { background:#e6f6f0; color:#0b7a5c; }
/* The two that are worth opening a dossier for, and the only two that
   take a colour anyone would call an alarm. */
.co_pass_n .is-contra { background:#fbeaea; color:#8f231d; font-weight:600; }
.co_pass_n .is-dis    { background:#fdf3e3; color:#9a6a10; font-weight:600; }

.co_pass_log     { font-size:10px; color:#6b7280; max-width:520px; }
.co_pass_log pre { margin:5px 0 0; padding:7px 9px; border-radius:4px;
                   background:#f7f8fa; font:10px/1.6 monospace; color:#41506b;
                   white-space:pre-wrap; overflow-wrap:anywhere; }
.co_pass_log summary { cursor:pointer; color:#1c53b8; }

body.appbuilder-dark .rs_fchip.is-run { background:#1e2c44; border-color:#33507d; color:#8ab4f8; }
body.appbuilder-dark .co_pass_n span  { background:#323844; border-color:#454d5c; color:#d4d8de; }
body.appbuilder-dark .co_pass_n .is-arm    { background:#17342b; color:#4fd1a5; }
body.appbuilder-dark .co_pass_n .is-contra { background:#3a1f1d; color:#f0837a; }
body.appbuilder-dark .co_pass_n .is-dis    { background:#3a2f1c; color:#e8c07a; }
body.appbuilder-dark .co_pass_log     { color:#8d949c; }
body.appbuilder-dark .co_pass_log pre { background:#22262b; color:#c9ccd2; }
body.appbuilder-dark .co_pass_log summary { color:#8ab4f8; }
body.appbuilder-dark .co_pass_pct     { color:#4fd1a5; }

/* ---- the spend budget ---- */

/* THE CEILING, STATED BEFORE THE CLICK. Muted, because it is a limit
   rather than a warning — a spend cap presented in alarm colours reads
   as something having gone wrong before anything has happened. */
.co_passcost     { margin-top:10px; padding:8px 10px; border-radius:4px;
                   background:#f4f7fb; font-size:10.5px; line-height:1.55;
                   color:#41506b; }
.co_passopt      { display:flex; gap:9px; align-items:flex-start;
                   padding:10px 0 0; font-size:11.5px; line-height:1.55;
                   color:#41506b; cursor:pointer; }
.co_passopt input { margin-top:2px; flex:0 0 auto; }

/* What a pass cost, beside what it did. Neutral: money spent as intended
   is not an alarm, and the two chips that ARE alarms sit in the same row. */
.co_pass_n .is-cost { background:#eef1f5; color:#41506b;
                      font-variant-numeric:tabular-nums; }

body.appbuilder-dark .co_passcost   { background:#22303f; color:#c9ccd2; }
body.appbuilder-dark .co_passopt    { color:#c9ccd2; }
body.appbuilder-dark .co_pass_n .is-cost { background:#2b2f35; color:#c9ccd2; }

/* ---- qualification: progress, guidance, and the reason ---- */

/* The bar sits between the panel head and the filters, and is EMPTY
   when nothing is running — it is written in place rather than
   repainted, so the slot has to exist before the first frame lands.
   Empty it collapses to nothing, hence no padding of its own. */
.co_qualbar      { flex:0 0 auto; }
.co_qualbar:not(:empty) { padding:9px 12px; border-bottom:1px solid #eceff4; }
.co_qualbar_t    { display:flex; align-items:center; gap:7px;
                   font-size:11px; color:#41506b; margin-bottom:6px; }
.co_qualbar_t .fa { color:#269DF0; }
.co_qualbar_n    { margin-left:auto; font-size:10px; color:#9aa0a8;
                   font-variant-numeric:tabular-nums; }

/* What the three buckets mean. Sits above the filters because it
   explains what they filter, and is muted because a reader who has
   understood it once should be able to look past it. */
.co_clhelp       { margin:0; padding:9px 12px 0; font-size:10.5px;
                   line-height:1.55; color:#6b7280; }

/* THE REASON, IN THE CLAIM COLUMN rather than in a tooltip (where a
   reader never looks) and rather than in the status column (which holds
   chips — a word each — and grew to five lines when a sentence landed in
   it). It is an argument ABOUT the claim, so it sits under the claim,
   beside the quoted evidence it competes with for the reader's attention.

   Tinted by which way it argues: agreeing and disagreeing with a claim
   are the two things a reader is scanning for, and identical grey
   paragraphs make them read the first words of every one to find out. */
.co_evverdwhy    { display:flex; align-items:flex-start; gap:6px;
                   margin-top:6px; padding:5px 8px; border-radius:4px;
                   font-size:10px; line-height:1.5; overflow-wrap:anywhere; }
.co_evverdwhy > .fa { font-size:9px; margin-top:2px; flex:0 0 auto; }
.co_evverdwhy.is-yes { background:#eef7f3; border-left:2px solid #0f9d76; color:#2f6b58; }
.co_evverdwhy.is-no  { background:#f7f2f2; border-left:2px solid #b3261e; color:#7a4a46; }

body.appbuilder-dark .co_qualbar:not(:empty) { border-bottom-color:var(--border); }
body.appbuilder-dark .co_qualbar_t  { color:#c9ccd2; }
body.appbuilder-dark .co_qualbar_n  { color:#8d949c; }
body.appbuilder-dark .co_clhelp     { color:#8d949c; }
body.appbuilder-dark .co_evverdwhy.is-yes { background:#17342b; border-left-color:#0f9d76; color:#8fd9c1; }
body.appbuilder-dark .co_evverdwhy.is-no  { background:#33211f; border-left-color:#b3261e; color:#e0a8a3; }

/* THE DOOR A GAP CLOSES THROUGH. A gap with no Find button used to end
   in nothing, and the two fields that stayed open on a worked dossier
   were exactly the two whose answer is a screen away. Quieter than the
   Find buttons beside it — it navigates, it does not fetch — but still
   visibly a control rather than a caption. */
.co_cvgo         { flex:0 0 auto; border:1px solid #d8d6d2; border-radius:9px;
                   background:#fff; color:#1c53b8; cursor:pointer;
                   font:10px OpenSans, sans-serif; padding:1px 8px;
                   white-space:nowrap; }
.co_cvgo:hover   { border-color:#269DF0; background:#f4f9fe; }

body.appbuilder-dark .co_cvgo       { background:#2b2f35; border-color:#4a4f57; color:#8ab4f8; }
body.appbuilder-dark .co_cvgo:hover { border-color:#4a9eff; background:#22303f; }

/* The committed-range chip on the Fair value synthesis head.
   Green when what is committed matches the blend, amber when the blend
   has moved on — the state "Re-commit" exists for. The numbers ride on
   the chip because the blend below keeps moving with the sliders, and
   the committed range is the one the radar and the verdict actually
   read. */
.co_fvcommit          { font-variant-numeric:tabular-nums; }
.co_fvcommit.is-on    { background:#e6f6f0; color:#0b7a5c; }
.co_fvcommit.is-on .fa    { color:#0f9d76; }
.co_fvcommit.is-stale { background:#fdf3e3; color:#9a6a10; }
.co_fvcommit.is-stale .fa { color:#e8a600; }

body.appbuilder-dark .co_fvcommit.is-on    { background:#17342b; color:#4fd1a5; }
body.appbuilder-dark .co_fvcommit.is-stale { background:#3a2f1c; color:#e8c07a; }

/* "reviewed <date>" — the theme's counterpart to the fair value's
   committed chip. Green because the promise is kept, quiet because a
   kept promise is the normal state: the loud treatment stays with
   overdue, which is the one that needs a reader's eye. */
.th_revchip           { background:#e6f6f0; color:#0b7a5c;
                        font-variant-numeric:tabular-nums; }
.th_revchip .fa       { color:#0f9d76; }

body.appbuilder-dark .th_revchip     { background:#17342b; color:#4fd1a5; }
body.appbuilder-dark .th_revchip .fa { color:#4fd1a5; }

/* THE UNSCORED DIAL, as the control that fills it. Same 60px circle the
   dial draws so the header row does not change height when a score
   lands — dashed, because the convention everywhere else here is that
   dashed means "nothing measured yet", and a solid ring would read as a
   score of zero. */
.co_dialgo       { width:60px; height:60px; flex:0 0 auto; border-radius:50%;
                   border:2px dashed #c8ccd4; background:transparent;
                   color:#9aa0a8; cursor:pointer;
                   display:flex; flex-direction:column; align-items:center;
                   justify-content:center; gap:1px;
                   font:9px OpenSans, sans-serif; letter-spacing:0.3px;
                   text-transform:uppercase; }
.co_dialgo .fa   { font-size:13px; }
.co_dialgo:hover { border-color:#269DF0; color:#1c53b8; }

body.appbuilder-dark .co_dialgo       { border-color:#4a4f57; color:#8d949c; }
body.appbuilder-dark .co_dialgo:hover { border-color:#4a9eff; color:#8ab4f8; }

/* An unscored axis reads muted and italic: it is a finding about the
   evidence, not a number, and five identical rows would make a reader
   compare a dash with a 72 as though they were the same kind of fact. */
.co_memoax.is-null .co_memoax_k,
.co_memoax.is-null .co_memoax_v { color:#c8ccd4; }
.co_memoax.is-null .co_memoax_w { font-style:italic; }
body.appbuilder-dark .co_memoax.is-null .co_memoax_k,
body.appbuilder-dark .co_memoax.is-null .co_memoax_v { color:#5a6068; }

/* The apply note, once the dossier holds the case's scores. Green like
   the committed-range and reviewed chips — one visual grammar for 'the
   press that mattered has landed', learned once, read everywhere. */
.co_memonote.is-applied { background:#eef7f3; }
.co_memoapplied         { color:#0b7a5c; font-weight:600; }
.co_memoapplied .fa     { color:#0f9d76; }
body.appbuilder-dark .co_memonote.is-applied { background:#17342b; }
body.appbuilder-dark .co_memoapplied         { color:#4fd1a5; }

/* The price block is a BUTTON now — it opens the instrument zoom — so
   it sheds the UA button styling and keeps the block's own. The ticker
   rides as an eyebrow: a price with no name on it is a number that
   could belong to anything once the eye has left the title. */
button.co_pricebox { font:inherit; text-align:left; cursor:pointer; }
button.co_pricebox:hover { border-color:#269DF0; }
.co_pricebox_t   { font-size:9px; font-weight:700; letter-spacing:0.5px;
                   color:#9aa0a8; margin-bottom:1px; }
/* The tone classes colour the block; the eyebrow stays neutral so the
   ticker does not read as up or down. */
.co_pricebox.instr_up .co_pricebox_t,
.co_pricebox.instr_down .co_pricebox_t { color:#9aa0a8; }
/* The all-N door on the tripwires head, pushed right. */
.co_watch_all    { margin-left:auto; }
body.appbuilder-dark button.co_pricebox:hover { border-color:#4a9eff; }
body.appbuilder-dark .co_pricebox_t { color:#8d949c; }

/* ---- the DCF, read aloud ---- */
/* The lead paragraph is the conclusion and reads at body size; the rest
   are the workings and step down. Same treatment the commentary gets. */
.co_dcfread          { margin:10px 0 0; font-size:11.5px; line-height:1.6; color:#41506b; }
.co_dcfread.is-lead  { font-size:12.5px; color:#27251E; }
.co_scntbl           { margin-bottom:4px; }
.co_scn_l            { font-size:10.5px; color:#6b7280; }
.co_scn_v            { font-weight:600; font-variant-numeric:tabular-nums; }
.co_scn_base .co_scn_l { color:#27251E; font-weight:600; }
body.appbuilder-dark .co_dcfread         { color:#c9ccd2; }
body.appbuilder-dark .co_dcfread.is-lead { color:#e6e6ea; }
body.appbuilder-dark .co_scn_l           { color:#8d949c; }
body.appbuilder-dark .co_scn_base .co_scn_l { color:#e6e6ea; }

/* A PINNED assumption field. The pin is the honest unit — per field,
   not the old all-or-nothing footer that called five back-filled
   constants 'your saved assumptions'. */
.co_assume_f.is-mine .co_assume_l { color:#1c53b8; }
.co_assume_pin       { font-size:9px; color:#269DF0; }
body.appbuilder-dark .co_assume_f.is-mine .co_assume_l { color:#8ab4f8; }
body.appbuilder-dark .co_assume_pin { color:#4a9eff; }

/* RECALCULATING. Every region the assumptions feed dims while the
   server recomputes — the numbers on screen are the old ones for that
   half-second, and figures about to be replaced should not look
   current. The savestate chip beside the title says the word;
   pointer-events stays ON so a reader can keep typing in the fields. */
.co_recalc .co_dcfbody, .co_recalc .co_sensbody, .co_recalc .co_revbody,
.co_recalc .co_synthbody, .co_recalc .co_multbody, .co_recalc .co_dcfhead,
.co_recalc .co_readwrap { opacity:0.45; transition:opacity 0.15s; }
.co_savestate.is-saving::before { content:''; display:inline-block;
   width:9px; height:9px; margin-right:5px; border-radius:50%;
   border:2px solid #269DF0; border-top-color:transparent;
   animation:co_spin 0.7s linear infinite; vertical-align:-1px; }
@keyframes co_spin { to { transform:rotate(360deg); } }

/* The synthesis head carries a long committed-range chip AND the Commit
   button in a half-width column. The chip gives way — ellipsis, with the
   full range still in its tooltip — because a label can shorten and a
   button that has been pushed out of the panel cannot be pressed. */
.co_fvcommit     { flex:0 1 auto; min-width:0; overflow:hidden;
                   text-overflow:ellipsis; white-space:nowrap; display:block; }
.th_panel_head .th_head_actions { flex:0 0 auto; margin-left:auto; }
/* The capped reverse figure: a bound, visually distinct from an answer. */
.co_rev_big.is-capped { color:#9a6a10; }
body.appbuilder-dark .co_rev_big.is-capped { color:#e8c07a; }

/* ---- the theme's verdict tab (Ship 5, 2026-09-07) -------------------------
   Three classes the dossier had no equivalent of: its headline sits inside a
   stance row (.co_stance_h) where the theme's stands alone above the signal
   table, and its coverage is a table where the theme's is a grouped checklist
   of WORK rather than of fields. Light and dark together, as every visual
   change here ships. */
.co_verdict_head { margin:0 0 8px; font-size:13px; line-height:1.6; color:#27251E;
                   font-weight:600; text-wrap:balance; }
.co_covgrp       { margin:10px 0 0; }
.co_covgrp h4    { margin:0 0 4px; font-size:10.5px; font-weight:700; color:#6b7280;
                   text-transform:uppercase; letter-spacing:0.6px; }
.co_covslot      { display:flex; align-items:center; gap:7px; padding:3px 0;
                   font-size:12px; color:#6b7280; }
/* Present reads as ordinary text and missing as muted, rather than the other
   way round: the reader is scanning for the gaps, and colouring the done ones
   would make a nearly-complete theme a wall of green with the one thing that
   matters hidden in it. */
.co_covslot.is-on { color:#27251E; }
.co_covslot .fa  { flex:0 0 auto; width:12px; font-size:11px; color:#c7ccd4; }
.co_covslot.is-on .fa { color:#3d8f5e; }
body.appbuilder-dark .co_verdict_head  { color:#e6e6ea; }
body.appbuilder-dark .co_covgrp h4     { color:#8d949c; }
body.appbuilder-dark .co_covslot       { color:#8d949c; }
body.appbuilder-dark .co_covslot.is-on { color:#e6e6ea; }
body.appbuilder-dark .co_covslot .fa   { color:#4a505a; }
body.appbuilder-dark .co_covslot.is-on .fa { color:#5fb37f; }

/* ---- verdict action line: the decision at this price (2026-09-04) ---- */
.co_actionline   { display:flex; align-items:center; gap:10px; margin:6px 0 2px; }
.co_action_tag   { flex:0 0 auto; font-size:11px; font-weight:700; letter-spacing:0.6px;
                   padding:3px 10px; border-radius:3px; border:1px solid transparent; }
.co_action_tag.act-good { background:#e6f4ec; color:#116b3a; border-color:#bfe3cd; }
.co_action_tag.act-bad  { background:#fbeaea; color:#b3261e; border-color:#efc6c3; }
.co_action_tag.act-warn { background:#fdf3e3; color:#9a6a10; border-color:#ecd9ae; }
.co_action_why   { font-size:12px; color:#555; min-width:0; }
.co_gateline     { margin:2px 0 4px; font-size:11.5px; font-style:italic; color:#9a6a10; }
.co_gateline .fa { font-size:10px; }
body.appbuilder-dark .co_action_tag.act-good { background:#22392c; color:#7ddb9a; border-color:#2f5540; }
body.appbuilder-dark .co_action_tag.act-bad  { background:#3a2626; color:#ef9a9a; border-color:#5a3838; }
body.appbuilder-dark .co_action_tag.act-warn { background:#3a3223; color:#f0b400; border-color:#5a4d2e; }
body.appbuilder-dark .co_action_why { color:#b5b5b5; }
body.appbuilder-dark .co_gateline   { color:#d9a72a; }

/* ---- Business & Context tab (Ship 1: About + Business model & mix) ---- */
.co_cx_body      { display:flex; flex-direction:column; gap:10px; }
.co_cx_note      { margin:0; padding:6px 10px; font-size:12px; color:#9a6a10;
                   background:#fdf3e3; border-radius:4px; }
.co_cx_about     { display:grid; grid-template-columns:1.55fr 1fr; gap:18px; align-items:start; }
@media (max-width:1300px) { .co_cx_about { grid-template-columns:1fr; } }
.co_cx_tagline   { font-size:15px; font-weight:700; color:#8a6210; letter-spacing:-0.01em; margin:0 0 6px; }
.co_cx_vp        { font-size:13px; line-height:1.55; margin:0 0 10px; }
.co_cx_kpis      { display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin:0 0 12px; }
@media (max-width:1300px) { .co_cx_kpis { grid-template-columns:repeat(2,1fr); } }
.co_cx_two       { display:grid; grid-template-columns:1.2fr 1fr; gap:16px; }
@media (max-width:1100px) { .co_cx_two { grid-template-columns:1fr; } }
.co_cx_blockh    { font-size:10.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase;
                   color:#8a8f98; margin:12px 0 5px; padding-bottom:4px; border-bottom:1px dashed #dfe2e8; }
.co_cx_offer     { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; }
.co_cx_offer li  { padding:4px 0 4px 10px; border-left:2px solid #dfe2e8; font-size:12px; line-height:1.4; }
.co_cx_dim       { color:#6b7280; }
.co_cx_chips     { display:flex; flex-wrap:wrap; gap:6px; }
.co_cx_chip      { display:inline-flex; align-items:center; gap:4px; }
.co_cx_eco       { display:grid; grid-template-columns:repeat(3,1fr); gap:14px; }
@media (max-width:1100px) { .co_cx_eco { grid-template-columns:1fr; } }
.co_cx_eco .co_cx_blockh { margin-top:0; }
.co_cx_info      { background:#f6f7f9; border:1px solid #e2e5ea; border-radius:6px; padding:10px 12px;
                   display:grid; gap:4px; }
.co_cx_infoh     { font-size:10.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase;
                   color:#8a8f98; margin-bottom:4px; }
.co_cx_kv        { display:flex; justify-content:space-between; gap:8px; font-size:12px; align-items:baseline; min-width:0; }
.co_cx_kv > span { color:#8a8f98; flex:0 0 auto; }
.co_cx_kv > b, .co_cx_kv > a { text-align:right; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.co_cx_src       { color:#3872b8; text-decoration:none; font-size:11px; }
.co_cx_src:hover { text-decoration:underline; }
.co_cx_geo       { display:flex; flex-direction:column; gap:5px; }
.co_cx_georow    { display:grid; grid-template-columns:90px 1fr 46px auto; gap:8px; align-items:center; font-size:11.5px; }
.co_cx_georow b  { text-align:right; }
.co_cx_bar       { height:6px; background:#e8eaef; border-radius:3px; overflow:hidden; }
.co_cx_bar i     { display:block; height:100%; background:#B08A3E; border-radius:3px; }
.co_cx_sites     { display:grid; grid-template-columns:1fr 1fr; gap:2px 10px; }
.co_cx_site      { padding:4px 0; border-bottom:1px dashed #e2e5ea; font-size:11.5px; line-height:1.35; }
.co_cx_mss       { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:8px; }
.co_cx_ms        { display:flex; gap:10px; align-items:flex-start; padding:7px 10px; background:#f6f7f9;
                   border:1px solid #e2e5ea; border-radius:6px; font-size:11.5px; line-height:1.4; }
.co_cx_ms b      { color:#8a6210; flex:0 0 auto; }
.co_cx_pitch     { font-size:13px; line-height:1.5; margin:0; }
.co_cx_mix       { display:grid; grid-template-columns:1fr 1fr; gap:20px; }
@media (max-width:1280px) { .co_cx_mix { grid-template-columns:1fr; } }
.co_cx_fit       { display:block; width:100%; height:auto; }
.co_cx_barlbl    { fill:#8a8f98; font-size:10px; }
.co_cx_barpct    { fill:#fff; font-size:10px; font-weight:700; }
.co_cx_legend    { display:flex; flex-wrap:wrap; gap:8px 14px; margin-top:5px; }
.co_cx_lg        { display:inline-flex; align-items:center; gap:5px; font-size:10.5px; color:#6b7280; }
.co_cx_lg i      { width:10px; height:10px; border-radius:2px; display:inline-block; }
.co_cx_barnote   { margin:4px 0 0; font-size:11.5px; }
.co_cx_gap       { font-size:11.5px; font-style:italic; color:#9aa0a8; }
.co_cx_ai        { display:inline-flex; align-items:center; gap:3px; margin-left:6px; vertical-align:baseline; }
.co_cx_aitag     { font-size:9px; font-weight:700; letter-spacing:0.05em; padding:1px 5px; border-radius:3px;
                   background:#fdf3e3; color:#9a6a10; border:1px dashed #ecd9ae; }
.co_cx_aitag.is-rev { background:#e6f4ec; color:#116b3a; border:1px solid #bfe3cd; margin-left:5px; }
.co_cx_ok, .co_cx_no { border:1px solid #d5d8de; background:#fff; border-radius:3px; padding:0 4px;
                   font-size:10px; line-height:16px; cursor:pointer; color:#116b3a; }
.co_cx_no        { color:#b3261e; }
.co_cx_ok:hover  { background:#e6f4ec; }
.co_cx_no:hover  { background:#fbeaea; }
.co_cx_btn.is-on { background:#fdf3e3; border-color:#ecd9ae; color:#9a6a10; }

body.appbuilder-dark .co_cx_note    { background:#3a3223; color:#f0b400; }
body.appbuilder-dark .co_cx_tagline { color:#e0b45a; }
body.appbuilder-dark .co_cx_blockh  { color:#9aa3b2; border-bottom-color:#333a46; }
body.appbuilder-dark .co_cx_offer li{ border-left-color:#333a46; }
body.appbuilder-dark .co_cx_dim     { color:#9aa3b2; }
body.appbuilder-dark .co_cx_info    { background:#20242c; border-color:#333a46; }
body.appbuilder-dark .co_cx_infoh   { color:#9aa3b2; }
body.appbuilder-dark .co_cx_kv > span { color:#9aa3b2; }
body.appbuilder-dark .co_cx_src     { color:#6ba3e0; }
body.appbuilder-dark .co_cx_bar     { background:#2a303b; }
body.appbuilder-dark .co_cx_bar i   { background:#c49a4e; }
body.appbuilder-dark .co_cx_site    { border-bottom-color:#333a46; }
body.appbuilder-dark .co_cx_ms      { background:#20242c; border-color:#333a46; }
body.appbuilder-dark .co_cx_ms b    { color:#e0b45a; }
body.appbuilder-dark .co_cx_barlbl  { fill:#9aa3b2; }
body.appbuilder-dark .co_cx_lg      { color:#9aa3b2; }
body.appbuilder-dark .co_cx_gap     { color:#7b828d; }
body.appbuilder-dark .co_cx_aitag   { background:#3a3223; color:#f0b400; border-color:#5a4d2e; }
body.appbuilder-dark .co_cx_aitag.is-rev { background:#22392c; color:#7ddb9a; border-color:#2f5540; }
body.appbuilder-dark .co_cx_ok, body.appbuilder-dark .co_cx_no
                 { background:#20242c; border-color:#3a414d; }
body.appbuilder-dark .co_cx_ok      { color:#7ddb9a; }
body.appbuilder-dark .co_cx_no      { color:#ef9a9a; }
body.appbuilder-dark .co_cx_ok:hover{ background:#22392c; }
body.appbuilder-dark .co_cx_no:hover{ background:#3a2626; }
body.appbuilder-dark .co_cx_btn.is-on { background:#3a3223; border-color:#5a4d2e; color:#f0b400; }

/* ---- Business & Context Ship 2: industry & trends + market perception ---- */
.co_cx_tag       { font-size:10px; padding:1px 6px; }
.co_cx_tag.is-pos  { background:#e6f4ec; color:#116b3a; }
.co_cx_tag.is-neg  { background:#fbeaea; color:#b3261e; }
.co_cx_tag.is-warn { background:#fdf3e3; color:#9a6a10; }
.co_cx_theme     { border:1px solid #ecd9ae; background:#fbf6ec; color:#8a6210; }
.co_cx_trends    { display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr)); gap:10px; }
.co_cx_trend     { padding:9px 10px; border:1px solid #e2e5ea; border-radius:6px; background:#fafbfc;
                   display:flex; flex-direction:column; gap:5px; }
.co_cx_trendh    { display:flex; gap:6px; flex-wrap:wrap; }
.co_cx_trendt    { font-size:12.5px; line-height:1.4; font-weight:600; }
.co_cx_trends_s  { font-size:11px; color:#6b7280; font-variant-numeric:tabular-nums; }
.co_cx_trajs     { display:flex; flex-direction:column; gap:6px; }
.co_cx_traj      { display:grid; grid-template-columns:260px 1fr; gap:10px; align-items:center;
                   padding:6px 10px; border:1px solid #e2e5ea; border-radius:4px; background:#fafbfc; }
@media (max-width:1000px) { .co_cx_traj { grid-template-columns:1fr; } }
.co_cx_trajl     { display:flex; align-items:center; gap:8px; font-size:12px; }
.co_cx_trajw     { font-size:11.5px; color:#6b7280; }
.co_cx_regs      { display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:8px; }
.co_cx_reg       { padding:8px 10px; border:1px solid #e2e5ea; border-radius:4px; background:#fafbfc; }
.co_cx_regt      { font-size:12px; margin-bottom:5px; }
.co_cx_regc      { display:flex; gap:6px; flex-wrap:wrap; }
.co_cx_perc      { display:grid; grid-template-columns:1.6fr 1fr; gap:18px; align-items:start; }
@media (max-width:1180px) { .co_cx_perc { grid-template-columns:1fr; } }
.co_cx_newsfeed  { display:flex; flex-direction:column; gap:6px; }
.co_cx_news      { border:1px solid #e2e5ea; border-radius:4px; padding:7px 10px; background:#fafbfc; }
.co_cx_newsh     { display:flex; gap:10px; justify-content:space-between; align-items:baseline; }
.co_cx_newst     { font-size:12.5px; font-weight:600; line-height:1.35; color:inherit; text-decoration:none; min-width:0; }
a.co_cx_newst:hover { color:#3872b8; text-decoration:underline; }
.co_cx_newsc     { display:inline-flex; gap:5px; flex-shrink:0; }
.co_cx_newsm     { font-size:10.5px; color:#9aa0a8; margin-top:2px; font-variant-numeric:tabular-nums; }
.co_cx_newsw     { font-size:11.5px; color:#6b7280; margin-top:2px; }
.co_cx_streetkv  { display:flex; flex-direction:column; gap:3px; margin-top:6px; }
.co_cx_streetkv .is-pos { color:#116b3a; }
.co_cx_streetkv .is-neg { color:#b3261e; }

body.appbuilder-dark .co_cx_tag.is-pos  { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .co_cx_tag.is-neg  { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .co_cx_tag.is-warn { background:#3a3223; color:#f0b400; }
body.appbuilder-dark .co_cx_theme  { border-color:#5a4d2e; background:#2a2517; color:#e0b45a; }
body.appbuilder-dark .co_cx_trend, body.appbuilder-dark .co_cx_traj,
body.appbuilder-dark .co_cx_reg, body.appbuilder-dark .co_cx_news
                 { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_cx_trends_s, body.appbuilder-dark .co_cx_trajw,
body.appbuilder-dark .co_cx_newsw { color:#9aa3b2; }
body.appbuilder-dark .co_cx_newsm { color:#7b828d; }
body.appbuilder-dark a.co_cx_newst:hover { color:#6ba3e0; }
body.appbuilder-dark .co_cx_streetkv .is-pos { color:#7ddb9a; }
body.appbuilder-dark .co_cx_streetkv .is-neg { color:#ef9a9a; }

/* ---- Business & Context Ship 3: competition + team & governance ---- */
.co_cx_competition { display:grid; grid-template-columns:340px 1fr; gap:18px; align-items:start; }
@media (max-width:1180px) { .co_cx_competition { grid-template-columns:1fr; } }
.co_cx_radar     { max-width:300px; }
.co_cx_radgrid   { stroke:#dfe2e8; fill:none; }
.co_cx_radlbl    { fill:#8a8f98; font-size:10px; }
.co_cx_radpoly   { fill:rgba(176,138,62,0.16); stroke:#B08A3E; stroke-width:1.6; }
.co_cx_raddot    { fill:#B08A3E; }
.co_cx_raddot.is-null { fill:#c9ccd3; }
.co_cx_forces    { display:flex; flex-direction:column; gap:4px; margin-top:6px; }
.co_cx_force     { font-size:11.5px; line-height:1.4; color:#6b7280; }
.co_cx_force b   { color:inherit; }
.co_cx_forcesc   { display:inline-block; min-width:24px; text-align:right; font-weight:700;
                   color:#8a6210; font-variant-numeric:tabular-nums; margin:0 4px; }
.co_cx_positioning { font-size:12px; line-height:1.5; margin:10px 0 0; }
.co_cx_comps     { display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr)); gap:8px; }
.co_cx_comp      { padding:9px 10px; border:1px solid #e2e5ea; border-radius:6px; background:#fafbfc;
                   display:flex; flex-direction:column; gap:5px; }
.co_cx_comp.is-direct { border-color:#ecd9ae; }
.co_cx_comp[style*="cursor"]:hover { border-color:#B08A3E; background:#fbf6ec; }
.co_cx_comph     { display:flex; gap:6px; align-items:baseline; flex-wrap:wrap; font-size:12.5px; }
.co_cx_compn     { display:flex; gap:12px; flex-wrap:wrap; }
.co_cx_compkv    { display:inline-flex; gap:5px; font-size:11.5px; align-items:baseline; }
.co_cx_compkv > span { color:#8a8f98; }
.co_cx_compkv .is-pos { color:#116b3a; }
.co_cx_compkv .is-neg { color:#b3261e; }
.co_cx_compnote  { font-size:11.5px; color:#6b7280; }
.co_cx_moats     { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:8px; }
.co_cx_moat      { padding:8px 10px; border:1px solid #e2e5ea; border-radius:4px; background:#fafbfc; }
.co_cx_moath     { display:flex; gap:8px; align-items:center; margin-bottom:3px; font-size:12px; }
.co_cx_moatf     { font-size:11.5px; color:#6b7280; line-height:1.35; }
.co_cx_execs     { display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:10px; }
.co_cx_exec      { display:grid; grid-template-columns:40px 1fr; gap:10px; padding:9px 10px;
                   border:1px solid #e2e5ea; border-radius:6px; background:#fafbfc; }
.co_cx_exec.is-ceo { border-color:#ecd9ae; }
.co_cx_avatar    { width:40px; height:40px; border-radius:50%; background:#fbf6ec; color:#8a6210;
                   font-weight:700; font-size:13px; line-height:40px; text-align:center;
                   border:1px solid #ecd9ae; }
.co_cx_exech     { display:flex; gap:8px; align-items:baseline; flex-wrap:wrap; font-size:12.5px; }
.co_cx_exect     { font-size:10.5px; color:#9aa0a8; margin:2px 0 3px; font-variant-numeric:tabular-nums; }
.co_cx_execbg    { font-size:11.5px; color:#6b7280; line-height:1.4; }
.co_cx_teamrow   { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
@media (max-width:1000px) { .co_cx_teamrow { grid-template-columns:1fr; } }
.co_cx_boardstrip{ display:grid; grid-template-columns:repeat(auto-fill,minmax(110px,1fr)); gap:6px;
                   padding:8px 10px; background:#f6f7f9; border-radius:4px; border:1px solid #e2e5ea; }
.co_cx_boardstrip .co_cx_kv { flex-direction:column; align-items:flex-start; display:flex; gap:1px; }
.co_cx_boardnote { font-size:11.5px; color:#6b7280; margin-top:6px; line-height:1.4; }
.co_cx_align     { display:grid; gap:4px; padding:8px 10px; background:#f6f7f9; border-radius:4px;
                   border:1px solid #e2e5ea; }
.co_cx_pevs      { display:flex; flex-direction:column; gap:5px; }
.co_cx_pev       { display:grid; grid-template-columns:70px 1fr auto; gap:10px; align-items:center;
                   padding:5px 10px; border:1px solid #e2e5ea; border-radius:4px; background:#fafbfc;
                   font-size:12px; }

body.appbuilder-dark .co_cx_radgrid  { stroke:#333a46; }
body.appbuilder-dark .co_cx_radlbl   { fill:#9aa3b2; }
body.appbuilder-dark .co_cx_radpoly  { fill:rgba(196,154,78,0.18); stroke:#c49a4e; }
body.appbuilder-dark .co_cx_raddot   { fill:#c49a4e; }
body.appbuilder-dark .co_cx_raddot.is-null { fill:#4a505c; }
body.appbuilder-dark .co_cx_force    { color:#9aa3b2; }
body.appbuilder-dark .co_cx_forcesc  { color:#e0b45a; }
body.appbuilder-dark .co_cx_comp, body.appbuilder-dark .co_cx_moat,
body.appbuilder-dark .co_cx_exec, body.appbuilder-dark .co_cx_pev
                 { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_cx_comp.is-direct, body.appbuilder-dark .co_cx_exec.is-ceo
                 { border-color:#5a4d2e; }
body.appbuilder-dark .co_cx_comp[style*="cursor"]:hover { border-color:#c49a4e; background:#2a2517; }
body.appbuilder-dark .co_cx_compkv > span { color:#9aa3b2; }
body.appbuilder-dark .co_cx_compkv .is-pos { color:#7ddb9a; }
body.appbuilder-dark .co_cx_compkv .is-neg { color:#ef9a9a; }
body.appbuilder-dark .co_cx_compnote, body.appbuilder-dark .co_cx_moatf,
body.appbuilder-dark .co_cx_execbg, body.appbuilder-dark .co_cx_boardnote
                 { color:#9aa3b2; }
body.appbuilder-dark .co_cx_avatar   { background:#2a2517; color:#e0b45a; border-color:#5a4d2e; }
body.appbuilder-dark .co_cx_boardstrip, body.appbuilder-dark .co_cx_align
                 { background:#20242c; border-color:#333a46; }

/* ---- Business & Context Ship 4: structural risks + analyst take ---- */
.co_cx_risks     { display:grid; grid-template-columns:380px 1fr; gap:18px; align-items:start; }
@media (max-width:1180px) { .co_cx_risks { grid-template-columns:1fr; } }
.co_cx_riskmx    { max-width:380px; }
.co_cx_mxhot     { fill:rgba(179,38,30,0.07); }
.co_cx_mxgrid    { stroke:#dfe2e8; stroke-dasharray:3 3; }
.co_cx_mxaxis    { stroke:#c9ccd3; }
.co_cx_mxlbl     { fill:#8a8f98; font-size:9.5px; }
.co_cx_risklist  { list-style:none; margin:0; padding:0; display:flex; flex-direction:column;
                   gap:6px; counter-reset:cxr 0; }
.co_cx_riskli    { padding:8px 10px 8px 30px; border:1px solid #e2e5ea; border-radius:4px;
                   background:#fafbfc; counter-increment:cxr 1; position:relative; }
.co_cx_riskli::before { content:counter(cxr); position:absolute; left:9px; top:8px;
                   font-weight:700; font-size:12px; color:#B08A3E; }
.co_cx_riskh     { display:flex; gap:6px; align-items:baseline; flex-wrap:wrap; font-size:12.5px; font-weight:600; }
.co_cx_riskc     { font-size:11px; color:#9aa0a8; margin-top:2px; font-variant-numeric:tabular-nums; }
.co_cx_riskd     { font-size:11.5px; color:#6b7280; margin-top:2px; line-height:1.4; }
.co_cx_esgs      { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:6px; }
.co_cx_esg       { padding:6px 10px; border:1px solid #e2e5ea; border-radius:4px; background:#fafbfc;
                   display:flex; gap:8px; justify-content:space-between; align-items:center; font-size:12px; }
.co_cx_take      { font-size:13px; line-height:1.55; margin:0 0 8px; }
.co_cx_takef     { display:flex; gap:10px; align-items:center; flex-wrap:wrap;
                   padding-top:6px; border-top:1px dashed #dfe2e8; }

body.appbuilder-dark .co_cx_mxhot   { fill:rgba(239,154,154,0.08); }
body.appbuilder-dark .co_cx_mxgrid  { stroke:#333a46; }
body.appbuilder-dark .co_cx_mxaxis  { stroke:#4a505c; }
body.appbuilder-dark .co_cx_mxlbl   { fill:#9aa3b2; }
body.appbuilder-dark .co_cx_riskli, body.appbuilder-dark .co_cx_esg
                 { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_cx_riskli::before { color:#e0b45a; }
body.appbuilder-dark .co_cx_riskc   { color:#7b828d; }
body.appbuilder-dark .co_cx_riskd   { color:#9aa3b2; }
body.appbuilder-dark .co_cx_takef   { border-top-color:#333a46; }

/* ---- Business & Context polish round (2026-09-04, 20 items) ---- */
/* Chips become true pills everywhere on the tab. */
.co_cx_chip      { border-radius:999px; padding:3px 10px; line-height:1.5; }
.co_cx_chips     { gap:6px 6px; line-height:1.8; }
.co_cx_tag       { border-radius:999px; padding:2px 8px; background:#eef0f3; border:1px solid #dfe2e8; }
/* The wand: AI-written, hover for the rationale. Soft on purpose. */
.co_cx_wand      { color:#9a8ec9; font-size:10px; cursor:help; opacity:0.85; }
.co_cx_wand:hover{ opacity:1; }
/* Anonymise: the text stays, a band paints over it. */
.co_cx_redact    { background:#d7dae0; color:transparent; border-radius:2px; user-select:none; }
/* Identity strip: roomier rows (was too compressed). */
.co_cx_info      { gap:7px; }
.co_cx_info .co_cx_kv { min-height:20px; align-items:center; }
/* Mix charts: smaller in-bar type, more air between the two blocks. */
.co_cx_barlbl    { font-size:7.5px; }
.co_cx_barpct    { font-size:8.5px; }
.co_cx_mix       { gap:24px 24px; }
.co_cx_mix .co_cx_blockh { margin-top:4px; }
/* Right column of About: air between geo and the sites block. */
.co_cx_gaptop    { margin-top:22px !important; }
.co_cx_geo       { margin-bottom:4px; }
/* Porter forces spread horizontally, positioning full width. */
.co_cx_forces    { display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
                   gap:10px; margin-top:12px; flex-direction:unset; }
.co_cx_force     { padding:8px 10px; border:1px solid #e2e5ea; border-radius:6px; background:#fafbfc; }
.co_cx_force b   { display:inline-block; margin-right:2px; }
.co_cx_forcew    { display:block; margin-top:3px; }
.co_cx_positioning { margin-top:10px; font-size:12.5px; }
/* Competitor add / remove. */
.co_cx_addbtn    { border:1px solid #d5d8de; background:transparent; border-radius:999px;
                   padding:1px 9px; font-size:10.5px; cursor:pointer; color:#6b7280;
                   margin-left:8px; text-transform:none; letter-spacing:0; }
.co_cx_addbtn:hover { border-color:#B08A3E; color:#8a6210; }
.co_cx_del       { border:none; background:transparent; color:#9aa0a8; cursor:pointer;
                   font-size:10px; padding:0 3px; }
.co_cx_del:hover { color:#b3261e; }
/* Risk matrix: four light quadrant washes. */
.co_cx_mx_tl     { fill:rgba(90,169,230,0.06); }
.co_cx_mx_tr     { fill:rgba(226,84,79,0.10); }
.co_cx_mx_bl     { fill:rgba(148,163,184,0.04); }
.co_cx_mx_br     { fill:rgba(224,168,46,0.08); }

body.appbuilder-dark .co_cx_tag    { background:#262b35; border-color:#3a414d; }
body.appbuilder-dark .co_cx_wand   { color:#a99fd6; }
body.appbuilder-dark .co_cx_redact { background:#3f4653; }
body.appbuilder-dark .co_cx_force  { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_cx_addbtn { border-color:#3a414d; color:#9aa3b2; }
body.appbuilder-dark .co_cx_addbtn:hover { border-color:#c49a4e; color:#e0b45a; }
body.appbuilder-dark .co_cx_del:hover { color:#ef9a9a; }
body.appbuilder-dark .co_cx_mx_tl  { fill:rgba(90,169,230,0.07); }
body.appbuilder-dark .co_cx_mx_tr  { fill:rgba(226,84,79,0.12); }
body.appbuilder-dark .co_cx_mx_bl  { fill:rgba(148,163,184,0.05); }
body.appbuilder-dark .co_cx_mx_br  { fill:rgba(224,168,46,0.10); }

/* ---- Business & Context: chips carry their OWN paint ---- */
/* rs_chip supplies geometry only; its colours come from is-* variants these
   chips do not use — which left "chips" rendering as bare words. */
.co_cx_chip      { background:#f2f4f7; border:1px solid #dcdfe5; color:#3d434c;
                   font-size:11px; }
.co_cx_chip:hover{ border-color:#c9ccd3; }
.co_cx_tag       { color:#5a616b; }
body.appbuilder-dark .co_cx_chip { background:#242a34; border-color:#39404c; color:#c6cdd8; }
body.appbuilder-dark .co_cx_chip:hover { border-color:#4a525f; }
body.appbuilder-dark .co_cx_tag  { color:#a5adb9; }

/* ---- Business & Context: second polish round ---- */
a.co_cx_wand     { cursor:pointer; text-decoration:none; }
i.co_cx_wand     { cursor:help; }
.co_cx_built     { flex:0 0 auto; align-self:center; margin-right:6px; }
.co_cx_georow    { min-height:21px; }
.co_cx_geo       { gap:7px; }
.co_cx_regt      { line-height:1.45; margin-bottom:6px; font-weight:600; font-size:12.5px; }
.co_cx_reg       { display:flex; flex-direction:column; gap:2px; }

/* ---- Business & Context: ESG cards breathe like the other cards ---- */
.co_cx_esg       { padding:9px 10px; }
.co_cx_esg > span:first-child { line-height:1.45; font-size:12px; }

/* ---- Business & Context: the Street figures sit clear of the split bar ---- */
.co_cx_streetkv  { margin-top:12px; gap:7px; }
.co_cx_streetkv .co_cx_kv { min-height:21px; align-items:center; font-size:12px; }
.co_cx_streetkv  { gap:3px; }

/* ---- Business & Context: the take's footer meta is small print ---- */
.co_cx_takef .co_cx_dim { font-size:10.5px; }

/* ---- AI verdict: air between the action row and the gate line ---- */
.co_actionline   { margin:8px 0 0; }
.co_gateline     { margin:8px 0 6px; }

/* ---- the earnings-delta writer's offer row (Conviction breakdown) ---- */
.co_deltaoffer   { display:flex; align-items:center; justify-content:space-between; gap:10px;
                   margin:6px 0 8px; padding:6px 10px; background:#fdf3e3;
                   border:1px dashed #ecd9ae; border-radius:4px; font-size:11.5px; color:#8a6210; }
body.appbuilder-dark .co_deltaoffer { background:#3a3223; border-color:#5a4d2e; color:#f0b400; }

/* ---- Ask: the dossier assistant, DOCKED beside the record ----
   The conversation itself is the standard chat widget every other panel
   mounts; everything here is the dock around it. */
.co_ws_split     { display:flex; align-items:stretch; min-height:0; flex:1 1 auto; }
.co_ws_main      { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; min-height:0; }
.co_ws_chat      { position:relative; flex:0 0 auto; width:400px; min-width:320px; max-width:760px;
                   display:flex; flex-direction:column; min-height:0;
                   border-left:1px solid #e2e5ea; background:#fafbfc; }
/* The grip straddles the border: grabbable without being drawn. */
.co_ws_grip      { position:absolute; left:-3px; top:0; bottom:0; width:7px; cursor:col-resize; z-index:2; }
.co_ws_grip:hover{ background:rgba(127,169,238,0.35); }
body.co_ws_resizing { cursor:col-resize; user-select:none; }
.co_ws_chatinner { display:flex; flex-direction:column; min-height:0; flex:1 1 auto; }
.co_ws_chathead  { display:flex; align-items:baseline; gap:8px; padding:8px 10px;
                   border-bottom:1px solid #e2e5ea; }
.co_ws_chatt     { font-weight:600; font-size:12.5px; }
.co_ws_chatsub   { font-size:10px; color:#6b7280; overflow:hidden;
                   text-overflow:ellipsis; white-space:nowrap; }
.co_ws_chatacts  { margin-left:auto; display:flex; gap:4px; flex:0 0 auto; }
/* Sized exactly as the Charts panel sizes the same widget. */
.co_ws_chathost  { width:100%; flex:1 1 auto; min-height:0; overflow:hidden; }
.co_askload      { padding:12px; font-size:12px; color:#6b7280; }
/* The header toggle wears the panel's state — a button that opens something
   and then looks identical is one you press twice. */
/* The pressed state of a header toggle (Ask). Both bars, because the rule
   was scoped to the dossier's only and the theme's Ask never lit. */
.co_hd_acts .pf_btn.is-on,
.th_head_acts .pf_btn.is-on { background:#eaf1fd; border-color:#a8c6f5; color:#1c53b8; }

/* The dossier's own footnotes, added under a standard bubble. */
.co_askread      { font-size:10.5px; color:#6b7280; margin-bottom:4px; }
.co_askread .fa  { margin-right:5px; }
.co_askcites     { display:flex; align-items:center; gap:6px; margin-top:6px; flex-wrap:wrap; }
.co_askcites_l   { font-size:10px; letter-spacing:0.6px; text-transform:uppercase; color:#6b7280; }


body.appbuilder-dark .co_ws_chat     { border-left-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_ws_chathead { border-bottom-color:#333a46; }
body.appbuilder-dark .co_ws_chatsub,
body.appbuilder-dark .co_askcites_l,
body.appbuilder-dark .co_askread,
body.appbuilder-dark .co_askload     { color:#9aa3b2; }
body.appbuilder-dark .co_hd_acts .pf_btn.is-on,
body.appbuilder-dark .th_head_acts .pf_btn.is-on {
                     background:#1e2c44; border-color:#33507d; color:#8ab4f8; }

/* ---- company logos on the directory + the dossier header ---- */
.co_dicon        { width:20px; height:20px; margin-right:6px; }
.co_dicon .screener_icon_img,
.co_dicon .screener_icon_mono { width:20px; height:20px; font-size:9px; }
.co_dicon .screener_icon_img  { padding:2px; }
/* The header logo spans exactly the identity's two lines (eyebrow + name),
   which sit in a column flush to its right — the gap is the only spacing.
   Status and stage live on their own row below, back at the left margin. */
.co_hd_id        { display:flex; align-items:center; gap:9px; }
.co_hd_idtxt     { min-width:0; }
.co_hdicon       { width:48px; height:48px; flex:0 0 auto; }
.co_hdicon .screener_icon_img,
.co_hdicon .screener_icon_mono { width:48px; height:48px; font-size:18px; }
.co_hd_id .co_hd_h1      { margin:0; }
.co_hd_idtxt .co_eyebrow { margin:0 0 4px; }
.co_hd_tags      { display:flex; align-items:center; gap:6px; margin:7px 0 2px; }

/* ---- Business & Context: the section rail (the description step's own,
       co_cx_rail only sizes it into this grid) ---- */
.co_cx_layout    { display:grid; grid-template-columns:200px minmax(0,1fr);
                   gap:14px; align-items:start; }
.co_cx_rail      { position:sticky; top:0; }
/* An anchored section lands a breath below the top edge, not glued to it. */
.co_cx_main [data-cxsec] { scroll-margin-top:8px; }

/* ---- dossier snapshots: the history list + the read-only viewer ---- */
.co_clocks       { cursor:pointer; }
/* The review cadence sits beside the clocks because it is a fact about the
   same thing — how current this reading is — and it is a control, so it says
   so with a pointer rather than the help cursor the readings carry. */
.co_cadence      { cursor:pointer; }
.co_cadence:hover{ text-decoration:underline; }
.co_snaprow      { display:flex; align-items:center; gap:8px; width:100%; text-align:left;
                   padding:8px 12px; margin-bottom:6px; border:1px solid #e2e5ea;
                   border-radius:6px; background:#fafbfc; cursor:pointer; font-size:12px; }
.co_snaprow:hover{ border-color:#7fa9ee; background:#f2f6fd; }
.co_snapwhen     { font-variant-numeric:tabular-nums; color:#41506b; flex:0 0 auto; }
.co_snapact      { font-size:11px; letter-spacing:0.4px; }
.co_snapdim      { color:#6b7280; font-size:11px; }
.co_snapnote     { color:#6b7280; font-size:11px; font-style:italic;
                   overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.co_snapview .co_snapsec { padding:10px 0; border-bottom:1px solid #eceef2; }
.co_snapview .co_snapsec:last-child { border-bottom:none; }
.co_snaph        { font-size:10px; letter-spacing:0.8px; text-transform:uppercase;
                   color:#6b7280; margin-bottom:6px; }
.co_snapline     { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.co_snapp        { margin:6px 0 0; font-size:12.5px; line-height:1.6; }
.co_snapgate     { color:#8a6210; }

body.appbuilder-dark .co_snaprow      { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_snaprow:hover{ border-color:#33507d; background:#1e2c44; }
body.appbuilder-dark .co_snapwhen     { color:#c9ccd2; }
body.appbuilder-dark .co_snapdim,
body.appbuilder-dark .co_snapnote     { color:#9aa3b2; }
body.appbuilder-dark .co_snapview .co_snapsec { border-color:#2c313a; }
body.appbuilder-dark .co_snapgate     { color:#e8c07a; }

/* ---- versions, the two clocks, read-only history ---- */
.co_clocks           { font-size:10.5px; letter-spacing:0; text-transform:none; cursor:help; }
.co_clocks.is-fresh,
.co_caseat.is-fresh  { color:#0f9d76; }
.co_clocks.is-aging,
.co_caseat.is-aging  { color:#b07a10; }
.co_clocks.is-old,
.co_caseat.is-old    { color:#b3372f; }
.co_caseat           { font-variant-numeric:tabular-nums; font-size:11px; }
.co_cx_vers          { display:inline-flex; gap:4px; margin-right:8px; }
/* Read-only history: the record keeps its wands (provenance) and loses its
   hands — every mutating control disappears as a set. */
.co_cx_ro .co_cx_del,
.co_cx_ro .co_cx_addbtn,
.co_cx_ro .co_cx_takebtn { display:none !important; }
.co_passopt_sub      { margin-left:26px; }

body.appbuilder-dark .co_clocks.is-fresh,
body.appbuilder-dark .co_caseat.is-fresh { color:#4fd1a5; }
body.appbuilder-dark .co_clocks.is-aging,
body.appbuilder-dark .co_caseat.is-aging { color:#e8c07a; }
body.appbuilder-dark .co_clocks.is-old,
body.appbuilder-dark .co_caseat.is-old   { color:#f0837a; }

/* ---- the perception pass: street view, AI card, overview risk fallback ---- */
.co_cx_mgmtcur     { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:2px 0 10px; }
.co_cx_mgmtnote    { font-size:11.5px; color:#41506b; }
.co_cx_mgmtcols    { display:grid; grid-template-columns:1fr 1fr; gap:18px; margin:4px 0 8px; }
.co_cx_mgmtcolh    { margin-bottom:6px; }
.co_cx_mgmtlist    { margin:0; padding-left:18px; font-size:12px; line-height:1.75; }
.co_cx_mgmtoverall { margin-top:6px; padding:7px 10px; background:#f6f8fa; border-radius:5px;
                     font-size:12px; line-height:1.6; color:#41506b; }
.co_cx_aihead      { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:2px 0 10px; }
.co_cx_aiframe     { font-size:12.5px; line-height:1.6; }
.co_ovrisk_src     { font-size:10.5px; margin-bottom:8px; }
.co_fvcommitbtn    { margin-top:8px; }

body.appbuilder-dark .co_cx_mgmtnote    { color:#c9ccd2; }
body.appbuilder-dark .co_cx_mgmtoverall { background:#22262b; color:#c9ccd2; }

/* ---- Run in background: the picker + the live tasks view ---- */
.co_bgtools      { display:flex; gap:8px; margin:2px 0 6px; }
.co_bglist       { max-height:220px; overflow-y:auto; border:1px solid #e2e5ea; border-radius:6px;
                   padding:4px 0; margin-bottom:10px; background:#fafbfc; }
.co_bgrow        { display:flex; align-items:center; gap:9px; padding:4px 12px; cursor:pointer;
                   font-size:12px; min-height:24px; }
.co_bgrow:hover  { background:#f2f4f7; }
.co_bgrow.is-busy { opacity:0.65; cursor:default; }
.co_bgrow b      { flex:0 0 auto; min-width:74px; }
.co_bgname       { color:#6b7280; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex:1 1 auto; }
.co_passlive     { color:#116b3a; font-size:11px; margin-left:6px; }
.co_pass_now     { color:#116b3a; font-size:11.5px; margin:0 0 4px; font-weight:600; }
.co_pass_now .fa { margin-right:5px; }

/* The tasks table: everything hangs from the TOP of the row — a tall step
   log must not float its status chip and buttons to the vertical middle. */
.co_passtbl td   { vertical-align:top; }
.co_pass_t       { font-variant-numeric:tabular-nums; font-size:11px;
                   color:#41506b; white-space:nowrap; }
.co_pass_act     { text-align:right; white-space:nowrap; }
.co_passbtn      { font-size:10.5px; padding:3px 9px; border:1px solid #c9d2de;
                   border-radius:4px; background:#fff; color:#41506b; cursor:pointer;
                   white-space:nowrap; }
.co_passbtn:hover{ border-color:#7fa9ee; color:#1c53b8; }
.co_passbtn.is-stop       { border-color:#e5b9b6; color:#8f231d; }
.co_passbtn.is-stop:hover { background:#fbeaea; border-color:#d99a95; color:#8f231d; }
.co_pass_n .is-pct { background:#e6f6f0; border-color:#bfe4d5; color:#0b7a5c;
                     font-variant-numeric:tabular-nums; }

body.appbuilder-dark .co_bglist  { border-color:#333a46; background:#20242c; }
body.appbuilder-dark .co_bgrow:hover { background:#262b35; }
body.appbuilder-dark .co_bgname  { color:#9aa3b2; }
body.appbuilder-dark .co_passlive{ color:#7ddb9a; }
body.appbuilder-dark .co_pass_now{ color:#7ddb9a; }
body.appbuilder-dark .co_pass_t  { color:#c9ccd2; }
body.appbuilder-dark .co_passbtn { background:#262b35; border-color:#3a4250; color:#c9ccd2; }
body.appbuilder-dark .co_passbtn:hover { border-color:#33507d; color:#8ab4f8; }
body.appbuilder-dark .co_passbtn.is-stop       { border-color:#5a2e2b; color:#f0837a; }
body.appbuilder-dark .co_passbtn.is-stop:hover { background:#3a1f1d; border-color:#6e3a36; }
body.appbuilder-dark .co_pass_n .is-pct { background:#17342b; border-color:#265c46; color:#4fd1a5; }

/* ============================================================
   Card / list toggle, and the shared directory shell
   ============================================================

   The two research directories — Themes and Company Coverage — now wear one
   chrome: title left, actions right, a two-row filter band under the toolbar,
   and this toggle. The band's own styling is .co_filterbar above; everything
   here is the plumbing that lets a screen hold two views at once, plus the
   card face the radar did not have.

   Light and dark are written together, deliberately: a visual change that
   ships one theme is a visual change that ships broken.                     */


/* ---- the toggle ---- */
/* Two segments, not a dropdown: it is a two-state control and the state has
   to be readable without opening anything. Sized to sit on the 40/44px
   toolbar without stretching it. */
.dir_viewtoggle  { display:inline-flex; align-items:center; margin:0 6px;
                   border:1px solid #d5d8dd; border-radius:6px; overflow:hidden; }
.dir_vbtn        { border:0; background:#fff; color:#9aa0a8; cursor:pointer;
                   padding:3px 10px; font-size:12px; line-height:16px; }
.dir_vbtn + .dir_vbtn { border-left:1px solid #d5d8dd; }
.dir_vbtn:hover  { color:#5a616b; background:#f4f6f9; }
/* SELECTED IS FILLED, not tinted. The first version reused the .rs_fchip "on"
   wash and, at two 12px glyphs, the two states were almost indistinguishable —
   a toggle you have to compare against its neighbour to read is not telling
   you which view you are in. */
.dir_vbtn.on       { background:#1c53b8; color:#fff; }
.dir_vbtn.on:hover { background:#164499; color:#fff; }

body.appbuilder-dark .dir_viewtoggle    { border-color:#4a4f57; }
body.appbuilder-dark .dir_vbtn          { background:#20242c; color:#767c87; }
body.appbuilder-dark .dir_vbtn + .dir_vbtn { border-left-color:#4a4f57; }
body.appbuilder-dark .dir_vbtn:hover    { background:#262b35; color:#c9ccd2; }
body.appbuilder-dark .dir_vbtn.on       { background:#2f6fd0; color:#fff; }
body.appbuilder-dark .dir_vbtn.on:hover { background:#3b7ee0; color:#fff; }

/* ---- the directory main panel, when it holds a band and two views ---- */
/* THERE IS NOTHING TO STYLE HERE, and that is the point. A banded directory
   nests a w2layout — a fixed-height top panel for the band, main for the view
   — which is what Company Coverage has always done, so the panels own the
   geometry and neither view carries a height of its own. Two hand-rolled
   versions were tried first (a flex column, then absolute offsets inside the
   single panel) and both produced a blank screen: each depended on a guess
   about which of w2ui's panel divs is sized and which receives the panel's
   style. .dir_filterbar survives only as the hook RenderFilterBar paints
   into; the band's own look is .co_filterbar, shared with the radar. */

/* ---- the company card ---- */
/* Deliberately the SAME box as the theme card: side by side in one
   application, two directories whose cards differ in size read as two
   applications. Both resets below are what .rs_tcard already does and what
   this card was missing —

   - .applications_element_text is absolutely positioned at left:56px with a
     fixed 156px height, sized for the old logo-on-the-left card. Left alone,
     that 56px is a large empty margin down the left of every company card.
   - and the card must NOT be display:flex. .applications_element is
     inline-block, which is exactly what makes the cards wrap into rows; any
     block-level display puts each card on its own line.                      */
.applications_element.co_card { width:340px; height:auto; }
.co_card .applications_element_text {
	position:static; left:auto; top:auto; width:auto; height:auto;
	overflow:visible; padding:2px 4px 4px;
}
.co_card_head    { display:flex; align-items:center; gap:6px; margin-bottom:2px; }
.co_card_sym     { font-family:'Roboto Mono', monospace; font-size:12px;
                   font-weight:600; color:#27251E; }
.co_card_name    { font-size:13px; font-weight:600; color:#27251E; line-height:20px;
                   white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.co_card_sector  { font-size:11px; color:#8a9099; margin-top:1px;
                   white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Three figures on one row, evenly weighted — the same block the theme card
   uses for conviction / composite / admission, so the eye lands in the same
   place on both. */
.co_card_figs    { display:flex; gap:14px; margin:8px 0 6px; }
.co_card_figs > div { flex:1 1 0; min-width:0; }
.co_card_themes  { margin:2px 0 0; display:flex; flex-wrap:wrap; gap:4px;
                   max-height:22px; overflow:hidden; }

body.appbuilder-dark .co_card_sym,
body.appbuilder-dark .co_card_name   { color:#e6e8ec; }
body.appbuilder-dark .co_card_sector { color:#767c87; }

/* The star as a grid cell rather than a card corner: no absolute placement,
   no card padding to sit in. */
.rs_tcard_fav.is-flat { position:static; padding:0; background:none; border:0;
                        font-size:12px; }

/* ---- the theme header's own idea, and its coverage worklist ----
   Two gaps the theme workspace carried against the dossier:

   1. THE DESCRIPTION WAS INVISIBLE. Only the tagline was rendered, and the
      tagline is written by the DECOMPOSITION — so a hand-created theme showed
      nothing at all and the idea its author typed lived only in the edit
      dialog. Clamped to two lines with the whole text on hover, because a
      pasted paragraph must not push the ladder off the top of the screen.
   2. THE COVERAGE LEDGER HAD NO DOORS. Every missing row now carries the same
      kind of link the dossier's does; .co_cvgo is that button, reused rather
      than re-cut so the two ledgers cannot drift. */
.th_head_desc     { font-size:12px; color:#6b7280; margin-top:3px; max-width:820px;
                    display:-webkit-box; -webkit-box-orient:vertical;
                    -webkit-line-clamp:2; overflow:hidden; }
/* Under a tagline it is the second voice, so it steps back a shade. */
.th_head_desc.is-second { color:#9aa0a8; font-size:11.5px; }

body.appbuilder-dark .th_head_desc           { color:#9aa3b2; }
body.appbuilder-dark .th_head_desc.is-second { color:#767c87; }


/* The theme's Verdict tab, stacked full width — the dossier's shape.
   It was `.th_grid` (1fr / 400px) with the coverage ledger in the right
   column, which is why the two Verdict tabs did not read as one screen: the
   dossier gives its ledger the full width and lays the groups out side by
   side. `.th_stack` is the same padding and gap as `.th_grid`, one column. */
.th_stack         { display:flex; flex-direction:column; gap:12px; padding:12px; min-width:0; }
.th_stack > div   { display:flex; flex-direction:column; gap:12px; min-width:0; }
/* Quiet until wanted, beside the name — the pencil that leads back to the idea. */
.th_head_name     { display:flex; align-items:center; gap:8px; }
.th_head_edit     { border:0; background:none; cursor:pointer; padding:2px 4px;
                    font-size:11px; color:#c7ccd4; line-height:1; }
.th_head_edit:hover { color:#269DF0; }
body.appbuilder-dark .th_head_edit       { color:#565b64; }
body.appbuilder-dark .th_head_edit:hover { color:#8ab4f8; }

/* ---- the fill confirm (both objects, all three doors) ----
   w2confirm centres its message; this box carries a lead, a list of steps, a
   caveat and sometimes an option, and centred it read as a poster. Geometry
   only — no colour — so light and dark are untouched. */
.rs_confirm      { text-align:left; line-height:1.5; padding:2px 8px 0; }
.rs_confirm p    { margin:0 0 8px; }
.rs_confirm ul   { margin:6px 0 10px; padding-left:22px; }
.rs_confirm li   { margin:3px 0; }
.rs_confirm_tail { color:inherit; opacity:0.85; }
.rs_confirm .co_passopt { text-align:left; justify-content:flex-start; margin:10px 0 0; }

/* Links inside a fill note (Background tasks ›, Pipeline ›) were the theme's
   default violet on a dark band — barely there. The note's own blue, bold. */
.co_fillnote a   { color:#1c53b8; font-weight:600; text-decoration:none; }
.co_fillnote a:hover { text-decoration:underline; }
body.appbuilder-dark .co_fillnote a { color:#8ab4f8; }

/* The Type column in Background tasks: a chip that is also the door to the
   object's Pipeline tab. Cursor only — the chip keeps its own colours. */
.co_pass_type    { white-space:nowrap; }
.co_passtype     { cursor:pointer; border:0; }
.co_passtype:hover { text-decoration:underline; }

/* ---- the theme header's fixed shape ----
   Name on one line with an ellipsis, one subtitle clamped to three lines, the
   whole text on hover. The header no longer grows with the prose in it. */
.th_head_id > div { min-width:0; flex:1 1 auto; }
.th_head_name     { max-width:820px; }
.th_head_name_t   { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; cursor:default; }
.th_head_tag      { max-width:820px; display:-webkit-box; -webkit-box-orient:vertical;
                    -webkit-line-clamp:3; overflow:hidden; line-height:1.45; cursor:default; }
/* The formatted tip: name, tagline, description — structure the plain
   data-tooltip cannot carry. Colours inherit from the tooltip itself. */
.th_idtip b       { display:block; font-size:12.5px; margin-bottom:4px; }
.th_idtip_tag     { opacity:0.85; margin-bottom:6px; }
.th_idtip_desc    { white-space:pre-wrap; line-height:1.5; }
/* The idea, in full, at the top of the written case. */
.th_case_idea     { margin:0 0 12px; padding:0 0 10px; border-bottom:1px solid #eceff4; }
.th_case_idea p   { margin:4px 0 0; font-size:12.5px; line-height:1.6; white-space:pre-wrap; color:#41506b; }
body.appbuilder-dark .th_case_idea   { border-bottom-color:#333a46; }
body.appbuilder-dark .th_case_idea p { color:#c9ccd2; }

/* The dossier header's ticker is a link to the instrument: link colour and
   cursor from .gridurl, the h1's size kept. */
.co_hd_tk.gridurl       { cursor:pointer; }
.co_hd_tk.gridurl:hover { text-decoration:underline; }

/* ---- OPENSANS ON THE DIRECTORIES AND THEIR BANDS ----
   This stylesheet has no global font rule (see .bt_panel): each root declares
   OpenSans and its children inherit. The three aligned directories — Themes,
   Company Coverage, Portfolios — render into w2layout panels whose roots
   declared none, so their bands, chips, cards and grids fell to the browser
   serif. And FORM CONTROLS never inherit: every <button> and <input> in a band
   or on a card needs the family said again. */
.applications-panel,
.co_panel,
.theme-panel,
.dir_filterbar,
.co_filterbar,
.applications_container,
.w2ui-grid.w2ui-reset { font-family: OpenSans, "Open Sans", sans-serif; }
.applications-panel button, .applications-panel input, .applications-panel select, .applications-panel textarea,
.co_panel button, .co_panel input, .co_panel select, .co_panel textarea,
.theme-panel button, .theme-panel input, .theme-panel select, .theme-panel textarea,
.co_filterbar button, .co_filterbar input,
.dir_viewtoggle button,
.pf_btn, .co_passbtn, .rs_tcard_fav, .co_brief_re, .pf_dcard_iconbtn,
.ot_side button, .ot_oo_chip, .ac_adopt button { font-family: inherit; }

/* Tag chips in the Scripts grid: one line, clipped rather than wrapped. */
.ts_gridchips { display:inline-flex; gap:4px; white-space:nowrap; overflow:hidden; max-width:100%; }

/* ---- CARDS OF ONE OBJECT ARE ONE SIZE ----
   .applications_element is a fixed 308x166 box. These three families opted out
   with height:auto and then grew with whatever they happened to hold — a
   company with three theme chips stood taller than one with none, a portfolio
   without live KPIs lost its Deployed row — and inline-block laid the result
   out ragged, each row starting wherever the previous one ended.

   Each family now has ONE height, sized to its own fullest card. The body is a
   column that fills it, and the LAST row is pinned to the bottom so the slack
   collects in one place instead of under a different element on every card. */
.applications_element.co_card,
.applications_element.rs_tcard,
.applications_element.pf_dcard  { vertical-align:top; }
.applications_element.co_card   { height:184px; }
.applications_element.rs_tcard  { height:244px; }
.applications_element.pf_dcard  { height:236px; }
.co_card  .applications_element_text,
.rs_tcard .applications_element_text,
.pf_dcard .applications_element_text {
                                  display:flex; flex-direction:column;
                                  height:100%; box-sizing:border-box; overflow:hidden; }
/* The bottom row of each card, pinned. */
.co_card_themes,
.rs_tcard_meta,
.pf_dcard_meta                  { margin-top:auto; }
/* …and the theme strip keeps its row even when the company is in no theme. */
.co_card_themes                 { height:22px; max-height:22px; margin-bottom:0; }
/* The optional sector line reserves its row (the element is always rendered). */
.co_card_sector                 { min-height:14px; }

/* ---- THE SCREENER'S CARD VIEW ----
   The same 340px box the other directories use, one height for every segment:
   the head is the instrument, and under it up to six figures taken from that
   segment's own columns. Two per row, so a long label has somewhere to go. */
.applications_element.scr_card  { width:340px; height:196px; vertical-align:top; }
.scr_card .applications_element_text {
                                  position:static; left:auto; top:auto; width:auto;
                                  display:flex; flex-direction:column; height:100%;
                                  box-sizing:border-box; overflow:hidden; padding:2px 4px 4px; }
.scr_card_figs                  { display:grid; grid-template-columns:1fr 1fr;
                                  gap:7px 14px; margin-top:8px; }
.scr_card_figs > div            { min-width:0; }
.scr_card_figs .rs_tcard_convk  { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.scr_card_figs .rs_tcard_convv  { font-size:13px; overflow:hidden; text-overflow:ellipsis; }
/* The count and the next page, under the last row of cards. */
.scr_cardsfoot                  { display:flex; align-items:center; gap:12px;
                                  padding:4px 2px 14px; }
.scr_cardscount                 { font-size:11.5px; color:#8a929b; }
body.appbuilder-dark .scr_cardscount { color:#8b919b; }

/* ---- THE LOGO IS A LOGO ----
   On a card it sat inline beside the ticker, which capped it at the height of
   one line of text — 20px, too small to recognise a company by. It now spans
   the ticker AND the name, the shape the dossier header already uses, which
   gives it two lines to fill. The GRID keeps the small one: a 34px row has no
   room for anything else. */
.co_card_id      { display:flex; align-items:center; gap:10px; }
.co_card_idtxt   { min-width:0; flex:1 1 auto; }
.co_cardicon     { width:44px; height:44px; flex:0 0 auto; }
.co_cardicon .screener_icon_img,
.co_cardicon .screener_icon_mono { width:44px; height:44px; font-size:17px; }
.co_cardicon .screener_icon_img  { padding:3px; }
.co_card_id .co_card_head        { margin-bottom:1px; }
/* And the dossier's own header logo, bigger for the same reason. */
.co_hdicon       { width:58px; height:58px; }
.co_hdicon .screener_icon_img,
.co_hdicon .screener_icon_mono   { width:58px; height:58px; font-size:22px; }

/* ---------------------------------------------------------------------------
   Night Desk (Ship 1): the launcher dialog and the queue board. Reuses the
   research Background-tasks vocabulary (co_fillbody, co_passbtn, rs_chip,
   co_pass_*) and adds only what the desk shows that a pass does not.
   Light rules here, dark ones right below, same edit. Font: the dialog sits
   in .tradingcfg and the board in .co_fillbody, both font-bearing roots.
   --------------------------------------------------------------------------- */
.nd_dlg          { font-family:OpenSans, sans-serif; }
.nd_intro        { font-size:12px; line-height:1.45; color:#4b5563; background:#f3f5f9; border-radius:6px; padding:9px 11px; margin-bottom:12px; }
.nd_scriptname   { font-weight:600; color:#1c53b8; padding:2px 0 4px; }
.nd_tpls         { display:flex; flex-wrap:wrap; gap:6px; padding:2px 0 4px; }
.nd_tplchip      { font-size:11.5px; }
.nd_row          { display:flex; gap:14px; }
.nd_row > .cfg-field { flex:1 1 0; min-width:0; }
.nd_cost         { font-size:11.5px; color:#4b5563; border-top:1px solid #e3e7ee; padding-top:9px; margin-top:6px; line-height:1.45; }
.nd_boardhead    { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.nd_boardhint    { font-size:11.5px; color:#6b7280; margin-bottom:10px; }
.nd_table        { width:100%; border-collapse:collapse; font-size:12px; }
.nd_table th     { text-align:left; font-weight:600; color:#6b7280; font-size:11px; padding:4px 8px; border-bottom:1px solid #e3e7ee; }
.nd_table td     { vertical-align:top; padding:8px 8px; border-bottom:1px solid #eef0f4; }
.nd_idea b       { font-weight:600; }
.nd_meta         { margin-top:4px; display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.nd_muted        { color:#6b7280; font-size:11px; }
.nd_summary      { margin-top:4px; font-size:11.5px; line-height:1.4; max-width:360px; }
.nd_outcome      { min-width:220px; }
.nd_log          { font:11px/1.4 Consolas, Menlo, monospace; white-space:pre-wrap; margin:6px 0 0; max-height:260px; overflow:auto; background:#f6f7f9; border-radius:4px; padding:6px 8px; }
.nd_script       { cursor:pointer; }
.nd_empty        { position:relative; min-height:120px; }
.nd_empty i      { font-size:22px; color:#8a94a6; display:block; margin-bottom:6px; }

body.appbuilder-dark .nd_intro      { color:#c3c9d4; background:rgba(255,255,255,.05); }
body.appbuilder-dark .nd_scriptname { color:#7fa9ee; }
body.appbuilder-dark .nd_cost       { color:#c3c9d4; border-top-color:rgba(255,255,255,.12); }
body.appbuilder-dark .nd_boardhint,
body.appbuilder-dark .nd_muted      { color:#98a2b3; }
body.appbuilder-dark .nd_table th   { color:#98a2b3; border-bottom-color:rgba(255,255,255,.12); }
body.appbuilder-dark .nd_table td   { border-bottom-color:rgba(255,255,255,.08); }
body.appbuilder-dark .nd_log        { background:rgba(255,255,255,.05); color:#d5dae1; }
body.appbuilder-dark .nd_empty i    { color:#8a94a6; }

/* ---------------------------------------------------------------------------
   Night Desk (Ship 2): the Lab screen. Sits on the pl_* vocabulary (panel,
   head, kpis, cards, notes) and adds the brief, the scorecard bars, the
   template cards and the standing-order form. Light, then dark, same edit.
   --------------------------------------------------------------------------- */
.nd_panel        { font-family:OpenSans, sans-serif; }
.nd_views        { margin-bottom:12px; }
.nd_nightsel     { display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.nd_nightsel label { font-size:11px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.nd_brief        { margin:6px 0 0; padding-left:0; list-style:none; counter-reset:nd; }
.nd_brief li     { display:flex; align-items:flex-start; gap:10px; padding:8px 0; border-bottom:1px solid #eef0f4; font-size:12.5px; line-height:1.45; }
.nd_brief li:last-child { border-bottom:0; }
.nd_verdict      { flex:0 0 auto; min-width:86px; text-align:center; }
.nd_brieftext    { flex:1 1 auto; }
.nd_brieflinks   { flex:0 0 auto; display:flex; gap:10px; white-space:nowrap; }
.nd_brieflinks .gridurl { cursor:pointer; }
.nd_score        { display:grid; grid-template-columns:260px 1fr 90px; align-items:center; gap:12px; padding:6px 0; font-size:12px; }
.nd_score_l      { color:#41506b; }
.nd_score_bar    { height:8px; background:#eceff4; border-radius:4px; overflow:hidden; }
.nd_score_fill   { height:100%; background:#1c53b8; border-radius:4px; }
.nd_score_v      { text-align:right; font-variant-numeric:tabular-nums; color:#27251E; }
.nd_foot         { font-size:11.5px; color:#6b7280; text-align:center; padding:10px 0 20px; }
.nd_tplgrid      { display:grid; grid-template-columns:repeat(auto-fill, minmax(280px, 1fr)); gap:12px; margin-top:8px; }
.nd_tplcard      { border:1px solid #e3e6ec; border-radius:8px; padding:10px 12px; background:#fafbfc; display:flex; flex-direction:column; gap:6px; }
.nd_tplname      { font-weight:600; font-size:13px; }
.nd_tplwhy       { font-size:11.5px; color:#4b5563; line-height:1.4; flex:1 1 auto; }
.nd_tplmeta      { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.nd_tplact       { margin-top:8px; }
.nd_profrow      { padding:6px 0; border-bottom:1px solid #eef0f4; font-size:12px; }
.nd_profrow:last-child { border-bottom:0; }
.nd_standing .cfg-field { margin-bottom:10px; }
.nd_logidea      { margin-bottom:6px; font-size:13px; }

body.appbuilder-dark .nd_nightsel label { color:#98a2b3; }
body.appbuilder-dark .nd_brief li   { border-bottom-color:rgba(255,255,255,.08); }
body.appbuilder-dark .nd_score_l    { color:#c3c9d4; }
body.appbuilder-dark .nd_score_bar  { background:rgba(255,255,255,.08); }
body.appbuilder-dark .nd_score_fill { background:#7fa9ee; }
body.appbuilder-dark .nd_score_v    { color:#e6e9ef; }
body.appbuilder-dark .nd_foot       { color:#98a2b3; }
body.appbuilder-dark .nd_tplcard    { border-color:rgba(255,255,255,.12); background:rgba(255,255,255,.04); }
body.appbuilder-dark .nd_tplwhy     { color:#c3c9d4; }
body.appbuilder-dark .nd_profrow    { border-bottom-color:rgba(255,255,255,.08); }

/* Night Desk (Ship 3): the sweep matrix inside a campaign row. */
.nd_mx           { margin-top:6px; font-size:11.5px; }
.nd_mx > summary { cursor:pointer; color:#1c53b8; }
.nd_mxt          { border-collapse:collapse; margin:4px 0; }
.nd_mxt td       { padding:2px 8px 2px 0; border-bottom:1px solid #eef0f4; font-size:11.5px; vertical-align:middle; }
.nd_mx_k         { color:#8a90a0; text-transform:uppercase; font-size:10px; letter-spacing:.3px; }
.nd_mx_v         { font-variant-numeric:tabular-nums; white-space:nowrap; }
.nd_mx_g i.fa-check { color:#116b3a; }
.nd_mx_g i.fa-times { color:#b3261e; }
.nd_mxt tr.is-rec td { background:#e6f4ec; }
body.appbuilder-dark .nd_mx > summary { color:#7fa9ee; }
body.appbuilder-dark .nd_mxt td       { border-bottom-color:rgba(255,255,255,.08); }
body.appbuilder-dark .nd_mxt tr.is-rec td { background:rgba(17,107,58,.25); }
body.appbuilder-dark .nd_mx_g i.fa-check { color:#5fd38d; }
body.appbuilder-dark .nd_mx_g i.fa-times { color:#ff6b6b; }

/* Night Desk (Ships 4+5): the harvest section and the claim line. */
.nd_harvest      { display:flex; gap:6px; align-items:center; }
.nd_harvest input{ flex:1 1 auto; margin-bottom:0; }
.nd_harvest .w2ui-btn { flex:0 0 auto; margin:0; }
.nd_claims       { max-height:180px; overflow:auto; margin:4px 0; }
.nd_claims .co_bgrow { align-items:flex-start; }
.nd_claims .co_bgname { white-space:normal; }
.nd_src          { color:#1c53b8; margin-left:4px; }
.nd_claim        { margin-top:4px; font-size:11.5px; color:#4b5563; }
body.appbuilder-dark .nd_src   { color:#7fa9ee; }
body.appbuilder-dark .nd_claim { color:#c3c9d4; }

/* Scripts card standing: out-of-sample expectancy + Night Desk outcome (2026-09-20). */
.ts_exp { font-weight:700; padding:1px 6px; border-radius:9px; cursor:help; background:#eef0f2; color:#6b7280; white-space:nowrap; }
.ts_exp.is-ok  { background:#e3f4ee; color:#0b7d5e; }
.ts_exp.is-bad { background:#fbe6e4; color:#8f1d17; }
.ts_exp_n { font-weight:400; opacity:.75; }
.ts_standing .ts_desk { font-size:10px; cursor:help; }
body.appbuilder-dark .ts_exp        { background:#33373b; color:#aab2bb; }
body.appbuilder-dark .ts_exp.is-ok  { background:#173a30; color:#5ed3a8; }
body.appbuilder-dark .ts_exp.is-bad { background:#3a1e1c; color:#f0857c; }

/* Backtests tab: run order, desk verdict, tested version (2026-09-20). */
.ts_bt_idx { color: var(--fg-muted, #808080); font-variant-numeric: tabular-nums; min-width: 26px; cursor: help; }
.ts_bt_verdict { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 1px 6px; border-radius: 9px; cursor: help; background: #eef0f2; color: #6b7280; white-space: nowrap; }
.ts_bt_verdict.is-ok   { background: #e3f4ee; color: #0b7d5e; }
.ts_bt_verdict.is-warn { background: #fdf1dc; color: #a8620a; }
.ts_bt_verdict.is-bad  { background: #fbe6e4; color: #8f1d17; }
.ts_bt_ver { font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 9px; background: #eef0f2; color: #6b7280; cursor: help; }
body.appbuilder-dark .ts_bt_verdict         { background: #33373b; color: #aab2bb; }
body.appbuilder-dark .ts_bt_verdict.is-ok   { background: #173a30; color: #5ed3a8; }
body.appbuilder-dark .ts_bt_verdict.is-warn { background: #3a2f17; color: #e0a34a; }
body.appbuilder-dark .ts_bt_verdict.is-bad  { background: #3a1e1c; color: #f0857c; }
body.appbuilder-dark .ts_bt_ver             { background: #33373b; color: #aab2bb; }

/* Backtests tab: which run is on the card, and which rows tested the current code (2026-09-20). */
.ts_bt_row.is-card { background: rgba(10,102,194,.06); }
.ts_bt_card { font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 9px; background: #e3edf8; color: #0a4f9c; cursor: help; white-space: nowrap; }
.ts_bt_code { font-size: 10px; padding: 1px 6px; border-radius: 9px; background: #eef0f2; color: #9aa0a8; cursor: help; white-space: nowrap; }
.ts_bt_code.is-cur { background: #e3f4ee; color: #0b7d5e; }
.ts_stale { font-size: 10px; padding: 1px 6px; border-radius: 9px; background: #fdf1dc; color: #a8620a; cursor: help; white-space: nowrap; margin-left: 4px; }
body.appbuilder-dark .ts_bt_row.is-card { background: rgba(93,160,230,.10); }
body.appbuilder-dark .ts_bt_card        { background: #1c3350; color: #8fc1f2; }
body.appbuilder-dark .ts_bt_code        { background: #33373b; color: #7d848c; }
body.appbuilder-dark .ts_bt_code.is-cur { background: #173a30; color: #5ed3a8; }
body.appbuilder-dark .ts_stale          { background: #3a2f17; color: #e0a34a; }

/* Versions tab: diff viewer, counters, legend (2026-09-21). */
.ts_ver_legend { display:flex; flex-wrap:wrap; gap:6px 18px; font-size:11px; color:#6b7280; padding:6px 0 10px; border-bottom:1px solid #eceff4; margin-bottom:4px; }
.ts_ver_legend b { color:#374151; }
.ts_rail { display:inline-block; width:3px; height:12px; vertical-align:middle; margin-right:4px; border-radius:1px; }
.ts_rail.is-ok  { background:#0f9d76; }
.ts_rail.is-bad { background:#b3261e; }
.ts_diffcount { font-family:Consolas, Menlo, monospace; font-size:11px; font-weight:700; cursor:help; white-space:nowrap; }
.ts_diffcount .is-add { color:#0f9d76; }
.ts_diffcount .is-del { color:#b3261e; }
.ts_diff_wrap { display:flex; flex-direction:column; height:100%; }
.ts_diff_head { padding:10px 14px; font-size:12px; color:#374151; border-bottom:1px solid #eceff4; }
.ts_diff_desc { color:#6b7280; margin-bottom:6px; }
.ts_diff_body { flex:1 1 auto; overflow:auto; }
.ts_diff { border-collapse:collapse; font-family:Consolas, Menlo, monospace; font-size:12px; line-height:18px; min-width:100%; }
.ts_diff td { padding:0 8px; white-space:pre; vertical-align:top; }
.ts_diff td.n { width:1%; text-align:right; color:#9aa0a8; user-select:none; border-right:1px solid #eceff4; background:#f8f9fb; }
.ts_diff td.m { width:1%; text-align:center; user-select:none; color:#9aa0a8; }
.ts_diff tr.is-add td.c, .ts_diff tr.is-add td.m { background:#e6f7ef; color:#0b5f47; }
.ts_diff tr.is-add td.n { background:#d3efe2; color:#0b5f47; }
.ts_diff tr.is-del td.c, .ts_diff tr.is-del td.m { background:#fdecea; color:#7a1d17; }
.ts_diff tr.is-del td.n { background:#f7d9d6; color:#7a1d17; }
.ts_diff tr.is-hunk td { background:#eef2ff; color:#4c5db0; font-size:11px; }
.ts_diff_empty { padding:16px; color:#6b7280; }
.ts_diff_raw { margin:0; padding:14px; font-family:Consolas, Menlo, monospace; font-size:12px; white-space:pre-wrap; }
body.appbuilder-dark .ts_ver_legend { color:#aab2bb; border-color:#34383d; }
body.appbuilder-dark .ts_ver_legend b { color:#d7dce2; }
body.appbuilder-dark .ts_diff_head { color:#d7dce2; border-color:#34383d; }
body.appbuilder-dark .ts_diff_desc { color:#aab2bb; }
body.appbuilder-dark .ts_diff td.n { color:#7d848c; border-color:#34383d; background:#1f2226; }
body.appbuilder-dark .ts_diff td.m { color:#7d848c; }
body.appbuilder-dark .ts_diff tr.is-add td.c, body.appbuilder-dark .ts_diff tr.is-add td.m { background:#14352a; color:#8fe0bf; }
body.appbuilder-dark .ts_diff tr.is-add td.n { background:#0f2a21; color:#8fe0bf; }
body.appbuilder-dark .ts_diff tr.is-del td.c, body.appbuilder-dark .ts_diff tr.is-del td.m { background:#3a1c1a; color:#f2a09a; }
body.appbuilder-dark .ts_diff tr.is-del td.n { background:#2e1513; color:#f2a09a; }
body.appbuilder-dark .ts_diff tr.is-hunk td { background:#22263a; color:#9fb0ff; }
body.appbuilder-dark .ts_diff_empty { color:#aab2bb; }

/* Versions tab polish (2026-09-21): small action buttons, the counter as the diff button. */
/* The app forces every .w2ui-btn to 32px / 14px with !important (line ~13330), so the small variant must say !important too. */
button.w2ui-btn.ts_btn_sm, .w2ui-btn.ts_btn_sm { font-size:13px !important; height:24px !important; line-height:22px !important; padding:0 9px !important; min-width:0 !important; }
.ts_diffcount.is-btn { cursor:pointer; padding:1px 7px; border-radius:9px; border:1px solid #d9dee5; background:#f8f9fb; }
.ts_diffcount.is-btn:hover { background:#eef2ff; border-color:#b7c3ff; }
.ts_diffcount .is-add { margin-right:5px; }
body.appbuilder-dark .ts_diffcount.is-btn { border-color:#3a3f45; background:#25282c; }
body.appbuilder-dark .ts_diffcount.is-btn:hover { background:#2b3350; border-color:#4a5a99; }
body.appbuilder-dark .ts_amend_ico.is-ok   { color:#5ed3a8; }
body.appbuilder-dark .ts_amend_ico.is-bad  { color:#f0857c; }
body.appbuilder-dark .ts_amend_ico.is-warn { color:#e0a34a; }

/* Night Desk dialog checkboxes reuse label.ms-cfg-inline (the charts dialog pattern). */

/* ---------------------------------------------------------------------------
   Night Desk layout (user, 2026-09-21): the header (title, view strip, hint)
   stays; the body scrolls. Board and Tonight are tabbed inside the body with
   the tab strip and a head row fixed and the content scrolling under them.
   The strip has the panel's own background, no rule, no inset.
   --------------------------------------------------------------------------- */
.nd_panel        { display:flex; flex-direction:column; }
.nd_head         { flex:0 0 auto; padding:18px 20px 0; }
.nd_head .pl_head { margin-bottom:8px; }
.nd_views        { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin:0; padding:0; border:0; background:transparent; }
.nd_viewhint     { font-size:11.5px; color:#737485; line-height:1.5; margin:8px 0 10px; max-width:1100px; }
.nd_body         { flex:1 1 auto; min-height:0; overflow:auto; padding:0 20px 28px; }
.nd_body.is-tabbed { overflow:hidden; display:flex; flex-direction:column; padding-bottom:16px; }
.nd_tabs         { flex:0 0 auto; }
.nd_tabhead      { flex:0 0 auto; padding:10px 0 8px; }
.nd_tabhead .nd_boardhint { margin-bottom:0; }
.nd_tabbody      { flex:1 1 auto; min-height:0; overflow:auto; background:#fff; border:1px solid #e3e6ec; border-radius:8px; padding:0 12px 10px; }
.nd_tabbody > .nd_table thead th,
.nd_tabbody > table thead th { position:sticky; top:0; z-index:1; background:#fff; }
.nd_tabbody > .nd_empty { border:0; }
.nd_tabbody .nd_tonightwrap { padding-top:12px; }
.nd_tabcnt       { font-size:9.5px; padding:1px 6px; line-height:1.4; vertical-align:middle; }
.nd_lanehead     { display:flex; align-items:flex-start; gap:14px; }
.nd_lanehead .nd_boardhint { flex:1 1 auto; }
.nd_lanehead .w2ui-btn { flex:0 0 auto; }
.nd_steps        { margin:0; padding-left:18px; font-size:12px; line-height:1.6; color:#41506b; }
/* The campaign table: the idea no longer takes half the width; time and progress have
   room of their own, and nothing resizes when a row starts running. */
.nd_table        { table-layout:fixed; }
.nd_c_state      { width:84px; }
.nd_c_idea       { width:26%; }
.nd_c_time       { width:120px; }
.nd_c_result     { width:30%; }
.nd_c_act        { width:150px; }
.nd_table .nd_outcome { min-width:0; }
.nd_table .nd_summary { max-width:none; }
.nd_ideatxt      { display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:default; }
.nd_progcell     { font-size:11px; }
.nd_prog_bar     { height:6px; background:#eceff4; border-radius:3px; overflow:hidden; margin:4px 0 5px; }
.nd_prog_fill    { height:100%; background:#1c53b8; border-radius:3px; transition:width .4s; }
.nd_prog_txt     { color:#116b3a; line-height:1.4; word-break:break-word; }
.nd_prog_txt b   { color:#27251E; }
.nd_table .co_pass_act .co_passbtn { margin-bottom:4px; }
/* The log dialog: stage lines as headings with their time, steps indented under them. */
.nd_logdlg .nd_logidea { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.nd_logv         { font:11.5px/1.5 Consolas, Menlo, monospace; background:#f6f7f9; border-radius:6px; padding:8px 12px; max-height:520px; overflow:auto; margin-top:8px; }
.nd_logv_stage   { font-weight:700; color:#1c53b8; margin-top:8px; }
.nd_logv_stage:first-child { margin-top:0; }
.nd_logv_t       { display:inline-block; min-width:48px; color:#8a90a0; font-weight:400; }
.nd_logv_line    { padding-left:48px; color:#41506b; white-space:pre-wrap; }
body.appbuilder-dark .nd_viewhint  { color:#98a2b3; }
body.appbuilder-dark .nd_tabbody   { background:#26282b; border-color:#3f4348; }
body.appbuilder-dark .nd_tabbody > .nd_table thead th,
body.appbuilder-dark .nd_tabbody > table thead th { background:#26282b; }
body.appbuilder-dark .nd_steps     { color:#c3c9d4; }
body.appbuilder-dark .nd_prog_bar  { background:rgba(255,255,255,.1); }
body.appbuilder-dark .nd_prog_txt  { color:#7ddb9a; }
body.appbuilder-dark .nd_prog_txt b { color:#eee; }
body.appbuilder-dark .nd_logv      { background:rgba(255,255,255,.05); }
body.appbuilder-dark .nd_logv_stage { color:#7fa9ee; }
body.appbuilder-dark .nd_logv_line { color:#c3c9d4; }

/* Standing order: the launcher's form vocabulary on the page, three columns. */
.nd_standing         { padding:0; }
.nd_standing .nd_intro { margin-bottom:14px; }
.nd_srow             { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:16px; }
.nd_standing .cfg-field { margin-bottom:12px; min-width:0; }
.nd_standing input[type=number] { max-width:140px; margin-bottom:0; }
.nd_standing textarea { margin-bottom:0; }
.nd_standing label.ms-cfg-inline { margin-top:2px; }
.nd_standing .nd_tplact { margin-top:4px; }

/* Standing order as tabs: the schedule row in the fixed head (with Save / Skip), a lane per tab. */
.nd_srow4            { display:grid; grid-template-columns:minmax(0,1.2fr) 150px minmax(0,1.6fr) auto; gap:16px; align-items:start; }
.nd_schedule         { padding:0; }
.nd_schedule .nd_intro { margin-bottom:12px; }
.nd_schedule .cfg-field { margin-bottom:0; }
.nd_schedule_act     { padding-top:18px; white-space:nowrap; }
.nd_lane             { padding:12px 0 4px; }
.nd_lane .nd_boardhint { margin-bottom:12px; }

/* ---- AIOS: Autonomy screens ----------------------------------------------
   Command Center, Radar, Decisions, Governance, Operations (Ship 1). Sits on
   the pl_* / nd_* vocabulary (panel, head, kpis, cards, tables, tab strip)
   and adds the state strip, the NOW line, the alert rows, the governor's
   buttons and the chip colours the five screens share. Light, then dark.
   --------------------------------------------------------------------------- */
.au_panel        { font-family:OpenSans, sans-serif; }
.au_rows         { display:flex; flex-direction:column; gap:0; }
.au_busy         { padding:24px 0; color:#737485; font-size:12px; }

/* Chips: one palette, four tones. */
.au_chip         { text-transform:uppercase; font-size:10px; letter-spacing:.3px; }
.au_chip.is-green { background:#e6f4ec; color:#116b3a; }
.au_chip.is-amber { background:#fdf3e3; color:#9a6a10; }
.au_chip.is-red   { background:#fbeaea; color:#b3261e; }
.au_chip.is-blue  { background:#eaf1fd; color:#1c53b8; }
.au_chip.is-grey  { background:#eceff4; color:#6b7280; }
.au_chip.au_bold  { font-weight:700; border:1px solid #eaa9a2; }
.au_ok           { color:#116b3a; font-weight:600; }
.au_warn         { color:#9a6a10; font-weight:600; }
.au_bad          { color:#b3261e; font-weight:600; }
.au_missing      { color:#b3261e; font-style:italic; }

/* Row 1: the state strip. */
.au_strip        { display:flex; align-items:center; gap:14px; flex-wrap:wrap; background:#fff; border:1px solid #e3e6ec; border-radius:8px; padding:10px 14px; margin-bottom:14px; }
.au_badge        { font-size:18px; font-weight:800; letter-spacing:1px; padding:8px 16px; border-radius:6px; white-space:nowrap; }
.au_badge.is-grey  { background:#e3e9f3; color:#3b4a66; }
.au_badge.is-green { background:#d5efe0; color:#0d5a30; }
.au_badge.is-amber { background:#fbe9c6; color:#7a5208; }
.au_badge.is-red   { background:#b3261e; color:#fff; }
.au_fileflag     { font-weight:700; border:1px solid #eaa9a2; }
.au_cell         { display:flex; flex-direction:column; gap:2px; min-width:90px; }
.au_cell_l       { font-size:10px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_cell_v       { font-size:12.5px; color:#27251E; white-space:nowrap; }
.au_armed        { color:#b3261e; font-weight:700; letter-spacing:.3px; }

/* Row 2: the money KPIs. */
.au_kpis .pl_kpi { flex:1 1 130px; }
.au_kpis .pl_kpi_v { font-size:17px; }
.au_of           { font-size:12px; font-weight:400; color:#9aa0ab; }

/* Row 3: NOW. */
.au_now          { display:flex; align-items:center; flex-wrap:wrap; gap:6px; font-size:12px; color:#41506b; padding:6px 2px 14px; }
.au_now_l        { font-size:10.5px; font-weight:700; letter-spacing:.5px; color:#8a90a0; margin-right:6px; }
.au_now_i        { white-space:nowrap; }
.au_now_i b      { font-variant-numeric:tabular-nums; }
.au_now_i:not(.on) { color:#9aa0ab; }
.au_dot          { color:#c3c9d4; }

/* Row 4: alerts. */
.au_alerts       { display:flex; flex-direction:column; }
.au_alert        { display:flex; align-items:baseline; gap:10px; padding:6px 0; border-bottom:1px solid #eef0f4; font-size:12px; }
.au_alert:last-child { border-bottom:0; }
.au_alert_t      { font-weight:600; white-space:nowrap; }
.au_alert_d      { flex:1 1 auto; color:#4b5563; }
.au_alert_p      { white-space:nowrap; }
.au_alert_at     { white-space:nowrap; color:#9aa0ab; font-size:11px; }
.au_headlink     { margin-left:auto; font-size:11px; font-weight:400; cursor:pointer; }

/* Row 6: the switches. */
.au_buttons      { margin-bottom:20px; }
.au_btnrow       { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.au_btn_l        { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_btn_gap      { flex:1 1 auto; }
.au_modepick.is-off .wf-pickbtn { opacity:.5; cursor:not-allowed; }
.au_kill         { font-weight:600; }
.au_note         { margin-top:10px; }
.au_confirmhint  { color:#737485; font-size:11.5px; }

/* Tables: the nd_table with a few column tones. */
.au_table        { table-layout:auto; }
.au_table td     { vertical-align:middle; }
.au_table tr.is-active td { background:#f3f8f5; }
.au_table tr.is-off td    { color:#9aa0ab; }
.au_num          { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.au_nowrap       { white-space:nowrap; }
.au_wrap         { word-break:break-word; max-width:420px; }
.au_mono         { font-family:Consolas, Menlo, monospace; font-size:11px; }
.au_from         { color:#b3261e; }
.au_to           { color:#116b3a; }
.au_more         { cursor:pointer; font-weight:700; letter-spacing:1px; }
.au_payload      { margin:6px 0 0; font-family:Consolas, Menlo, monospace; font-size:10.5px; white-space:pre-wrap; background:#f4f6f9; border-radius:5px; padding:6px 8px; max-height:280px; overflow:auto; }
.au_more_row     { padding:10px 0 4px; display:flex; align-items:center; gap:10px; }
.au_side         { font-weight:700; font-size:11px; letter-spacing:.3px; }
.au_side.is-buy  { color:#116b3a; }
.au_side.is-sell { color:#b3261e; }
.au_code         { display:inline-block; font-family:Consolas, Menlo, monospace; font-size:10px; background:#eceff4; color:#41506b; border-radius:3px; padding:1px 5px; margin:1px 0; }
.au_json         { margin:0; font-family:Consolas, Menlo, monospace; font-size:11.5px; white-space:pre-wrap; word-break:break-word; }
.au_jsonedit     { font-family:Consolas, Menlo, monospace; font-size:11.5px; width:100%; box-sizing:border-box; }

/* Tab bars, filters, placeholders. */
.au_tabbar       { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.au_tabbar label { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_tabbar .nd_boardhint { flex:1 1 100%; margin:4px 0 0; }
.au_filters      { display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding:2px 0 10px; }
.au_filters label { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_filter       { width:140px; }
.au_verify       { font-size:12px; }
.au_blockers     { display:inline-flex; gap:4px; flex-wrap:wrap; }
.au_placeholder  { text-align:center; padding:36px 20px; color:#6b7280; }
.au_placeholder i { font-size:28px; color:#8a94a6; display:block; margin-bottom:10px; }
.au_placeholder p { margin:0; font-size:13px; }
.au_dec .pl_card_h { margin-bottom:4px; }
.au_dlg .cfg-field { margin-bottom:10px; }

body.appbuilder-dark .au_busy        { color:#98a2b3; }
body.appbuilder-dark .au_chip.is-green { background:#22392c; color:#7ddb9a; }
body.appbuilder-dark .au_chip.is-amber { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .au_chip.is-red   { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .au_chip.is-blue  { background:#22304a; color:#8fb6f0; }
body.appbuilder-dark .au_chip.is-grey  { background:#2c2f33; color:#aab2bb; }
body.appbuilder-dark .au_chip.au_bold  { border-color:#6b2f2f; }
body.appbuilder-dark .au_ok          { color:#7ddb9a; }
body.appbuilder-dark .au_warn        { color:#e0b871; }
body.appbuilder-dark .au_bad         { color:#ff9b8f; }
body.appbuilder-dark .au_missing     { color:#ff9b8f; }
body.appbuilder-dark .au_strip       { background:#1f2226; border-color:rgba(255,255,255,.12); }
body.appbuilder-dark .au_badge.is-grey  { background:#2a3140; color:#a8bdd4; }
body.appbuilder-dark .au_badge.is-green { background:#1d3a29; color:#7ddb9a; }
body.appbuilder-dark .au_badge.is-amber { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .au_badge.is-red   { background:#b03030; color:#ffe3e0; }
body.appbuilder-dark .au_fileflag    { border-color:#6b2f2f; }
body.appbuilder-dark .au_cell_l      { color:#98a2b3; }
body.appbuilder-dark .au_cell_v      { color:#e6e9ef; }
body.appbuilder-dark .au_armed       { color:#ff9b8f; }
body.appbuilder-dark .au_of          { color:#98a2b3; }
body.appbuilder-dark .au_now         { color:#c3c9d4; }
body.appbuilder-dark .au_now_l       { color:#98a2b3; }
body.appbuilder-dark .au_now_i:not(.on) { color:#6f7784; }
body.appbuilder-dark .au_dot         { color:#4a4f57; }
body.appbuilder-dark .au_alert       { border-bottom-color:rgba(255,255,255,.08); }
body.appbuilder-dark .au_alert_d     { color:#c3c9d4; }
body.appbuilder-dark .au_alert_at    { color:#98a2b3; }
body.appbuilder-dark .au_btn_l       { color:#98a2b3; }
body.appbuilder-dark .au_confirmhint { color:#98a2b3; }
body.appbuilder-dark .au_table tr.is-active td { background:rgba(125,219,154,.08); }
body.appbuilder-dark .au_table tr.is-off td    { color:#6f7784; }
body.appbuilder-dark .au_from        { color:#ff9b8f; }
body.appbuilder-dark .au_to          { color:#7ddb9a; }
body.appbuilder-dark .au_payload     { background:rgba(255,255,255,.06); }
body.appbuilder-dark .au_side.is-buy  { color:#7ddb9a; }
body.appbuilder-dark .au_side.is-sell { color:#ff9b8f; }
body.appbuilder-dark .au_code        { background:#2c2f33; color:#c3c9d4; }
body.appbuilder-dark .au_tabbar label,
body.appbuilder-dark .au_filters label { color:#98a2b3; }
body.appbuilder-dark .au_placeholder { color:#98a2b3; }
body.appbuilder-dark .au_placeholder i { color:#6f7784; }

/* Live Radar (Ship 2): the header strip (market chip, last scan, research
   count, filters), the ranked table with its five-segment score bar, the
   expandable "Why" row, the collapsed playbooks card. Light, then dark. */
.au_radar        { display:flex; flex-direction:column; }
.au_rd_head      { margin-bottom:6px; }
.au_rd_strip     { display:flex; align-items:center; gap:12px; flex-wrap:wrap; font-size:12px; color:#41506b; padding:2px 0 8px; }
.au_rd_scan      { white-space:nowrap; }
.au_rd_scan i    { color:#8a90a0; margin-right:3px; }
.au_rd_research b { font-variant-numeric:tabular-nums; }
.au_rd_note      { flex:1 1 100%; }
.au_rd_date      { width:140px; color-scheme:light; }
.au_rd_scanbtn   { min-width:104px; }
.au_rd_table th  { white-space:nowrap; }
.au_rd_rank      { white-space:nowrap; }
.au_rd_pos       { display:inline-block; min-width:18px; font-size:10.5px; color:#9aa0ab; font-variant-numeric:tabular-nums; }
.au_rd_score     { font-size:15px; font-weight:800; font-variant-numeric:tabular-nums; margin-right:6px; }
.au_bar5         { display:inline-flex; gap:2px; vertical-align:middle; }
.au_bar5 i       { display:inline-block; width:7px; height:9px; border-radius:2px; background:#e3e6ec; }
.au_bar5 i.on    { background:#9aa0ab; }
.au_bar5.is-high i.on { background:#116b3a; }
.au_bar5.is-mid i.on  { background:#c98a12; }
.au_bar5.is-low i.on  { background:#b3261e; }
.au_rd_sub       { font-size:10.5px; color:#8a90a0; white-space:nowrap; }
.au_rd_ret       { font-weight:700; font-variant-numeric:tabular-nums; }
.au_dir          { font-size:11px; }
.au_dir.is-up    { color:#00a152; }
.au_dir.is-down  { color:#d32f2f; }
.au_rd_event     { text-transform:none; letter-spacing:0; }
.au_rd_downs     { display:flex; flex-wrap:wrap; gap:3px; justify-content:flex-end; margin-top:3px; }
.au_rd_down      { display:inline-block; font-size:9.5px; background:#fbeaea; color:#b3261e; border-radius:3px; padding:1px 5px; white-space:nowrap; }
.au_rd_whybtn.is-on { background:#e3e9f3; }
.au_rd_why > td  { background:#f7f8fa; padding:8px 12px 10px; }
.au_rd_whybox    { display:flex; gap:28px; flex-wrap:wrap; }
.au_rd_col       { min-width:200px; }
.au_rd_col_wide  { flex:1 1 260px; }
.au_rd_colh      { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; margin:4px 0 4px; }
.au_rd_kv        { display:flex; justify-content:space-between; gap:12px; font-size:11.5px; padding:1px 0; }
.au_rd_kv b      { font-variant-numeric:tabular-nums; }
.au_rd_news      { margin:4px 0 6px; padding-left:16px; font-size:11.5px; }
.au_rd_newstext  { font-size:11.5px; margin:4px 0 6px; }
.au_rd_stamp     { margin-top:6px; }
.au_rd_pbcard    { margin-top:14px; }
.au_rd_pbh       { cursor:pointer; user-select:none; }
.au_rd_pbh i     { width:10px; color:#8a90a0; }
.au_rd_pbact     { display:flex; align-items:center; gap:6px; }

body.appbuilder-dark .au_rd_strip   { color:#c3c9d4; }
body.appbuilder-dark .au_rd_scan i  { color:#98a2b3; }
body.appbuilder-dark .au_rd_date    { color-scheme:dark; }
body.appbuilder-dark .au_rd_pos     { color:#6f7784; }
body.appbuilder-dark .au_bar5 i     { background:#2c2f33; }
body.appbuilder-dark .au_bar5 i.on  { background:#6f7784; }
body.appbuilder-dark .au_bar5.is-high i.on { background:#7ddb9a; }
body.appbuilder-dark .au_bar5.is-mid i.on  { background:#e0b871; }
body.appbuilder-dark .au_bar5.is-low i.on  { background:#ff9b8f; }
body.appbuilder-dark .au_rd_sub     { color:#98a2b3; }
body.appbuilder-dark .au_dir.is-up  { color:#7ddb9a; }
body.appbuilder-dark .au_dir.is-down { color:#ff9b8f; }
body.appbuilder-dark .au_rd_down    { background:#3a2626; color:#ef9a9a; }
body.appbuilder-dark .au_rd_whybtn.is-on { background:#2a3140; }
body.appbuilder-dark .au_rd_why > td { background:rgba(255,255,255,.04); }
body.appbuilder-dark .au_rd_colh    { color:#98a2b3; }
body.appbuilder-dark .au_rd_pbh i   { color:#98a2b3; }

/* Decision Stream (Ship 3): the head bar (today's counters, since / symbol,
   the three buttons), the stream table with its drill-down row, the proposal
   card (header, thesis + plan grid, verdict blocks, gate, lineage), the
   outcomes table, the briefs. Light, then dark. */
.au_chip.is-purple { background:#efe7fb; color:#5b2ca8; }
.au_ds_bar       { padding:2px 0 8px; }
.au_ds_today     { font-size:12px; color:#41506b; white-space:nowrap; }
.au_ds_today b   { font-variant-numeric:tabular-nums; }
.au_ds_date      { width:140px; color-scheme:light; }
.au_ds_note      { flex:1 1 100%; }
.au_ds_busy      { font-size:12px; color:#9a6a10; }
.au_ds_count     { font-size:11.5px; color:#8a90a0; }
.au_ds_sum       { font-size:12px; color:#41506b; font-weight:600; }
.au_ds_stream th { white-space:nowrap; }
.au_ds_decision  { font-weight:600; }
.au_ds_sym       { margin-left:4px; }
.au_ds_kind      { font-family:Consolas, Menlo, monospace; font-size:10px; margin-top:2px; }
.au_ds_codes     { display:inline-flex; flex-wrap:wrap; gap:3px; }
.au_ds_why       { font-size:11.5px; margin-top:2px; }
.au_ds_row.is-open td { background:#f7f8fa; border-bottom-color:transparent; }
.au_ds_openbtn.is-on { background:#e3e9f3; }
.au_ds_drill > td { background:#f7f8fa; padding:4px 12px 12px; }
.au_ds_drill .au_ds_card { margin:6px 0 10px; }
.au_ds_payload .au_payload { max-height:360px; }
.au_ds_cards     { padding-top:12px; }
.au_ds_card      { padding:12px 14px 10px; }
.au_ds_ch        { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:10px; }
.au_ds_symbol    { font-size:15px; font-weight:800; }
.au_ds_h         { font-size:12px; color:#41506b; font-variant-numeric:tabular-nums; }
.au_ds_when      { font-size:11px; white-space:nowrap; }
.au_ds_pb        { font-size:11.5px; color:#41506b; white-space:nowrap; }
.au_ds_pb i      { color:#8a90a0; margin-right:2px; }
.au_ds_grid      { display:flex; gap:24px; flex-wrap:wrap; margin-bottom:10px; }
.au_ds_block     { flex:1 1 320px; min-width:260px; }
.au_ds_claim     { font-size:13px; font-weight:600; line-height:1.4; margin-bottom:6px; }
.au_ds_kv        { display:flex; gap:10px; font-size:11.5px; padding:2px 0; line-height:1.45; }
.au_ds_k         { flex:0 0 110px; font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; padding-top:1px; }
.au_ds_v         { flex:1 1 auto; min-width:0; word-break:break-word; }
.au_ds_kv.is-inval .au_ds_v { color:#b3261e; }
.au_ds_notrade   { margin-top:6px; color:#b3261e; font-weight:600; font-size:12px; }
.au_ds_edge b    { font-variant-numeric:tabular-nums; }
.au_ds_thin      { border-bottom:2px solid #b3261e; }
.au_ds_conf      { display:inline-block; width:80px; height:7px; border-radius:4px; background:#e3e6ec; vertical-align:middle; overflow:hidden; }
.au_ds_conf i    { display:block; height:100%; background:#9aa0ab; }
.au_ds_conf.is-high i { background:#116b3a; }
.au_ds_conf.is-mid i  { background:#c98a12; }
.au_ds_conf.is-low i  { background:#b3261e; }
.au_ds_confv     { font-size:11px; font-variant-numeric:tabular-nums; }
.au_ds_verdict   { border-left:4px solid #c3c9d4; background:#f7f8fa; border-radius:0 6px 6px 0; padding:8px 12px; margin:8px 0; }
.au_ds_verdict.is-vgreen  { border-left-color:#116b3a; }
.au_ds_verdict.is-vamber  { border-left-color:#c98a12; }
.au_ds_verdict.is-vred    { border-left-color:#b3261e; }
.au_ds_verdict.is-vpurple { border-left-color:#5b2ca8; }
.au_ds_verdict.is-hl      { box-shadow:0 0 0 2px #cfd9ea inset; }
.au_ds_verdict.is-none    { padding:6px 12px; }
.au_ds_vh        { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.au_ds_vlabel    { font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.5px; color:#8a90a0; }
.au_ds_vchip     { font-weight:800; }
.au_ds_audits    { display:flex; flex-direction:column; gap:2px; margin:4px 0 8px; }
.au_ds_audit     { font-size:11px; line-height:1.5; }
.au_ds_ag        { display:inline-block; min-width:76px; font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_ds_akv       { display:inline-block; margin-right:10px; white-space:nowrap; }
.au_ds_ak        { color:#6b7280; }
.au_ds_ak::after { content:":"; }
.au_ds_redteam   { font-size:11.5px; }
.au_ds_rt        { font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.5px; color:#b3261e; margin-right:4px; }
.au_ds_stance    { font-weight:600; }
.au_ds_obj       { margin:6px 0; font-size:11.5px; }
.au_ds_obj th, .au_ds_obj td { padding:4px 6px; }
.au_ds_vlineage  { font-family:Consolas, Menlo, monospace; font-size:10px; margin-top:4px; }
.au_ds_gate      { display:flex; align-items:center; gap:6px; flex-wrap:wrap; font-size:12px; padding:6px 0 2px; }
.au_ds_lineage   { font-family:Consolas, Menlo, monospace; font-size:10px; margin-top:6px; padding-top:6px; border-top:1px dashed #e3e6ec; }
.au_ds_lineage i { color:#8a90a0; margin-right:3px; }
.au_ds_outcomes th { white-space:nowrap; }
.au_ds_briefs    { padding-top:12px; }
.au_ds_bh        { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.au_ds_btitle    { font-size:13px; }
.au_ds_brief.is-unread .au_ds_btitle { font-weight:800; }
.au_ds_brief.is-unread { border-left:4px solid #1c53b8; }
.au_ds_bchips    { display:flex; flex-wrap:wrap; gap:3px; margin-bottom:6px; }
.au_ds_bbody     { font-size:12px; line-height:1.55; color:#27251E; }

body.appbuilder-dark .au_chip.is-purple { background:#31264a; color:#c9aef5; }
body.appbuilder-dark .au_ds_today, body.appbuilder-dark .au_ds_sum,
body.appbuilder-dark .au_ds_h, body.appbuilder-dark .au_ds_pb { color:#c3c9d4; }
body.appbuilder-dark .au_ds_date    { color-scheme:dark; }
body.appbuilder-dark .au_ds_busy    { color:#e0b871; }
body.appbuilder-dark .au_ds_count, body.appbuilder-dark .au_ds_k, body.appbuilder-dark .au_ds_vlabel,
body.appbuilder-dark .au_ds_ag, body.appbuilder-dark .au_ds_pb i, body.appbuilder-dark .au_ds_lineage i { color:#98a2b3; }
body.appbuilder-dark .au_ds_row.is-open td, body.appbuilder-dark .au_ds_drill > td { background:rgba(255,255,255,.04); }
body.appbuilder-dark .au_ds_openbtn.is-on { background:#2a3140; }
body.appbuilder-dark .au_ds_kv.is-inval .au_ds_v, body.appbuilder-dark .au_ds_notrade, body.appbuilder-dark .au_ds_rt { color:#ff9b8f; }
body.appbuilder-dark .au_ds_thin    { border-bottom-color:#ff9b8f; }
body.appbuilder-dark .au_ds_conf    { background:#2c2f33; }
body.appbuilder-dark .au_ds_conf i  { background:#6f7784; }
body.appbuilder-dark .au_ds_conf.is-high i { background:#7ddb9a; }
body.appbuilder-dark .au_ds_conf.is-mid i  { background:#e0b871; }
body.appbuilder-dark .au_ds_conf.is-low i  { background:#ff9b8f; }
body.appbuilder-dark .au_ds_verdict { background:rgba(255,255,255,.05); border-left-color:#4a4f57; }
body.appbuilder-dark .au_ds_verdict.is-vgreen  { border-left-color:#7ddb9a; }
body.appbuilder-dark .au_ds_verdict.is-vamber  { border-left-color:#e0b871; }
body.appbuilder-dark .au_ds_verdict.is-vred    { border-left-color:#ff9b8f; }
body.appbuilder-dark .au_ds_verdict.is-vpurple { border-left-color:#c9aef5; }
body.appbuilder-dark .au_ds_verdict.is-hl      { box-shadow:0 0 0 2px #2a3140 inset; }
body.appbuilder-dark .au_ds_ak      { color:#98a2b3; }
body.appbuilder-dark .au_ds_lineage { border-top-color:rgba(255,255,255,.12); }
body.appbuilder-dark .au_ds_brief.is-unread { border-left-color:#8fb6f0; }
body.appbuilder-dark .au_ds_bbody   { color:#e6e9ef; }

/* Exposures & Risk (Ship 4): the first tab of Operations. Sections inside the
   white tab body (a heading with its plain-words hint), the five-line risk
   waterfall with its stacked bar, the limits / events / slippage / drift
   tables, the sleeve cards, the three exposure tables side by side with a
   thin weight bar, and the event-study form and result grid. Light, then dark. */
.au_rk           { display:flex; flex-direction:column; padding-top:10px; }
.au_rk_note      { margin-bottom:10px; }
.au_rk_sec       { padding:4px 0 18px; }
.au_rk_h         { font-size:12.5px; font-weight:700; color:#27251E; margin-bottom:8px; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.au_rk_hint      { font-size:11px; font-weight:400; color:#737485; }
.au_rk_sub       { font-size:10.5px; color:#8a90a0; white-space:nowrap; }
/* 1. the waterfall */
.au_rk_wf        { max-width:640px; }
.au_rk_line      { display:flex; align-items:center; gap:10px; padding:4px 0; font-size:12.5px; border-bottom:1px dotted #eef0f4; }
.au_rk_line.is-budget { font-weight:700; }
.au_rk_line.is-avail  { font-weight:700; border-bottom:0; border-top:1px solid #d9dde5; margin-top:2px; padding-top:7px; }
.au_rk_sw        { flex:0 0 10px; width:10px; height:10px; border-radius:2px; background:#c3c9d4; }
.au_rk_line.is-budget   .au_rk_sw { background:#41506b; }
.au_rk_line.is-realised .au_rk_sw, .au_rk_seg.is-realised { background:#b3261e; }
.au_rk_line.is-stress   .au_rk_sw, .au_rk_seg.is-stress   { background:#c98a12; }
.au_rk_line.is-reserved .au_rk_sw, .au_rk_seg.is-reserved { background:#7a8aa8; }
.au_rk_line.is-avail    .au_rk_sw, .au_rk_seg.is-avail    { background:#116b3a; }
.au_rk_l         { flex:1 1 auto; }
.au_rk_v         { font-variant-numeric:tabular-nums; white-space:nowrap; }
.au_rk_pct       { flex:0 0 44px; text-align:right; font-size:11px; color:#8a90a0; font-variant-numeric:tabular-nums; }
.au_rk_bar       { display:flex; height:14px; border-radius:7px; overflow:hidden; background:#eceff4; margin-top:10px; }
.au_rk_seg       { display:block; height:100%; min-width:0; }
.au_rk_nobudget  { margin-top:8px; }
/* 2. limits */
.au_rk_limits tr.is-breach td  { background:#fdf1f0; }
.au_rk_limits tr.is-warning td { background:#fdf8ec; }
/* 3. sleeves */
.au_rk_sleeves   { display:flex; gap:12px; flex-wrap:wrap; }
.au_rk_sleeve    { flex:1 1 240px; max-width:360px; margin-bottom:0; background:#f7f8fa; }
.au_rk_sleeve .pl_card_h { display:flex; align-items:center; gap:8px; }
.au_rk_kv        { display:flex; gap:10px; font-size:12px; padding:2px 0; line-height:1.45; }
.au_rk_k         { flex:0 0 84px; font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; padding-top:2px; }
.au_rk_vv        { flex:1 1 auto; min-width:0; word-break:break-word; font-variant-numeric:tabular-nums; }
/* 4. exposures */
.au_rk_exps      { display:flex; gap:18px; flex-wrap:wrap; align-items:flex-start; }
.au_rk_exp       { flex:1 1 260px; min-width:240px; }
.au_rk_exph      { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; margin-bottom:4px; }
.au_rk_exptable td { padding:5px 8px; }
.au_rk_w         { white-space:nowrap; }
.au_rk_wbar      { display:inline-block; width:56px; height:6px; border-radius:3px; background:#e3e6ec; vertical-align:middle; margin-right:6px; overflow:hidden; }
.au_rk_wbar i    { display:block; height:100%; background:#1c53b8; }
.au_rk_wbar.is-neg i { background:#b3261e; }
/* 6. slippage, 7. drift */
.au_rk_slipbad td { background:#fdf1f0; }
.au_rk_drift th, .au_rk_slip th, .au_rk_events th { white-space:nowrap; }
/* 8. event study */
.au_rk_form      { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:10px; }
.au_rk_form label { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_rk_sym       { width:140px; text-transform:uppercase; }
.au_rk_studyres  { background:#f7f8fa; border:1px solid #e3e6ec; border-radius:8px; padding:10px 12px; max-width:900px; }
.au_rk_studyh    { display:flex; align-items:center; gap:6px; flex-wrap:wrap; font-size:13px; font-weight:700; margin-bottom:6px; }
.au_rk_summary   { font-size:12.5px; line-height:1.5; margin-bottom:10px; }
.au_rk_stats     { display:flex; flex-wrap:wrap; gap:8px; }
.au_rk_stat      { flex:1 1 120px; background:#fff; border:1px solid #e3e6ec; border-radius:6px; padding:6px 10px; }
.au_rk_statl     { font-size:10px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; }
.au_rk_statv     { font-size:14px; font-weight:700; color:#27251E; font-variant-numeric:tabular-nums; margin-top:2px; white-space:nowrap; }

body.appbuilder-dark .au_rk_h       { color:#e6e9ef; }
body.appbuilder-dark .au_rk_hint    { color:#98a2b3; }
body.appbuilder-dark .au_rk_sub, body.appbuilder-dark .au_rk_pct,
body.appbuilder-dark .au_rk_k, body.appbuilder-dark .au_rk_exph,
body.appbuilder-dark .au_rk_form label, body.appbuilder-dark .au_rk_statl { color:#98a2b3; }
body.appbuilder-dark .au_rk_line    { border-bottom-color:rgba(255,255,255,.08); }
body.appbuilder-dark .au_rk_line.is-avail { border-top-color:rgba(255,255,255,.18); }
body.appbuilder-dark .au_rk_sw      { background:#4a4f57; }
body.appbuilder-dark .au_rk_line.is-budget   .au_rk_sw { background:#a8bdd4; }
body.appbuilder-dark .au_rk_line.is-realised .au_rk_sw, body.appbuilder-dark .au_rk_seg.is-realised { background:#ff9b8f; }
body.appbuilder-dark .au_rk_line.is-stress   .au_rk_sw, body.appbuilder-dark .au_rk_seg.is-stress   { background:#e0b871; }
body.appbuilder-dark .au_rk_line.is-reserved .au_rk_sw, body.appbuilder-dark .au_rk_seg.is-reserved { background:#8fa3c4; }
body.appbuilder-dark .au_rk_line.is-avail    .au_rk_sw, body.appbuilder-dark .au_rk_seg.is-avail    { background:#7ddb9a; }
body.appbuilder-dark .au_rk_bar     { background:#2c2f33; }
body.appbuilder-dark .au_rk_limits tr.is-breach td, body.appbuilder-dark .au_rk_slipbad td { background:rgba(255,155,143,.10); }
body.appbuilder-dark .au_rk_limits tr.is-warning td { background:rgba(224,184,113,.10); }
body.appbuilder-dark .au_rk_sleeve  { background:#2c2f33; }
body.appbuilder-dark .au_rk_wbar    { background:#2c2f33; }
body.appbuilder-dark .au_rk_wbar i  { background:#8fb6f0; }
body.appbuilder-dark .au_rk_wbar.is-neg i { background:#ff9b8f; }
body.appbuilder-dark .au_rk_sym     { color-scheme:dark; }
body.appbuilder-dark .au_rk_studyres { background:#26282b; border-color:#3f4348; }
body.appbuilder-dark .au_rk_stat    { background:#272a30; border-color:#383c44; }
body.appbuilder-dark .au_rk_statv   { color:#e6e9ef; }

/* Ships 5-6: Governance ▸ Incidents + Calibration, Operations ▸ Knowledge
   (queue + neighbourhood columns), Instruments (tick-source chips), Data &
   broker (four health cards: score ring, quota bar). Light, then dark. */
.au_inc_head     { display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-size:12.5px; color:#27251E; padding:8px 0 12px; }
.au_inc_head i   { color:#b3261e; }
.au_inc_drill    { font-size:11.5px; }
.au_incidents th { white-space:nowrap; }
.au_cal_wrap     { display:flex; flex-direction:column; padding-top:6px; }
.au_cal th, .au_cal_cost th { white-space:nowrap; }
.au_cal_gap      { font-weight:600; }
.au_kn           { display:flex; flex-direction:column; padding-top:6px; }
.au_kn_cols      { display:flex; gap:14px; flex-wrap:wrap; align-items:flex-start; }
.au_kn_col       { flex:1 1 220px; min-width:200px; max-width:340px; background:#f7f8fa; border:1px solid #e3e6ec; border-radius:8px; padding:8px 10px; }
.au_kn_colh      { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:#8a90a0; margin-bottom:6px; display:flex; align-items:center; gap:6px; }
.au_kn_node      { background:#fff; border:1px solid #e3e6ec; border-left:3px solid #c3c9d4; border-radius:6px; padding:6px 8px; margin-bottom:6px; font-size:12px; }
.au_kn_node:last-child { margin-bottom:0; }
.au_kn_node.is-instrument { border-left-color:#1c53b8; }
.au_kn_node.is-company    { border-left-color:#41506b; }
.au_kn_node.is-claim      { border-left-color:#7a4bb8; }
.au_kn_node.is-candidate  { border-left-color:#c98a12; }
.au_kn_node.is-playbook   { border-left-color:#0f766e; }
.au_kn_node.is-proposal   { border-left-color:#9a6a10; }
.au_kn_node.is-verdict    { border-left-color:#116b3a; }
.au_kn_node.is-intent     { border-left-color:#b3261e; }
.au_kn_node.is-outcome    { border-left-color:#6b7280; }
.au_kn_node.is-portfolio  { border-left-color:#2563eb; }
.au_kn_nh        { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.au_kn_score     { margin-left:auto; font-variant-numeric:tabular-nums; font-weight:700; color:#41506b; font-size:11px; }
.au_kn_detail    { color:#4b5563; font-size:11.5px; margin-top:2px; line-height:1.4; word-break:break-word; }
.au_kn_edges     { margin-top:4px; border-top:1px dotted #eef0f4; padding-top:4px; }
.au_kn_edge      { font-size:11px; color:#6b7280; line-height:1.5; }
.au_kn_rel       { font-family:Consolas, Menlo, monospace; font-size:10px; background:#eceff4; color:#41506b; border-radius:3px; padding:0 4px; }
.au_instr th     { white-space:nowrap; }
.au_instr tr.is-halted td { background:#fdf1f0; }
.au_in_trad      { text-align:center; font-weight:700; font-size:13px; }
.au_in_rebuild   { min-width:110px; }
.au_hc_grid      { display:grid; grid-template-columns:repeat(auto-fit, minmax(260px, 1fr)); gap:14px; padding-top:10px; }
.au_hc           { margin-bottom:0; border-top:3px solid #c3c9d4; }
.au_hc.is-ok     { border-top-color:#116b3a; }
.au_hc.is-warn   { border-top-color:#c98a12; }
.au_hc.is-bad    { border-top-color:#b3261e; }
.au_hc_row       { display:flex; align-items:center; gap:14px; }
.au_hc_kvs       { flex:1 1 auto; min-width:0; }
.au_hc_ring      { flex:0 0 68px; width:68px; height:68px; border-radius:50%; position:relative; display:flex; align-items:center; justify-content:center;
                   background:conic-gradient(#8a90a0 calc(var(--au-score, 0) * 1%), #eceff4 0); }
.au_hc_ring.is-ok   { background:conic-gradient(#116b3a calc(var(--au-score, 0) * 1%), #eceff4 0); }
.au_hc_ring.is-warn { background:conic-gradient(#c98a12 calc(var(--au-score, 0) * 1%), #eceff4 0); }
.au_hc_ring.is-bad  { background:conic-gradient(#b3261e calc(var(--au-score, 0) * 1%), #eceff4 0); }
.au_hc_ring::before { content:""; position:absolute; inset:8px; border-radius:50%; background:#fff; }
.au_hc_ring span { position:relative; font-weight:700; font-size:13px; font-variant-numeric:tabular-nums; color:#27251E; }
.au_hc_chip      { margin-bottom:6px; }
.au_hc_chip .au_chip { font-size:12px; padding:4px 10px; }
.au_hc_note      { font-size:12px; color:#4b5563; line-height:1.45; margin:4px 0 6px; }
.au_hc_quota     { font-size:17px; font-weight:700; font-variant-numeric:tabular-nums; color:#27251E; }
.au_hc_bar       { height:10px; border-radius:5px; background:#eceff4; overflow:hidden; margin:6px 0 8px; }
.au_hc_bar i     { display:block; height:100%; background:#1c53b8; }
.au_hc_bar.is-amber i { background:#c98a12; }
.au_hc_bar.is-red i   { background:#b3261e; }
.pf_wiz_deskhint { color:#1c53b8; }

body.appbuilder-dark .au_inc_head   { color:#e6e9ef; }
body.appbuilder-dark .au_inc_head i { color:#ff9b8f; }
body.appbuilder-dark .au_kn_col     { background:#26282b; border-color:#3f4348; }
body.appbuilder-dark .au_kn_colh    { color:#98a2b3; }
body.appbuilder-dark .au_kn_node    { background:#1f2226; border-color:#3f4348; border-left-color:#4a4f57; }
body.appbuilder-dark .au_kn_node.is-instrument { border-left-color:#8fb6f0; }
body.appbuilder-dark .au_kn_node.is-company    { border-left-color:#a8bdd4; }
body.appbuilder-dark .au_kn_node.is-claim      { border-left-color:#c4a5ef; }
body.appbuilder-dark .au_kn_node.is-candidate  { border-left-color:#e0b871; }
body.appbuilder-dark .au_kn_node.is-playbook   { border-left-color:#5eead4; }
body.appbuilder-dark .au_kn_node.is-proposal   { border-left-color:#e0b871; }
body.appbuilder-dark .au_kn_node.is-verdict    { border-left-color:#7ddb9a; }
body.appbuilder-dark .au_kn_node.is-intent     { border-left-color:#ff9b8f; }
body.appbuilder-dark .au_kn_node.is-outcome    { border-left-color:#aab2bb; }
body.appbuilder-dark .au_kn_node.is-portfolio  { border-left-color:#8fb6f0; }
body.appbuilder-dark .au_kn_score   { color:#c3c9d4; }
body.appbuilder-dark .au_kn_detail  { color:#c3c9d4; }
body.appbuilder-dark .au_kn_edges   { border-top-color:rgba(255,255,255,.08); }
body.appbuilder-dark .au_kn_edge    { color:#98a2b3; }
body.appbuilder-dark .au_kn_rel     { background:#2c2f33; color:#c3c9d4; }
body.appbuilder-dark .au_instr tr.is-halted td { background:rgba(255,155,143,.10); }
body.appbuilder-dark .au_hc         { border-top-color:#4a4f57; }
body.appbuilder-dark .au_hc.is-ok   { border-top-color:#7ddb9a; }
body.appbuilder-dark .au_hc.is-warn { border-top-color:#e0b871; }
body.appbuilder-dark .au_hc.is-bad  { border-top-color:#ff9b8f; }
body.appbuilder-dark .au_hc_ring    { background:conic-gradient(#98a2b3 calc(var(--au-score, 0) * 1%), #2c2f33 0); }
body.appbuilder-dark .au_hc_ring.is-ok   { background:conic-gradient(#7ddb9a calc(var(--au-score, 0) * 1%), #2c2f33 0); }
body.appbuilder-dark .au_hc_ring.is-warn { background:conic-gradient(#e0b871 calc(var(--au-score, 0) * 1%), #2c2f33 0); }
body.appbuilder-dark .au_hc_ring.is-bad  { background:conic-gradient(#ff9b8f calc(var(--au-score, 0) * 1%), #2c2f33 0); }
body.appbuilder-dark .au_hc_ring::before { background:#1f2226; }
body.appbuilder-dark .au_hc_ring span { color:#e6e9ef; }
body.appbuilder-dark .au_hc_note    { color:#c3c9d4; }
body.appbuilder-dark .au_hc_quota   { color:#e6e9ef; }
body.appbuilder-dark .au_hc_bar     { background:#2c2f33; }
body.appbuilder-dark .au_hc_bar i   { background:#8fb6f0; }
body.appbuilder-dark .au_hc_bar.is-amber i { background:#e0b871; }
body.appbuilder-dark .au_hc_bar.is-red i   { background:#ff9b8f; }
body.appbuilder-dark .pf_wiz_deskhint { color:#8fb6f0; }

/* AIOS Ship 7: SLA, drills, post-mortems, readiness, behaviour, reallocation */
.au_sla            { font-size:11.5px; color:#4b5563; font-variant-numeric:tabular-nums; }
.au_sla.is-late    { color:#b3261e; font-weight:600; }
.au_table tr.au_overdue td { background:#fdf1f0; }
.au_drilllink      { text-decoration:none; }
.au_drilllink .au_chip { cursor:pointer; }
.au_now_i.is-late  { color:#b3261e; font-weight:600; }
.au_now_pm         { cursor:pointer; }
.au_pm_btn         { font-size:11px; padding:2px 8px; }
.au_pm_row         { cursor:pointer; }
.au_pm_row:hover td { background:#f4f6f9; }
.au_pm_row.is-sel td { background:#eaf1fd; }
.au_pm_detailhost  { margin-top:14px; }
.au_pm_hint        { padding:10px 2px; font-size:12px; }
.au_pm_meta        { display:flex; flex-wrap:wrap; gap:14px; font-size:12px; color:#41506b; margin-bottom:8px; }
.au_pm_text        { width:100%; box-sizing:border-box; font-family:Consolas, Menlo, monospace; font-size:12px; line-height:1.5; resize:vertical; min-height:240px; }
.au_pm_actions     { display:flex; align-items:center; flex-wrap:wrap; gap:8px; margin:8px 0 14px; }
.au_pm_pol         { margin-left:6px; font-size:12px; }
.au_pm_res         { margin:0 0 14px; }
.au_rd             { margin-top:18px; }
.au_rd .au_rk_h .pl_btn { font-weight:400; }
.au_rd_line        { font-size:12px; color:#41506b; margin:0 0 8px; }
.au_rd_line.au_bad { color:#b3261e; }
.au_rd_miss        { display:inline-block; font-size:11px; background:#fdf3e3; color:#9a6a10; border-radius:10px; padding:1px 8px; margin:1px 2px 1px 0; }
.au_rd_miss::before { content:"• "; }
.au_rd_met         { font-size:11px; cursor:help; border-bottom:1px dotted #9aa0ab; }
.au_ra_hint        { font-size:12px; margin:0 0 8px; }
.au_ra_arrow       { color:#8a90a0; text-align:center; padding-left:2px; padding-right:2px; }
.au_ra_from        { color:#6b7280; }
.au_ra_to          { color:#27251E; font-weight:600; }
.au_dr_head        { font-size:12px; color:#41506b; }
.au_table tr.au_dr_fail td { background:#fdf1f0; }

body.appbuilder-dark .au_sla            { color:#c3c9d4; }
body.appbuilder-dark .au_sla.is-late    { color:#ff9b8f; }
body.appbuilder-dark .au_table tr.au_overdue td { background:rgba(255,155,143,.08); }
body.appbuilder-dark .au_now_i.is-late  { color:#ff9b8f; }
body.appbuilder-dark .au_pm_row:hover td { background:rgba(255,255,255,.04); }
body.appbuilder-dark .au_pm_row.is-sel td { background:#22304a; }
body.appbuilder-dark .au_pm_meta        { color:#c3c9d4; }
body.appbuilder-dark .au_pm_text        { background:#1f2226; color:#e6e9ef; border-color:#3f4348; }
body.appbuilder-dark .au_rd_line        { color:#c3c9d4; }
body.appbuilder-dark .au_rd_line.au_bad { color:#ff9b8f; }
body.appbuilder-dark .au_rd_miss        { background:#3a3226; color:#e0b871; }
body.appbuilder-dark .au_rd_met         { border-bottom-color:#6f7784; }
body.appbuilder-dark .au_ra_arrow       { color:#98a2b3; }
body.appbuilder-dark .au_ra_from        { color:#aab2bb; }
body.appbuilder-dark .au_ra_to          { color:#e6e9ef; }
body.appbuilder-dark .au_dr_head        { color:#c3c9d4; }
body.appbuilder-dark .au_table tr.au_dr_fail td { background:rgba(255,155,143,.08); }

/* Autonomy empty states sit IN the flow of their card or tab. `.anylist_empty` is
   absolutely centred (left/top 50% + translate -50%) for full-panel lists;
   `.nd_empty` turns it back to position:relative, and a relative box with
   top:auto still takes translateY(-50%) — so a card with no rows drew its
   "Nothing waiting for a decision." half its height UP, over the card header. */
.au_panel .anylist_empty.nd_empty { position:static; left:auto; top:auto; transform:none;
                                    min-height:0; padding:18px 12px 14px; font-size:13px; line-height:1.4; }
.au_panel .anylist_empty.nd_empty i { font-size:18px; margin-bottom:4px; }

/* An overridable ESCALATE verdict: where a person decides. */
.au_ds_decide     { font-size:11px; font-weight:600; color:#b45309; white-space:nowrap; }
.au_ds_decide i   { margin-right:3px; }
body.appbuilder-dark .au_ds_decide { color:#fbbf24; }
