body{margin:0;}

.page {
	width: 100%;
}
.page > h1 {
	font-weight: 300 !important;
	color: #fff;
	font-size: 34px;
	margin: 0;
}
.circles-container {
	min-height: 400px;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-around;
}
.loader {
	position: relative;
	user-select: none;
	box-sizing: border-box;
	width: 150px;
	height: 150px;
}
.loader-bg {
	width: 100%;
	height: 100%;
	border-radius: 50%;
	box-sizing: border-box;
	border: 5px solid #eeeeee;
	display: flex;
	align-items: center;
	justify-content: center;
}
.spinner-holder-one {
	position: absolute;
	top: 0;
	left: 0;
	overflow: hidden;
	width: 50%;
	height: 50%;
	background: transparent;
	box-sizing: border-box;
}
.spinner-holder-two {
	position: absolute;
	top: 0;
	left: 0;
	overflow: hidden;
	width: 100%;
	height: 100%;
	background: transparent;
	box-sizing: border-box;
}
.loader-spinner {
	width: 200%;
	height: 200%;
	border-radius: 50%;
	border: 5px solid rgb(135, 206, 235);
	box-sizing: border-box;
}
.animate-0-25-a {
	transform: rotate(90deg);
	transform-origin: 100% 100%;
}
.animate-0-25-b {
	transform: rotate(-90deg);
	transform-origin: 100% 100%;
}
.animate-25-50-a {
	transform: rotate(180deg);
	transform-origin: 100% 100%;
}
.animate-25-50-b {
	transform: rotate(-90deg);
	transform-origin: 100% 100%;
}
.animate-50-75-a {
	transform: rotate(270deg);
	transform-origin: 100% 100%;
}
.animate-50-75-b {
	transform: rotate(-90deg);
	transform-origin: 100% 100%;
}
.animate-75-100-a {
	transform: rotate(0deg);
	transform-origin: 100% 100%;
}
.animate-75-100-b {
	transform: rotate(-90deg);
	transform-origin: 100% 100%;
}
.text {
	text-align: center;
	font-size: 20px;
	color: rgb(135, 206, 235);
	font-weight: bold;
}
.blue .loader-bg {
	border-color: rgba(255, 255, 255, 0.1);
	/*box-shadow: inset 2px 2px 20px 0 rgba(0, 0, 0, 0.1) !important;*/
}
.blue .text {
	font-size: 20px;
	color: #3ba8b6 !important;
}
.blue .loader-spinner {
	border-color: #3ba8b6;
}
.blue.circle-loaded-75 .text {
	color: #57a3d8 !important;
}
.blue.circle-loaded-75 .loader-spinner {
	border-color: #57a3d8;
}
.cobalt .loader-bg {
	border-color: #ccc;
	/*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.4) !important;*/
}
.cobalt .text {
	font-size: 20px;
	color: #333 !important;
}
.cobalt .loader-spinner {
	border-color: #333;
}
.fire .loader {
}
.fire .loader-bg {
	border-color: #333;
	/*box-shadow: inset 2px 2px 20px 0 rgba(0, 0, 0, 0.4);*/
}
.fire .text {
	font-size: 20px;
	color: #ee4230 !important;
}
.fire .loader-spinner {
	border-color: #ee4230;
}
.fire.circle-loaded-75 .text {
	color: #c6594e !important;
}
.fire.circle-loaded-75 .loader-spinner {
	border-color: #c6594e;
}
.matte .loader-bg {
	border-color: rgba(255, 255, 255, 0.4);
	/*box-shadow: 2px 2px 20px 0 rgba(0, 0, 0, 0.6);*/
}
.matte .text {
	color: rgba(20, 20, 20) !important;
	font-weight: bold;
}
.matte .loader-spinner {
	border-color: rgba(20, 20, 20);
}
.purple .loader-bg {
	border-color: rgba(255, 255, 255, 0.1);
	/*box-shadow: inset 2px 2px 20px 0 rgba(0, 0, 0, 0.1) !important;*/
}
.purple .text {
	font-size: 20px;
	color: #7b708d !important;
}
.purple .loader-spinner {
	border-color: #7b708d;
}
.purple.circle-loaded-75 .text {
	color: #a186ce !important;
}
.purple.circle-loaded-75 .loader-spinner {
	border-color: #a186ce;
}
.loader-bg {
	border-color: rgba(255, 255, 255, 0.4);
	/*box-shadow: 2px 2px 20px 0 rgba(0, 0, 0, 0.6);*/
}
.text {
	color: rgb(135, 206, 235) !important;
	font-weight: bold;
}
.loader-spinner {
	border-color: rgb(135, 206, 235);
}
.white .loader-bg {
	border-color: rgba(255, 255, 255, 0.1);
	/*box-shadow: inset 2px 2px 20px 0 rgba(0, 0, 0, 0.1) !important;*/
}
.white .text {
	font-size: 20px;
	color: #fff !important;
}
.white .loader-spinner {
	border-color: #fff;
}
.white.circle-loaded-75 .text {
	color: #ddd !important;
}
.white.circle-loaded-75 .loader-spinner {
	border-color: #ddd;
}

}
.page > h1 {
  font-weight: 300 !important;
  color: #fff;
  font-size:34px;
  margin:0;
}
.circles-container {
  min-height: 400px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-around;
}
.loader {
    position: relative;
    user-select: none;
    box-sizing: border-box;
    width: 150px;
    height: 150px;
}
.loader-bg {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    box-sizing: border-box;
    border: 5px solid #eeeeee;
    display: flex;
    align-items: center;
    justify-content: center;
}
.spinner-holder-one {
    position: absolute;
    top:0;
    left:0;
    overflow: hidden;
    width: 50%;
    height: 50%;
    background: transparent;
    box-sizing: border-box;
}
.spinner-holder-two {
    position: absolute;
    top:0;
    left:0;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: transparent;
    box-sizing: border-box;
}
.loader-spinner {
    width: 200%;
    height: 200%;
    border-radius: 50%;
    border: 5px solid rgb(135, 206, 235);
    box-sizing: border-box;
}  
.animate-0-25-a {
    transform: rotate(90deg);
    transform-origin: 100% 100%;
}
.animate-0-25-b {
    transform: rotate(-90deg);
    transform-origin: 100% 100%;
}
.animate-25-50-a {
    transform: rotate(180deg);
    transform-origin: 100% 100%;
}
.animate-25-50-b {
    transform: rotate(-90deg);
    transform-origin: 100% 100%;
}
.animate-50-75-a {
    transform: rotate(270deg);
    transform-origin: 100% 100%;
}
.animate-50-75-b {
    transform: rotate(-90deg);
    transform-origin:100% 100%;
}
.animate-75-100-a {
    transform: rotate(0deg);
    transform-origin: 100% 100%;
}
.animate-75-100-b {
    transform: rotate(-90deg);
    transform-origin: 100% 100%;
}
.text {
    text-align: center;
    font-size: 20px;
    color: rgb(135, 206, 235);
    font-weight: bold;  
}
.blue .loader-bg {
  border-color: rgba(255,255,255,0.1);
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.1) !important;*/
}
.blue .text {
  font-size: 20px;
  color: #3ba8b6 !important;
}
.blue .loader-spinner {
  border-color: #3ba8b6;
}
.blue.circle-loaded-75 .text {
  color: #57a3d8 !important;
}
.blue.circle-loaded-75 .loader-spinner {
  border-color: #57a3d8;
}
.cobalt .loader-bg {
  border-color: #ccc;
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.4) !important;*/
}
.cobalt .text {
  font-size: 20px;
  color: #333 !important;
}
.cobalt .loader-spinner {
  border-color: #333;
}
.fire .loader {
}
.fire .loader-bg {
  border-color: #333;
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.4);*/
}
.fire .text {
  font-size: 20px;
  color: #ee4230 !important;
}
.fire .loader-spinner {
  border-color: #ee4230;
}
.fire.circle-loaded-75 .text {
  color: #c6594e !important;
}
.fire.circle-loaded-75 .loader-spinner {
  border-color: #c6594e;
}
.matte .loader-bg {
  border-color: rgba(255,255,255,0.4);
  /*box-shadow: 2px 2px 20px 0 rgba(0,0,0,0.6);*/
}
.matte .text {
  color: rgba(20, 20, 20) !important;
  font-weight: bold;
}
.matte .loader-spinner {
  border-color: rgba(20, 20, 20);
}
.purple .loader-bg {
  border-color: rgba(255,255,255,0.1);
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.1) !important;*/
}
.purple .text {
  font-size: 20px;
  color: #7b708d !important;
}
.purple .loader-spinner {
  border-color: #7b708d;
}
.purple.circle-loaded-75 .text {
  color: #a186ce !important;
}
.purple.circle-loaded-75 .loader-spinner {
  border-color: #a186ce;
}
.loader-bg {
  border-color: rgba(255,255,255,0.4);
  /*box-shadow: 2px 2px 20px 0 rgba(0,0,0,0.6);*/
}
.text {
  color: rgb(135, 206, 235) !important;
  font-weight: bold;
}
.loader-spinner {
  border-color: rgb(135, 206, 235);
}
.white .loader-bg {
  border-color: rgba(255,255,255,0.1);
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.1) !important;*/
}
.white .text {
  font-size: 20px;
  color: #fff !important;
}
.white .loader-spinner {
  border-color: #fff;
}
.white.circle-loaded-75 .text {
  color: #ddd !important;
}
.white.circle-loaded-75 .loader-spinner {
  border-color: #ddd;
}



.yellow .loader-bg {
	border-color: rgba(255, 255, 255, 0.1);
	/*box-shadow: inset 2px 2px 20px 0 rgba(0, 0, 0, 0.1) !important;*/
}

.yellow .text {
	font-size: 20px;
	color: #d2c315 !important;
}

.yellow .loader-spinner {
	border-color: #d2c315;
}

.yellow.circle-loaded-75 .text {
	color: #ffeb3b !important;
}

.yellow.circle-loaded-75 .loader-spinner {
	border-color: #ffeb3b;
}

.yellow .loader-bg {
  border-color: rgba(255,255,255,0.1);
  /*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.1) !important;*/
}
.yellow .text {
  font-size: 20px;
  color: #d2c315 !important;
}
.yellow .loader-spinner {
  border-color: #d2c315;
}
.yellow.circle-loaded-75 .text {
  color: #ffeb3b !important;
}
.yellow.circle-loaded-75 .loader-spinner {
  border-color: #ffeb3b;
}




.dkgray .loader-bg {
	border-color: rgba(255, 255, 255, 0.1);
}

.dkgray .text {
	font-size: 20px;
	color: #333333 !important;
}

.dkgray .loader-spinner {
	border-color: #333333;
}

.dkgray.circle-loaded-75 .text {
	color: #333333 !important;
}

.dkgray.circle-loaded-75 .loader-spinner {
	border-color: #333333;
}

.dkgray .loader-bg {
	border-color: rgba(255,255,255,0.1);
	/*box-shadow: inset 2px 2px 20px 0 rgba(0,0,0,0.1) !important;*/
}

.dkgray .text {
	font-size: 20px;
	color: #333333 !important;
}

.dkgray .loader-spinner {
	border-color: #333333;
}

.dkgray.circle-loaded-75 .text {
	color: #333333 !important;
}

.dkgray.circle-loaded-75 .loader-spinner {
	border-color: #333333;
}
/* CSS custom properties — default skin values.
   Override these in Content/skins/st-*.css files only. */
:root {
    /* ---- brand / accent ---- */
    --st-accent:            #6366f1;
    --st-accent-hover:      #ebebff;
    --st-accent-text:       #ffffff;

    /* ---- focus ring ---- */
    /* Defaults to --st-accent (matches the convention every component already converged on
       independently - see standardtime-gridengine.css, -toastengine.css, -ribbon.css,
       -propertygridengine.css). Kept as its own variable, not just reused inline, so a skin
       (e.g. a future high-contrast one) can override focus-ring visibility without changing
       what --st-accent does everywhere else (grid header bg, hover bg, toast bg, etc.). */
    --st-focus-ring:        var(--st-accent);

    /* ---- backgrounds ---- */
    --st-bg-body:           whitesmoke;
    --st-bg-ribbon:         whitesmoke;
    --st-bg-toolbar:        #E8E8E8;
    --st-bg-footer:         gray;
    --st-bg-dialog-overlay: rgb(50, 50, 70);
    --st-border-color:      #dee2e6;

    /* ---- text ---- */
    --st-text-body:         #212529;
    --st-text-muted:        color-mix(in srgb, var(--st-text-body) 60%, transparent);
    --st-text-footer:       whitesmoke;
    --st-text-search-sel:   blue;
    --st-text-search-cur:   orange;
    --st-text-autofilter:   #b45f06;

    /* ---- grid / report tables ---- */
    --st-grid-header-bg:   color-mix(in srgb, var(--st-accent) 15%, white);
    --st-grid-header-text: color-mix(in srgb, var(--st-accent) 60%, #000);
    --st-grid-alt-row-bg:  color-mix(in srgb, var(--st-accent)  4%, var(--st-bg-body));
    --st-grid-hover-bg:    color-mix(in srgb, var(--st-accent) 10%, white);
    --st-grid-hover-text:  var(--st-text-body);   /* pairs with --st-grid-hover-bg; override together if a skin's hover-bg goes light/saturated enough that body text loses contrast on it */
    --st-grid-border:      var(--st-border-color);
    --st-grid-edited-bg:   #fff3cd;   /* StGrid "edited but not yet saved" yellow flag (.editedgridcell) */
    --st-grid-edited-text: #000000;   /* pairs with --st-grid-edited-bg; override together if a skin's edited-bg goes dark */

    /* ---- grid density (row height / font size) ---- */
    /* Derived from --st-font-size-base so a density-only skin (e.g. Compact) shrinks the grid just by  */
    /* overriding that one var. Font-size and cell-padding-y are a paired lever: bumping one up shifts   */
    /* the other down to hold row height (line-height + 2*padding-y + 1px border) roughly constant -     */
    /* see td.st-grid-cell in standardtime-gridengine.css. Currently ~30px rows at a typical desktop      */
    /* viewport width.                                                                                    */
    --st-grid-font-size:              calc(var(--st-font-size-base) + 0.25vw);
    --st-grid-line-height:            normal;   /* browser default; a density skin can tighten this independently of font-size */
    --st-grid-cell-padding-y:         3px;   /* paired with the font-size bump above to hold ~30px row height */
    --st-grid-header-padding-y:       4px;
    --st-grid-cell-editor-min-height: 22px;

    /* ---- property grid density (row height) ---- */
    /* Separate from the grid density vars above - StPropertyGrid (the property panel) is a different  */
    /* engine/stylesheet from StGrid (the content grid) and is not affected by the vars above. Defaults */
    /* match today's previously-hardcoded values exactly, so only a skin that explicitly overrides these */
    /* (e.g. Compact) changes property panel row height. */
    --st-propgrid-row-min-height:     26px;
    --st-propgrid-cell-padding-y:     1px;
    --st-propgrid-header-padding-y:   4px;

    /* .reporttable* (stdata.Globals.DataTableToHtml() plain HTML report tables) - NOT consumed by StGrid */
    --st-reporttable-col1-bg: color-mix(in srgb, var(--st-accent) 10%, var(--st-bg-body));

    /* ---- tabs ---- */
    --st-tab-bg:             #888888;
    --st-tab-hover-bg:       #466291;
    --st-tab-active-bg:      #293955;
    --st-tab-text:           #ffffff;
    --st-tab-border:         #4897aa;

    /* ---- timesheet cells ---- */
    --st-ts-cell-bg:        #f0f0ff;
    --st-ts-cell-bg-alt:    #E0E0ff;
    --st-ts-cell-bg-sel:    #A0A0ff;

    /* ---- gantt ---- */
    --st-gantt-bar-bg:          lightsteelblue;
    --st-gantt-summary-bg:      orange;
    --st-gantt-summary-triangle: darkorange;
    --st-gantt-percent-bg:      rgba(0, 0, 0, 0.35);
    --st-gantt-milestone-color: slateblue;
    --st-gantt-milestone-bg:    yellow;
    --st-gantt-scale-border:    white;
    --st-gantt-gridline:        lightgray;
    --st-gantt-drag-bg:         blue;
    --st-gantt-link-color:      blue;

    /* ---- gantt critical path ---- */
    --st-gantt-critical-bar-start:    #dc2626;
    --st-gantt-critical-bar-end:      #ef4444;
    --st-gantt-noncritical-bar-start: #2563eb;
    --st-gantt-noncritical-bar-end:   #3b82f6;
    --st-gantt-float-bar-bg:          rgba(30, 58, 95, 0.30);
    --st-gantt-float-bar-stroke:      #3b82f6;
    --st-gantt-float-bar-text:        #60a5fa;
    --st-gantt-critical-arrow:        #ef4444;
    --st-gantt-noncritical-arrow:     #3b82f6;
    --st-gantt-today-color:           #c2580a;
    --st-gantt-weekend-bg:            rgba(0, 0, 0, 0.06);
    --st-gantt-weekend-scale-bg:      rgba(0, 0, 0, 0.12);
    --st-gantt-baseline-bar:          #888888;

    /* ---- gantt mini-map ---- */
    --st-gantt-minimap-bar-bg:             color-mix(in srgb, var(--st-accent) 55%, transparent);
    --st-gantt-minimap-viewport-bg:        color-mix(in srgb, var(--st-accent) 18%, transparent);
    --st-gantt-minimap-viewport-border:    color-mix(in srgb, var(--st-accent) 80%, transparent);

    /* ---- dock manager ---- */
    --st-dock-header-bg:    rgba(41, 57, 85, 1.0);
    --st-dock-text:         rgba(255, 255, 255, 1.0);
    --st-dock-border:       #212121;
    --st-dock-pane-bg:      #F5F5F5;
    --st-dock-splitter:     steelblue;
    --st-dock-active-tab:   #212121;
    --st-new-tab-flash:     yellow;

    /* ---- frozen rows (shop-floor status strips - Mini WIP, Mini Resource Allocation, etc.) ----
       Deliberately dark in every skin, light or dark - these are pinned summary rows meant to be read
       up close on one screen, not themed grid content. Each skin overrides both to its own
       --st-tab-active-bg/--st-tab-text pair (already proven dark-enough/high-contrast-enough as the
       active ribbon/dock tab color) rather than inventing a new color. The root default below is the
       flat charcoal-slate used before this variable existed, kept as the default/no-skin look. */
    --st-frozenrow-bg:      #343c4a;
    --st-frozenrow-text:    #f4f6f8;

    /* ---- scrollbars ---- */
    --st-scrollbar-size:        10px;   /* width for vertical, height for horizontal */
    --st-scrollbar-track:       transparent;
    --st-scrollbar-thumb:       color-mix(in srgb, var(--st-accent) 35%, transparent);
    --st-scrollbar-thumb-hover: color-mix(in srgb, var(--st-accent) 55%, transparent);

    /* ---- ai chat bubbles ---- */
    --st-ai-bubble-text:    #ffffff;
    --st-ai-bubble-you-bg:  #00469f;
    --st-ai-bubble-ai-bg:   #1e6b3c;
    --st-ai-bubble-app-bg:  #505050;

    /* Spinner color for the AI chat "Thinking..." indicator (.st-spinner in standardtime-uikit.css).
       Defaults to white, matching Bootstrap's hardcoded .text-light spinner it replaces (zero visual
       change), on the toolbar-header background it sits on today. */
    --st-spinner-color:     var(--st-dock-text, #fff);

    /* ---- toasts ---- */
    --st-toast-bg:      color-mix(in srgb, var(--st-bg-body) 92%, var(--st-accent));
    --st-toast-text:    var(--st-text-body);
    --st-toast-border:  var(--st-border-color);
    --st-toast-shadow:  0 6px 18px rgba(0, 0, 0, 0.22), 0 1px 3px rgba(0, 0, 0, 0.14);
    --st-toast-success: #16a34a;
    --st-toast-danger:  #dc2626;
    --st-toast-warning: #d97706;
    --st-toast-info:    #2563eb;

    /* ---- text selection ---- */
    --st-selection-bg:      #6366f1;
    --st-selection-text:    #ffffff;

    /* ---- typography ---- */
    /* Reproduces Bootstrap reboot.css's body { font-family: ... } sans-serif stack — this app
       never defined its own font-family, it silently inherited Bootstrap's via `body`. Consumed
       by standardtime-main.css's body rule plus -contextmenuengine.css/-toastengine.css, all of
       which used `var(--st-font-family, inherit)` and were relying on Bootstrap the same way. */
    --st-font-family:       system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    --st-font-size-base:    10pt;
    --st-font-weight:       normal;
    /* Reproduces Bootstrap reboot.css's body { line-height: 1.5 } — same silent-inheritance shape as
       --st-font-family above. Elements that vertically center text via flexbox (e.g. .st-dock-tab's
       .st-dock-tab-label) are sensitive to the inherited line-height even though their own box size
       doesn't change, so losing this shifted tab-label text by ~1px without any layout change otherwise
       visible. Not the same variable as --st-grid-line-height (standardtime-gridengine.css), which grid
       cells already set explicitly on themselves and never inherited from body. */
    --st-line-height:       1.5;
    --st-border-radius:     4px;
}

/* Firefox */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--st-scrollbar-thumb) var(--st-scrollbar-track);
}

/* Chromium / Edge / Safari */
*::-webkit-scrollbar {
    width: var(--st-scrollbar-size);
    height: var(--st-scrollbar-size);
}
*::-webkit-scrollbar-track {
    background: var(--st-scrollbar-track);
}
*::-webkit-scrollbar-thumb {
    background: var(--st-scrollbar-thumb);
    border-radius: var(--st-border-radius);
}
*::-webkit-scrollbar-thumb:hover {
    background: var(--st-scrollbar-thumb-hover);
}

/* Purpose of this file: this app's own permanent global CSS resets - box-sizing and form-control
   typography inheritance - for properties/elements that need their OWN selector rather than
   piggybacking on an existing rule elsewhere: the universal `*` selector below, or a tag-selector
   list like `input, button, select, ...` that doesn't already exist anywhere else in this app's
   CSS. Browsers never provided either of these by default, with or without Bootstrap; this file
   is where the app owns them outright now that Bootstrap is gone. This is deliberately NOT the
   same file as standardtime-main.css's `body` rule: two sibling global resets (--st-font-family,
   --st-line-height) live in standardtime-main.css instead, because they're single properties that
   inherit by default and could be added as one line to the `body` rule that was already there -
   see that file if you're looking for those two. Everything here needs a rule of its own because
   the whole point of the rule is that the property does NOT arrive by ordinary inheritance from
   `body`. Also holds the layout-utility classes (`.st-flex`, `.st-flex-center`, `.st-toolbar-row`)
   below - unrelated to the reset rules above beyond sharing this file, per the app's
   one-file-per-concern convention (standardtime-toastengine.css, standardtime-dockengine.css, etc.).
   For why these resets exist (they used to arrive for free via Bootstrap's reboot.css, discovered
   one dependency at a time as Bootstrap was removed), see the git history of
   "Feature enhancement md's/ReplaceBootstrap/ReplaceBootstrap.md" and "RemoveBootstrap.md". */

/* Global box-sizing reset, reproducing Bootstrap reboot.css's `*, *::before, *::after {
   box-sizing: border-box; }`. This app relies on border-box sizing everywhere today via
   Bootstrap's reboot, whether or not an element ever touches a Bootstrap class. Known
   dependents if this rule is ever changed or removed:
     - standardtime-dockengine.css's .st-dock-tabstrip-top 39px tab-strip height calc
     - standardtime-resizeengine.js's _applyDrag() geometry math (see its top-of-file comment)
   See ReplaceBootstrap.md, "## 6. Global reset dependency", for the full writeup. */
*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Reproduces Bootstrap reboot.css's `input, button, select, optgroup, textarea { margin: 0;
   font-family: inherit; font-size: inherit; line-height: inherit; }`. Browsers do NOT inherit
   typography onto form controls by default (a classic UA-stylesheet gotcha) - without this,
   every <input>/<select>/<textarea> in the app falls back to the browser's own native
   control font (confirmed live: Chrome's default is "Arial" at 13.3333px, vs. this app's
   `--st-font-family` stack at the inherited size). Property grid editors
   (standardtime-propertygridengine.css's .st-propgrid-cell-value input/select/textarea) are
   the highest-visibility example, but this affects every form control app-wide, the same
   "not a markup class, easy to miss" shape as the `*` box-sizing rule above. Applied directly
   to these tag selectors, not via `body`, because that's the whole reason this rule exists -
   these elements don't pick up inherited typography the normal way. See ReplaceBootstrap.md,
   "### 9. Global reset dependency: form-control typography inheritance", for the full writeup. */
input,
button,
select,
optgroup,
textarea {
    margin: 0;
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
}

/* Phase 3 layout-utility replacements (ReplaceBootstrap.md, "## 1. Layout utilities" /
   "## New files needed"), swapping in for Bootstrap's `.d-flex`, `.align-items-center`, and
   `.container` utility classes. `.container` itself is dropped rather than reproduced - see
   ReplaceBootstrap.md for why it's inert at the toolbar-header call sites this replaces. */
.st-flex {
    display: flex;
}

.st-flex-center {
    display: flex;
    align-items: center;
}

.st-toolbar-row {
    display: flex;
    align-items: center;
    width: 100%;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* ---------------------------------------------------------------------
   Bootstrap small-component replacements: buttons, button-group, close
   button, spinner. Part of the ReplaceBootstrap migration — see
   "Feature enhancement md's\ReplaceBootstrap\ReplaceBootstrap.md".
   --------------------------------------------------------------------- */

/* ---- Buttons ---- */
.st-btn {
    display: inline-block;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: var(--st-border-radius, 4px);
    background: none;
    padding: 0.375rem 0.75rem;
    cursor: pointer;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-btn-outline {
    color: var(--st-text-muted);
    border-color: var(--st-border-color);
    background-color: transparent;
}
.st-btn-outline:hover {
    /* A translucent wash (not the pre-mixed --st-accent-hover) so it stays visible regardless of what
       background this button sits on — --st-accent-hover is calibrated against --st-bg-body/--st-bg-ribbon
       (whitesmoke) and is nearly invisible against the toolbar's darker --st-bg-toolbar (#E8E8E8), the
       context these buttons actually render in. Same idiom as --st-scrollbar-thumb. */
    background-color: color-mix(in srgb, var(--st-accent) 20%, transparent);
}
.st-btn-outline:focus,
.st-btn-outline:focus-visible {
    outline: none;
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--st-focus-ring) 25%, transparent);
}

/* ---- Button group: merges adjacent buttons into one segmented control ---- */
.st-btn-group {
    display: inline-flex;
    --st-btn-group-radius: 0.25rem;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-btn-group-sm {
    --st-btn-group-radius: 0.2rem;
}
.st-btn-group > .st-btn {
    border-radius: 0;
    margin-left: -1px;
}
.st-btn-group > .st-btn:first-child {
    margin-left: 0;
    border-top-left-radius: var(--st-btn-group-radius);
    border-bottom-left-radius: var(--st-btn-group-radius);
}
.st-btn-group > .st-btn:last-child {
    border-top-right-radius: var(--st-btn-group-radius);
    border-bottom-right-radius: var(--st-btn-group-radius);
}
.st-btn-group > .st-btn:hover,
.st-btn-group > .st-btn:focus,
.st-btn-group > .st-btn.active {
    position: relative;
    z-index: 1;
}

/* ---- Close button: mirrors .st-dialog-close-btn's plain-&times; technique
   (standardtime-dialog.css), sized for a popup context rather than a dialog titlebar. ---- */
.st-close-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    padding: 0 4px;
    color: var(--st-text-body);
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-close-btn:hover {
    color: var(--st-accent);
}

/* ---- Spinner: dependency-free rotating-border indicator, replaces .spinner-border. ---- */
@keyframes st-spinner-rotate {
    to { transform: rotate(360deg); }
}
.st-spinner {
    display: inline-block;
    width: 2rem;
    height: 2rem;
    vertical-align: text-bottom;
    border: 0.25em solid var(--st-spinner-color);
    border-right-color: transparent;
    border-radius: 50%;
    animation: st-spinner-rotate 0.75s linear infinite;
}
.st-spinner-sm {
    width: 1rem;
    height: 1rem;
    border-width: 0.2em;
}

/* ---- Dropdown menu: replaces .dropdown-menu/.dropdown-item/.dropdown-divider/.active.
   Sits inside .custom-dropdown-panel (standardtime-main.css), which already supplies the
   panel's own background/border/border-radius — this stays visually minimal rather than
   duplicating that chrome a second time. ---- */
.st-dropdown-menu {
    list-style: none;
    margin: 0;
    padding: 4px 0;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-dropdown-item {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 6px 16px;
    color: var(--st-text-body);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
.st-dropdown-item:hover {
    /* Deliberately lighter than .active below — same idiom as .st-btn-outline:hover and the
       app's own grid-hover/grid-selected split (--st-grid-hover-bg is a light tint, the
       selected-cell fill is solid --st-accent). If both hover and active used solid accent,
       hovering a non-active item while a different item is active would show two
       identically-colored items at once, exactly the ambiguity this migration's own testing
       notes warn against. */
    background-color: color-mix(in srgb, var(--st-accent) 15%, transparent);
}
.st-dropdown-item.active {
    background-color: var(--st-accent);
    color: var(--st-accent-text);
}
.st-dropdown-divider {
    height: 0;
    margin: 8px 0;
    border-top: 1px solid var(--st-border-color);
}

/* ------------------------------------------------------------------------- */
/* StPropertyGrid engine - structural + themed base styles                   */
/* Companion to standardtime-propertygridengine.js.                          */
/*                                                                           */
/* Renders a two-level property grid: collapsible category headers, each     */
/* holding name/value property rows. General-purpose: no app-specific rules. */
/* Colors use the --st-* skin variables so every skin themes consistently.   */
/* ------------------------------------------------------------------------- */


/* Root fills the width of its scrolling pane and never overflows horizontally: */
/* the fixed-ish name column plus a flexible value column always add up to the  */
/* pane width, so the editor dropdown buttons on the right stay reachable        */
/* without a horizontal scrollbar. Long names ellipsize and value editors shrink */
/* to fit rather than pushing the row wider than the pane.                       */
.st-propgrid {
    width: 100%;
    color: var(--st-text-body, #212529);
}

/* Hide the grid until the host has applied the saved collapsed-category state, so the */
/* user never sees every category flash open and then collapse (the server renders all */
/* categories expanded). The host must remove this class from a code path that cannot  */
/* be skipped by a JS error: Standard Time removes it in the loader img's inline       */
/* onload try/finally (with an onerror fallback), NOT inside the setup function - a    */
/* missing or stale engine script would prevent that function from ever running and    */
/* leave the grid permanently hidden.                                                  */
.st-propgrid.st-propgrid-initializing {
    visibility: hidden;
}

/* Message the host shows instead of a grid when there is nothing to edit (no          */
/* properties, access denied, build error) - also reused as-is for the Properties/      */
/* Settings dock panes' own initial "Select a/an X to..." placeholder text              */
/* (Views/Shared/DockManagerPartialView.cshtml). Rendered outside the .st-propgrid root. */
.st-propgrid-caption {
    padding: 12px;
    color: var(--st-text-body, #212529);
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}


/* ---- Category ---------------------------------------------------------- */

.st-propgrid-category {
    border-bottom: 1px solid var(--st-border-color, #dee2e6);
}

/* Clickable header row: caret + label. Spans the full width. */
.st-propgrid-category-header {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: var(--st-propgrid-header-padding-y, 4px) 6px;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    background-color: var(--st-grid-header-bg, #f1f3f5);
    color: var(--st-grid-header-text, #212529);
    font-weight: 600;
}

.st-propgrid-category-header:hover {
    background-color: var(--st-grid-hover-bg, #e9ecef);
    color: var(--st-grid-hover-text, inherit);
}

/* Focus ring for keyboard users toggling with Enter / Space. Uses --st-focus-ring
   (standardtime-skin-variables.css, defaults to --st-accent) so the ring re-themes per skin
   instead of being pinned to a hardcoded colour - same variable every other component's own
   focus ring uses (gridengine/toastengine/ribbon). */
.st-propgrid-category-header:focus-visible {
    outline: 2px solid var(--st-focus-ring, #6366f1);
    outline-offset: -2px;
}

.st-propgrid-category-label {
    flex: 0 0 auto;
    white-space: nowrap;
}


/* Expand/collapse caret. Drawn as a CSS border-triangle rather than a Unicode  */
/* glyph (e.g. "\25B6") - on some Windows font configurations the browser        */
/* substitutes a colored icon font for that character that ignores `color` and  */
/* always renders solid blue. A border-triangle cannot be hijacked by font       */
/* substitution since it is not text. (Same rationale as the StTree caret.)     */
.st-propgrid-toggle {
    display: inline-block;
    position: relative;
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    user-select: none;
}

.st-propgrid-toggle::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 4px 0 4px 6px;
    border-color: transparent transparent transparent var(--st-text-muted, gray);
    transform: translate(-50%, -50%);
    transition: transform 0.1s ease;
}

/* Rotate the caret to point down when the category is open */
.st-propgrid-category.st-open > .st-propgrid-category-header > .st-propgrid-toggle::before {
    transform: translate(-50%, -50%) rotate(90deg);
}


/* ---- Category body (property rows) ------------------------------------- */

/* Hidden until the category is expanded */
.st-propgrid-category-body {
    display: none;
}

.st-propgrid-category.st-open > .st-propgrid-category-body {
    display: block;
}


/* ---- Property row ------------------------------------------------------ */

/* Two columns: name | value. The value column flexes; the name column is a    */
/* fixed share so editors line up down the grid.                              */
/* The 24px left padding indents property rows under their category label      */
/* (6px header padding + 14px caret + 4px gap), preserving the indented        */
/* parent/child look of the old IG grid (which used Indentation="15%" - a      */
/* fixed indent is used here so it does not drift with pane width).            */
.st-propgrid-row {
    display: flex;
    align-items: center;
    min-height: var(--st-propgrid-row-min-height, 26px);
    padding: var(--st-propgrid-cell-padding-y, 1px) 6px var(--st-propgrid-cell-padding-y, 1px) 24px;
    white-space: nowrap;
    border-bottom: 1px solid var(--st-border-color, #dee2e6);
}

.st-propgrid-row:hover {
    background-color: var(--st-grid-hover-bg, #e9ecef);
    color: var(--st-grid-hover-text, inherit);
}

/* Property name cell. Marked searchableitem so standardtime-search.js can       */
/* highlight it (adds searchselected / searchcurrent).                          */
/* Pixel basis (not a %) so every editor lines up down the grid regardless of    */
/* the widest value. flex-grow:0 caps it at 200px on wide panels; flex-shrink:1  */
/* with a 120px floor lets it give room back to the value column (and its        */
/* dropdown button) on narrow panels instead of forcing a horizontal scrollbar.  */
/* All rows share the same basis + container width, so they stay aligned even    */
/* while shrinking.                                                              */
.st-propgrid-cell-name {
    flex: 0 1 200px;
    max-width: 200px;
    min-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-right: 6px;
    color: var(--st-text-body, #212529);
}

/* Value cell hosts the server-built editor HTML (input / select / dropdown).   */
/*                                                                              */
/* flex-basis MUST be 0 (flex: 1 1 0), NOT auto. With flex-basis:auto the cell's */
/* base size is its content's max-content - for a native <select> that is its    */
/* widest <option> - which varies per row (long client/project lists vs short    */
/* Yes/No). On rows with a wide dropdown that large basis pulled flex-shrink out  */
/* of the sibling name cell (which is shrinkable), collapsing the name column     */
/* toward its 120px floor, so the editor's LEFT edge protruded farther left than  */
/* the other rows. A 0 basis is content-independent: every row splits the row     */
/* width identically, so the name column stays a constant 200px down the grid.    */
/*                                                                              */
/* overflow:hidden keeps a stray over-wide editor from spilling out and from      */
/* propagating its intrinsic width upward. Safe for the dropdown-panel editors    */
/* (Folder / Attachments / Assign users): their .custom-dropdown-panel is         */
/* position:fixed (see standardtime-main.css), out of flow, so it is not clipped. */
.st-propgrid-cell-value {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
}

/* Each editor's inner .propertycontainer is display:flex (Bootstrap d-flex), so */
/* the <select>/<input>/<textarea> inside it are flex items. A flex item's       */
/* default min-width:auto equals its content's min size - for a <select> that is */
/* the widest <option> (long client/project lists) - which overrides the inline  */
/* width:100%, refuses to shrink, and overflows the value column, reintroducing  */
/* a horizontal scrollbar. Pin min-width:0 + max-width:100% down the chain so    */
/* the controls honor width:100% and shrink to the value column instead.         */
.st-propgrid-cell-value .propertycontainer {
    min-width: 0;
    max-width: 100%;
}

.st-propgrid-cell-value select,
.st-propgrid-cell-value input,
.st-propgrid-cell-value textarea {
    min-width: 0;
    max-width: 100%;
}


/* ---- Search highlight ---------------------------------------------------- */
/*                                                                            */
/* Intentionally NOT styled here. standardtime-search.js adds the             */
/* searchselected / searchcurrent classes to the .searchableitem name cell,   */
/* and standardtime-search.css already styles those classes with `!important` */
/* backgrounds themed from --st-text-search-sel / --st-text-search-cur. Any    */
/* rule we added here would be dead (the app-wide !important rule always wins) */
/* AND would reference skin variables that do not exist, so the highlight      */
/* would not re-theme on dark skins. Leave highlighting to the shared          */
/* search stylesheet.                                                         */

/* ------------------------------------------------------------------------- */
/* StTree engine - structural + themed base styles                           */
/* Companion to standardtime-treeengine.js.                                  */
/*                                                                           */
/* Reusable by every StTree instance (Filter, Favorites, Check-list,         */
/* User-assign, Folder). Per-tree appearance (font sizes, exact spacing,     */
/* scoping) is layered on top - e.g. standardtime-filtertree.css.            */
/* Colors use the --st-* skin variables so all skins theme consistently.     */
/* ------------------------------------------------------------------------- */


/* Root list and nested child lists */
ul.st-tree,
ul.st-tree-children {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* The root sizes to its widest row (max-content) but always fills the pane     */
/* (min-width:100%). Long labels are therefore not truncated - the scrolling    */
/* container shows a horizontal scrollbar, matching the previous IG tree. Full- */
/* width rows also let the hover/selection highlight span the scrolled width.   */
ul.st-tree {
    width: max-content;
    min-width: 100%;
}

/* Indent one level per depth; children are hidden until the parent is open */
ul.st-tree-children {
    padding-left: 18px;
    display: none;
}

/* Reveal children when the parent node is expanded */
li.st-tree-node.st-parent.st-open > ul.st-tree-children {
    display: block;
}

li.st-tree-node {
    margin: 0;
    padding: 0;
}


/* One clickable row: caret, optional checkbox, optional icon, then label */
.st-tree-row {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 2px 4px;
    white-space: nowrap;
    cursor: pointer;
    border-radius: var(--st-border-radius, 4px);
    color: var(--st-text-body, #212529);
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-tree-row:hover {
    background-color: var(--st-grid-hover-bg, #eef);
    color: var(--st-grid-hover-text, inherit);
}

/* Selected node highlight */
li.st-tree-node.st-tree-selected > .st-tree-row {
    background-color: var(--st-selection-bg, #6366f1);
    color: var(--st-selection-text, #ffffff);
}


/* Expand/collapse caret. The span reserves width on leaves too, so labels    */
/* line up whether or not a node has children.                               */
.st-tree-toggle {
    display: inline-block;
    position: relative;
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
    -webkit-tap-highlight-color: transparent; /* suppress mobile/touch tap-highlight flash */
}

/* Caret glyph appears only on parent nodes. Drawn as a CSS border-triangle rather */
/* than a Unicode glyph (was "\25B6") - Windows substitutes a colored icon font    */
/* for that character in some configurations, which ignores `color` entirely and  */
/* always renders blue regardless of the CSS below. A border-triangle can't be     */
/* hijacked by font substitution since it isn't text.                             */
li.st-tree-node.st-parent > .st-tree-row > .st-tree-toggle::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 4px 0 4px 6px;
    border-color: transparent transparent transparent var(--st-text-muted, gray);
    transform: translate(-50%, -50%);
    transition: transform 0.1s ease;
}

/* Rotate the caret to point down when the parent is open */
li.st-tree-node.st-parent.st-open > .st-tree-row > .st-tree-toggle::before {
    transform: translate(-50%, -50%) rotate(90deg);
}


/* Node icon (data:image/png;base64 from the model) */
.st-tree-icon {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    object-fit: contain;
}


/* Checkbox (checkbox trees only: Favorites, Check-list, User-assign) */
.st-tree-checkbox {
    flex: 0 0 auto;
    margin: 0;
    cursor: pointer;
}


/* Label never wraps or truncates; the container scrolls horizontally instead */
/* (matches the previous Infragistics tree).                                  */
.st-tree-label {
    flex: 0 0 auto;
    white-space: nowrap;
}

/* ------------------------------------------------------------------------- */
/* StToaster engine - structural + themed styles                             */
/* Companion to standardtime-toastengine.js.                                 */
/*                                                                           */
/* Replaces the Bootstrap alert-* classes the old jquery.toaster plugin       */
/* borrowed (alert alert-success / alert-danger / btn-close), which were      */
/* hardcoded light-theme colors and unreadable on the dark skins.            */
/*                                                                           */
/* Every color resolves from an --st-toast-* custom property that falls back  */
/* to an existing --st-* skin variable, so the component themes correctly on  */
/* all skins with NO edit to standardtime-skin-variables.css. A skin that     */
/* wants finer control can declare the --st-toast-* names itself - see the    */
/* "optional skin variables" block in ReplaceToaster.md.                      */
/*                                                                           */
/* Design note: the toast surface is neutral (derived from --st-bg-body) with */
/* a colored left accent bar, colored icon and colored title, rather than a   */
/* fully saturated colored panel. A saturated panel has to pick a text color, */
/* and any choice is wrong on half the skins - the old plugin's pale-green    */
/* alert-success with dark text was illegible on st-dark. A neutral surface   */
/* inherits the skin's own text color and can never lose contrast.            */
/* ------------------------------------------------------------------------- */


/* ------------------------------------------------------------------------- */
/* Container                                                                  */
/* ------------------------------------------------------------------------- */

/* One container holds the whole stack. It spans a screen edge, so it must    */
/* never intercept clicks meant for the app underneath - pointer-events is    */
/* re-enabled per toast below.                                                */
.st-toast-container {
    position: fixed;
    z-index: 2147483000;
    display: flex;
    flex-direction: column;
    /* Spacing lives on the toasts as margin-bottom, NOT as a container `gap`. A gap is not an animatable
       property of the leaving element, so it would survive the collapse and snap away only when the node
       is finally removed - a visible 8px jolt at the end of every dismissal. */
    width: 380px;
    max-width: calc(100vw - 20px);
    max-height: calc(100vh - 20px);
    pointer-events: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    overflow: visible;
    font-family: var(--st-font-family, inherit);
    font-size: var(--st-font-size-base, 10pt);
    /* The container is relocated into the open modal <dialog> when there is one (see the "Top layer"
       section of standardtime-toastengine.js). Everything here is parent-independent - position is
       fixed and therefore viewport-relative either way - so no dialog-scoped variant is needed. */
}

/* Anchoring. Top-anchored stacks grow downward (new toasts appended); bottom-anchored stacks grow  */
/* upward (new toasts prepended) - see the isTopAnchored() branch in standardtime-toastengine.js.   */
.st-toast-container.st-toast-top-right    { top: 10px;    right: 10px; }
.st-toast-container.st-toast-top-left     { top: 10px;    left: 10px; }
.st-toast-container.st-toast-top-center   { top: 10px;    left: 50%; transform: translateX(-50%); }
.st-toast-container.st-toast-bottom-right  { bottom: 10px; right: 10px; }
.st-toast-container.st-toast-bottom-left   { bottom: 10px; left: 10px; }
.st-toast-container.st-toast-bottom-center { bottom: 10px; left: 50%; transform: translateX(-50%); }


/* ------------------------------------------------------------------------- */
/* Toast                                                                      */
/* ------------------------------------------------------------------------- */

.st-toast {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin-bottom: 8px;        /* stack spacing - see the note on .st-toast-container */
    padding: 10px 10px 11px 13px;
    box-sizing: border-box;    /* the inline pixel height removeToast() pins must include padding+border */
    pointer-events: auto;      /* re-enable interaction the container turned off */
    overflow: hidden;          /* clips the accent bar and progress bar to the rounded corners */

    background: var(--st-toast-bg, color-mix(in srgb, var(--st-bg-body, #f5f5f5) 92%, var(--st-accent, #6366f1)));
    color: var(--st-toast-text, var(--st-text-body, #212529));
    border: 1px solid var(--st-toast-border, var(--st-border-color, #dee2e6));
    border-radius: var(--st-border-radius, 4px);
    box-shadow: var(--st-toast-shadow, 0 6px 18px rgba(0, 0, 0, 0.22), 0 1px 3px rgba(0, 0, 0, 0.14));

    animation: st-toast-in 180ms ease-out;
}

/* The colored left accent bar carrying the priority signal. Drawn as a pseudo-element rather than a */
/* border-left so the border-radius clip and the progress bar can coexist with it.                   */
.st-toast::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 4px;
    background: var(--st-toast-accent);
}

/* There is deliberately NO `.st-toast:last-child { margin-bottom: 0 }` rule here. It looks tidier, but
   :last-child re-evaluates the instant a leaving toast's node is finally detached: the toast above it
   becomes the new last child and its margin-bottom drops 8px -> 0 in a single frame. On a bottom-anchored
   stack (the small-app layout) that shifts the entire stack 8px at the very end of every dismissal - the
   exact snap the two-phase leave animation exists to eliminate. The cost of leaving it out is 8px of
   transparent space at the stack's trailing edge, which is invisible and, crucially, constant. */

.st-toast-clickable {
    cursor: pointer;
}


/* ---- priority colors ---- */
/* Fixed hex rather than skin variables: these are semantic status colors that must read the same on */
/* every skin (the same reasoning as --st-gantt-critical-* in standardtime-skin-variables.css). They */
/* are used only for the 4px bar, the icon and the title - never as a background behind body text -  */
/* so they cannot create a contrast failure on a light or a dark skin.                               */

.st-toast-success { --st-toast-accent: var(--st-toast-success, #16a34a); }
.st-toast-danger  { --st-toast-accent: var(--st-toast-danger,  #dc2626); }
.st-toast-warning { --st-toast-accent: var(--st-toast-warning, #d97706); }
.st-toast-info    { --st-toast-accent: var(--st-toast-info,    #2563eb); }


/* ---- icon ---- */

.st-toast-icon {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    margin-top: 1px;
    /* The inline SVGs use fill/stroke="currentColor", so this one declaration tints them. */
    color: var(--st-toast-accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.st-toast-icon svg {
    display: block;
}


/* ---- text ---- */

.st-toast-body {
    flex: 1 1 auto;
    min-width: 0;    /* lets a long unbroken token wrap instead of stretching the flex row */
}

.st-toast-title {
    font-weight: bold;
    color: var(--st-toast-accent);
    margin-bottom: 2px;
    overflow-wrap: anywhere;
}

/* pre-wrap is what makes an embedded "\n" render as a real line break. The old plugin converted     */
/* newlines to "<br />" and injected the result with jQuery .html() - that conversion is gone, and   */
/* with it the HTML-injection path for server error text and record names.                           */
/* A window.onerror toast can carry a very long stack trace, so cap the height and scroll inside the  */
/* toast rather than growing a toast taller than the viewport.                                        */
.st-toast-message {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 38vh;
    overflow-y: auto;
    line-height: 1.35;
}


/* ---- duplicate counter ---- */

.st-toast-count {
    flex: 0 0 auto;
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    font-size: 0.8em;
    font-weight: bold;
    color: var(--st-toast-accent);
    /* Unlike the bare var(--st-toast-accent) uses elsewhere in this file, --st-toast-accent needs a literal
       fallback INSIDE this color-mix(): an invalid color-mix() argument invalidates the whole function (and
       therefore the whole `background` declaration), not just that one argument, whereas a bare `var()` with
       no fallback merely falls back to the property's own initial value. --st-toast-accent is always set in
       practice (renderToast() always adds one of .st-toast-success/-danger/-warning/-info), but this keeps
       the badge from losing its background entirely if that guarantee is ever broken. */
    background: color-mix(in srgb, var(--st-toast-accent, var(--st-toast-info, #2563eb)) 16%, transparent);
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* The engine toggles the `hidden` attribute; the display rule above would otherwise beat the UA's */
/* [hidden] { display: none } and leave an empty badge on every single toast.                      */
.st-toast-count[hidden] {
    display: none;
}


/* ---- controls ---- */

.st-toast-controls {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 2px;
    margin-top: -2px;
    margin-right: -2px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-toast-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 3px;
    background: transparent;
    color: var(--st-text-muted, rgba(0, 0, 0, 0.55));
    cursor: pointer;
    line-height: 1;
}

.st-toast-btn:hover {
    background: color-mix(in srgb, var(--st-toast-text, var(--st-text-body, #212529)) 12%, transparent);
    color: var(--st-toast-text, var(--st-text-body, #212529));
}

.st-toast-btn:focus-visible {
    outline: 2px solid var(--st-focus-ring, #6366f1);
    outline-offset: 1px;
}

/* Copy-to-clipboard result feedback (a short tint, no layout shift). */
.st-toast-copy-ok   { color: var(--st-toast-success, #16a34a); }
.st-toast-copy-fail { color: var(--st-toast-danger,  #dc2626); }


/* ---- progress bar ---- */

/* Duration is set inline by the engine (animationDuration = timeout). The bar is paused in place by  */
/* the st-toast-paused class rather than restarted, so it stays in lockstep with the JS timer across  */
/* hover/unhover. The engine adds and removes that class from ONE place (applyPauseState), which is   */
/* what keeps the bar and the setTimeout agreeing when the pointer and the keyboard disagree - hover  */
/* and focus are two independent holds and either alone keeps the class on.                           */
/*                                                                                                    */
/* `forwards` holds the bar at scaleX(0) once it has drained. That is the intended look for a toast    */
/* about to go, but it is also why the engine grants its end-of-life pause grace only once per toast:  */
/* every extra grace period is time the bar has already claimed is spent (see MIN_REMAINING_ON_PAUSE   */
/* in standardtime-toastengine.js).                                                                    */
.st-toast-progress {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 100%;
    transform-origin: left center;
    background: var(--st-toast-accent);
    opacity: 0.55;
    animation-name: st-toast-progress;
    animation-timing-function: linear;
    animation-fill-mode: forwards;
}

.st-toast-paused .st-toast-progress {
    animation-play-state: paused;
}


/* ------------------------------------------------------------------------- */
/* Animations                                                                 */
/* ------------------------------------------------------------------------- */

/* Slide in from the right edge the stack is anchored to. */
@keyframes st-toast-in {
    from { opacity: 0; transform: translateX(24px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* The leave keyframes handle ONLY the fade and slide. The height collapse that makes the toasts below   */
/* glide up is a separate `transition` declared on .st-toast-leaving below - see the long comment in     */
/* removeToast() for why the two phases cannot both be keyframes (a keyframe would need the start height */
/* written in the stylesheet, and it is a runtime pixel value).                                          */
@keyframes st-toast-out {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(24px); }
}

@keyframes st-toast-in-left {
    from { opacity: 0; transform: translateX(-24px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes st-toast-out-left {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(-24px); }
}

@keyframes st-toast-progress {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

/* A short pulse when an identical toast arrives and the count badge increments. */
@keyframes st-toast-bump {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.035); }
    100% { transform: scale(1); }
}


/* Specificity note: every rule below that overrides animation-name is written as a compound          */
/* selector at 0,2,0 or higher and ordered so the later rule wins at equal specificity. The           */
/* left-anchored enter override is 0,2,0, so plain `.st-toast-leaving` (0,1,0) would have lost to it  */
/* and a closing toast on a left-anchored stack would have replayed its ENTER animation instead.      */

/* Left-anchored stacks slide in/out from the left instead of the right. */
.st-toast-top-left .st-toast,
.st-toast-bottom-left .st-toast {
    animation-name: st-toast-in-left;
}

/* Phase 1: the toast itself fades and slides out quickly (150ms), and `forwards` holds it invisible for
   the rest of the move.

   Phase 2: the geometry collapses on a decelerating curve after an 80ms head start, so the toast has
   visibly gone before the gap closes and the toasts below glide up and settle rather than snapping. The
   easing is a standard "ease-out-quint" - it does most of its travel early and eases into rest, which is
   what reads as a glide. Do NOT put this back on `ease-in`: that curve barely moves for the first half of
   its duration and then rushes, which is precisely what made the earlier version look snappy.

   All FIVE collapsing values are set inline by removeToast(), never here. A transition only starts when
   the transition property was already present in the element's "before-change" style. Declaring the zero
   targets in this same rule would land them in the very style recalculation that first applies
   `transition`, so the before-change style would still say `transition: none` and margin/padding/border
   would jump straight to zero while only `height` (set inline afterwards) animated - a collapse that
   loses the toast's padding and border on frame one. removeToast() therefore adds this class, forces a
   reflow to commit the transition, and only then writes the five targets.

   Two numbers below are COUPLED TO THE JS and nothing enforces it: the 80ms delay and the 280ms duration
   sum to 360ms, and `LEAVE_FALLBACK_MS` in standardtime-toastengine.js (600) is the safety net that must
   stay clear of that sum. Raise either one past the net and the net starts firing mid-collapse, deleting
   the node partway through the glide - the same visible snap constraint 3 exists to prevent, reached from
   the other side. Change one, change the other.

   The `ease-in` on the `animation` line below is on the FADE (phase 1) and is correct there. The curve the
   "do not put this back on ease-in" warning above refers to is the one on the five transitioned
   properties, which must stay cubic-bezier(0.22, 0.61, 0.36, 1). */
.st-toast.st-toast-leaving {
    animation: st-toast-out 150ms ease-in forwards;
    transition: height         280ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms,
                margin-bottom  280ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms,
                padding-top    280ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms,
                padding-bottom 280ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms,
                border-width   280ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms;
    /* pointer-events: none is load-bearing for the timer logic, not just a cosmetic "do not click a
       toast that is on its way out". It is what stops a pointer moving across the collapsing stack from
       firing mouseenter on a record whose timer has already been torn down. (The engine's pause entry
       points all bail on rec.removed, so the pause would be a no-op even without this - but dropping the
       rule would also make the toast clickable, firing onClick for a toast the user can no longer see.)
       Note the flip side: a pointer already resting on the toast when the class lands gets a synthesized
       mouseleave, which is exactly why the resume path must tolerate an already-removed record. */
    pointer-events: none;
}

/* This class is deliberately never removed by bumpDuplicate() after its 220ms pulse finishes - it stays
   until the NEXT bump retriggers it via the classList remove/reflow/add dance. That is only safe because
   `.st-toast.st-toast-bump` and `.st-toast.st-toast-leaving` are equal-specificity compound selectors that
   both set the `animation` shorthand: at equal specificity the later rule in the stylesheet wins outright
   for an element matching both, which today is this rule. If a toast that was ever bumped is later
   dismissed while still carrying this class, ITS FADE-OUT WOULD SILENTLY BE REPLACED BY THE BUMP PULSE.
   removeToast() therefore strips "st-toast-bump" in the same statement that adds "st-toast-leaving" - see
   the comment there. Do not "clean up" that removal as redundant; it is the only thing keeping these two
   classes from ever coexisting on an element. */
.st-toast.st-toast-bump {
    animation: st-toast-bump 220ms ease-out;
}

.st-toast-top-left .st-toast.st-toast-leaving,
.st-toast-bottom-left .st-toast.st-toast-leaving {
    animation-name: st-toast-out-left;
}


/* ------------------------------------------------------------------------- */
/* Reduced motion                                                             */
/* ------------------------------------------------------------------------- */

/* The engine also skips the leave animation entirely under prefers-reduced-motion (it removes the  */
/* node immediately), so this only has to neutralize the enter/bump animations and the progress bar. */
/* The progress bar is hidden rather than merely un-animated: a bar frozen at 100% width would read  */
/* as "this toast is stuck".                                                                         */
@media (prefers-reduced-motion: reduce) {

    .st-toast,
    .st-toast.st-toast-bump,
    .st-toast.st-toast-leaving {
        animation: none !important;
        transition: none !important;
    }

    .st-toast-progress {
        display: none;
    }
}


/* ------------------------------------------------------------------------- */
/* Narrow screens (the bSmallSizeApp / phone layout)                          */
/* ------------------------------------------------------------------------- */

/* Below this width a 380px fixed column plus margins no longer fits, so the stack goes edge-to-edge. */
/* These selectors repeat the anchor class deliberately: they have to match the 0,2,0 specificity of  */
/* the anchor rules above, otherwise `right: 10px` and the -center `translateX(-50%)` would win and   */
/* push the now-full-width bar off screen.                                                            */
@media (max-width: 600px) {

    .st-toast-container.st-toast-top-right,
    .st-toast-container.st-toast-top-left,
    .st-toast-container.st-toast-top-center,
    .st-toast-container.st-toast-bottom-right,
    .st-toast-container.st-toast-bottom-left,
    .st-toast-container.st-toast-bottom-center {
        width: auto;
        /* The base rule's `max-width: calc(100vw - 20px)` is narrower than the 100vw - 16px this
           left/right pair implies, so without overriding it here the max-width cap wins and the
           browser falls back to its CSS2.1 over-constrained resolution: `left` is honored and `right`
           is silently discarded and recomputed, landing a few pixels short of the 8px this rule states.
           `max-width: none` removes the conflicting cap so both insets are honored exactly as written -
           `left`/`right` alone already fully determine the width, so there is nothing left for
           max-width to usefully bound here. */
        max-width: none;
        left: 8px;
        right: 8px;
        transform: none;
    }

    .st-toast-message {
        max-height: 30vh;
    }
}

/* ------------------------------------------------------------------------- */
/* StGrid engine - structural + themed base styles                           */
/* Companion to standardtime-gridengine.js.                                  */
/*                                                                           */
/* Replacement for the Infragistics igGrid CSS used by RecordsetGridPartial- */
/* View.cshtml. Colors use the --st-* skin variables so every skin themes    */
/* consistently (see Content/standardtime-skin-variables.css). Structural    */
/* rules (sticky header, sticky fixed column, resize grip, inline editor)    */
/* are skin-independent.                                                     */
/* ------------------------------------------------------------------------- */


/* The scrolling viewport. Downstream scroll-persistence code binds to        */
/* #{gridId}_scroll and reads its scrollTop/scrollLeft, so THIS element must   */
/* be the one that scrolls. It fills the content pane the partial view gives   */
/* it (that pane is `height: calc(100% - 48px)` in RecordsetGridPartialView).  */
.st-grid-scroll {
    width: 100%;
    height: 100%;
    overflow: auto;
    position: relative;
    /* Baseline for the whole grid - see td.st-grid-cell's own user-select:none for why click/right-click
       must never place a native text-selection caret anywhere in this engine. Belt-and-suspenders with
       the per-cell rules below: a click over a pointer-events:none cell (td.st-grid-spacer/-insert-end)
       is NOT hit-tested onto that <td> at all, so its own user-select:none has no effect - the browser's
       caret-from-point placement keeps walking up the DOM past it looking for a selectable ancestor,
       and without this rule lands the false caret on THIS container instead (confirmed via
       getSelection().anchorNode resolving to this div). user-select:none here stops that walk. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    /* Reserve the scrollbar's own width/height up front instead of only carving it out of the content   */
    /* box once a scrollbar actually appears. The old grid's AddRightMostFillerColumn hack existed        */
    /* because Infragistics' internal viewport clipped the rightmost column by the scrollbar's width when */
    /* one appeared; this is the modern CSS equivalent for this engine's plain native scroll container -   */
    /* the layout no longer shifts (and the last column no longer gets clipped) as content grows past the */
    /* point a vertical scrollbar is needed.                                                              */
    /* Browsers without scrollbar-gutter support do NOT fall back to "the same as before this rule        */
    /* existed" - the FILLERCOLUMN hack that used to compensate for this is deleted in the same migration, */
    /* so an unsupported browser would get neither fix. scrollbar-gutter only reached broad support        */
    /* recently (Safari added it in 18.2); the @supports block below restores a plain padding-based        */
    /* reservation for browsers that lack it, so the clipping bug this replaces doesn't quietly come back  */
    /* for exactly the users who can't benefit from the modern property.                                   */
    scrollbar-gutter: stable;
}

/* Fallback for browsers without scrollbar-gutter support (see the corrected comment above). A fixed     */
/* 16px right-padding reservation - the same width AddRightMostFillerColumn used - is a coarser fix than */
/* scrollbar-gutter (it reserves the space even when no scrollbar is actually showing), but that's the   */
/* same trade-off the old DOM-column hack made, just expressed in CSS instead of as a phantom column.    */
@supports not (scrollbar-gutter: stable) {
    .st-grid-scroll {
        padding-right: 16px;
        box-sizing: border-box;
    }
}

/* Single table, fixed layout so <colgroup> widths are authoritative (and so   */
/* resizing one column never reflows the others).                              */
table.st-grid {
    border-collapse: separate;   /* separate: sticky cells keep their own borders */
    border-spacing: 0;
    table-layout: fixed;
    /* The real width is set inline (in px) by StGrid._syncTableWidth = the sum of the column widths.  */
    /* Do NOT use `width: max-content` here: with table-layout:fixed it sizes each column to the       */
    /* greater of its <col> width and its own nowrap content width, so a wide-content column (a long   */
    /* project Name) can never be dragged narrower than its text. `width: auto` is only the pre-JS     */
    /* fallback; the inline pixel width overrides it before first paint.                               */
    width: auto;
    min-width: 100%;             /* fill the pane when the summed width is narrower than it            */
    font-size: var(--st-grid-font-size, calc(10pt + 0.25vw));
    line-height: var(--st-grid-line-height, normal);
    color: var(--st-text-body, #212529);
    background-color: var(--st-bg-body, #ffffff);
}

/* fitCols100Perc grids stretch to exactly the viewport width (no h-scroll).    */
table.st-grid.st-grid-fit {
    width: 100%;
    min-width: 0;
}


/* --------------------------------------------------------------------------- */
/* Header                                                                       */
/* --------------------------------------------------------------------------- */

/* Sticky header stays visible while the body scrolls vertically (the old grid  */
/* used FixedHeaders=true). z-index keeps it above body cells; the fixed corner */
/* cell (sticky header AND sticky column) needs to sit above both, handled      */
/* below.                                                                       */
table.st-grid > thead {
    position: sticky;
    top: 0;
    z-index: 3;
}

th.st-grid-header-cell {
    position: relative;
    box-sizing: border-box;
    /* Extra right padding leaves room for the pin button + resize grip so neither overlaps the header  */
    /* text (padding-right: 8px base + ~12px pin + ~10px resizer, rounded up). Vertical padding is a     */
    /* density var so a compact skin can shrink header row height along with the body rows below.        */
    padding: var(--st-grid-header-padding-y, 4px) 26px var(--st-grid-header-padding-y, 4px) 8px;
    text-align: left;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;                                   /* header click = sort */
    background-color: var(--st-grid-header-bg, #f1f3f5);
    color: var(--st-grid-header-text, #212529);
    border-right: 1px solid var(--st-grid-border, #dee2e6);
    /* Thick accent line under the whole header row (parity with the old Infragistics grid). Matched on   */
    /* the trailing spacer + insert-end header cells below so it runs the full width. Uses the skin accent */
    /* so it adapts per skin.                                                                             */
    border-bottom: 3px solid var(--st-accent, #6366f1);
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.st-grid-header-text {
    pointer-events: none;   /* clicks fall through to the <th> sort handler */
}

/* Sort-direction indicator - rendered only in the one header the server reports as sorted            */
/* (_buildHead), so every other header stays bare. Inline (not absolutely positioned like the pin      */
/* button) so it sits right after the label text and never collides with the pin/resize hit-areas at   */
/* the right edge. Inline SVG with fill=currentColor, same reasoning as the pin button above: a         */
/* Unicode arrow glyph risks Windows font substitution that ignores CSS color (CLAUDE.md's StTree        */
/* caret note). One upward-pointing triangle path covers both directions - .st-grid-sort-desc rotates    */
/* it 180deg instead of shipping a second path.                                                          */
.st-grid-sort-icon {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-left: 4px;
    vertical-align: middle;
    color: var(--st-accent, #6366f1);
    line-height: 0;
}
.st-grid-sort-icon svg {
    display: block;
    width: 100%;
    height: 100%;
}
.st-grid-sort-icon.st-grid-sort-desc {
    transform: rotate(180deg);
}

/* Pin (fix/unfix) toggle - the only user-facing way to fix a column now that Infragistics'          */
/* ShowFixButtons widget chrome is gone. Sits left of the resize grip so the two hit-areas don't      */
/* overlap. A plain circle keeps this dependency-free (no icon font/image), same spirit as the        */
/* CSS border-triangle StTree caret (see CLAUDE.md "StTree caret must be a CSS border-triangle").      */
.st-grid-pin-btn {
    position: absolute;
    top: 50%;
    right: 10px;
    width: 13px;
    height: 13px;
    margin-top: -6px;
    /* The thumbtack is an inline SVG with fill=currentColor (see _buildHead), so `color` skins it and    */
    /* `opacity` dims it. Muted when unpinned; accent + full opacity when pinned.                          */
    color: var(--st-grid-header-text, #212529);
    opacity: 0.4;
    cursor: pointer;
    box-sizing: border-box;
    line-height: 0;                                    /* no extra inline-box height around the SVG */
}
.st-grid-pin-btn svg {
    display: block;
    width: 100%;
    height: 100%;
    /* Unpinned: the tack leans, as if not pushed in. It straightens ("stuck in") when pinned, below. */
    transform: rotate(-30deg);
}
.st-grid-pin-btn:hover {
    opacity: 0.85;
}
.st-grid-pin-btn.st-grid-pin-fixed {
    color: var(--st-accent, #6366f1);
    opacity: 1;
}
.st-grid-pin-btn.st-grid-pin-fixed svg {
    transform: rotate(0deg);                           /* pinned = tack pushed straight in */
}

/* The pin button now carries tabindex="0" (it's the only user-facing way to fix/unfix a column, so it  */
/* can't be mouse-only - see standardtime-gridengine.js's _buildHead). A default browser focus ring on a  */
/* 9px circle sitting inside a header cell is easy to miss or clip against overflow:hidden; give it an     */
/* explicit, larger outline instead so keyboard focus is actually visible here.                             */
.st-grid-pin-btn:focus {
    outline: 2px solid var(--st-focus-ring, #6366f1);
    outline-offset: 2px;
}

/* Resize grip: a thin hit-area pinned to the right edge of each header cell.   */
.st-grid-col-resizer {
    position: absolute;
    top: 0;
    right: 0;
    width: 10px;
    height: 100%;
    cursor: col-resize;
    /* Wider invisible hit target than the 1px visible border it sits on, so a mouse aiming for the
       column edge is less likely to miss onto the header text and trigger a sort instead. Capped at
       10px (not pushed further, and not shifted with a negative `right` to bite into the neighboring
       cell) because th.st-grid-header-cell has overflow:hidden - anything past right:0 would be
       clipped - and because the pin button sits at right:10px/width:13px; going wider here would start
       overlapping its hit zone. */
}
.st-grid-col-resizer:hover {
    background-color: var(--st-accent, #6366f1);
    opacity: 0.5;
}

/* While a drag-resize is in progress, force the resize cursor everywhere and   */
/* prevent accidental text selection.                                          */
body.st-grid-resizing,
body.st-grid-resizing * {
    cursor: col-resize !important;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}


/* Trailing spacer column (auto width) - absorbs the pane's slack width so the real columns always     */
/* render at their exact <col> widths and drag-resize maps 1:1 (see _buildColgroup in the engine).      */
/* pointer-events:none lets a click in the empty header area fall through to the sort handler, which     */
/* then resolves no column and safely no-ops instead of sorting by the spacer. The td variant inherits  */
/* the row background so a SetGridRowStyles custom row color continues to the pane's right edge.         */
th.st-grid-spacer {
    padding: 0;
    background-color: var(--st-grid-header-bg, #f1f3f5);
    border-bottom: 3px solid var(--st-accent, #6366f1);   /* continue the header accent line to the pane's right edge */
    pointer-events: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
td.st-grid-spacer {
    padding: 0;
    background-color: inherit;
    border-bottom: 1px solid var(--st-grid-border, #dee2e6);
    pointer-events: none;
    /* pointer-events:none excludes this <td> from click hit-testing (the click lands on
       tr.st-grid-row instead), but the browser's caret-from-point placement is a separate mechanism
       that ignores pointer-events - left-clicking this empty cell placed a false text-selection
       caret anchored inside it (getSelection().type === "Caret", anchorNode this empty <td>) despite
       never being a real click target. Same fix as td.st-grid-cell above. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}


/* Skinny trailing "insert column at the end" column (see _buildHead / _buildColgroup in the engine).    */
/* Right-click the header to open the column context menu, whose Insert items add a column at the end.    */
/* Unlike the spacer it KEEPS pointer-events so the contextmenu handler can resolve its <th> (a           */
/* left-click sort is guarded off in OnGridHeaderClickEvent). Purely a render-time affordance - its body  */
/* cells carry no st-grid-cell class, so it never participates in selection / edit / resize.              */
col.st-grid-insert-end {
    width: 24px;
}
th.st-grid-insert-end {
    padding: 0;
    text-align: center;
    vertical-align: middle;
    cursor: context-menu;
    background-color: var(--st-grid-header-bg, #f1f3f5);
    border-bottom: 3px solid var(--st-accent, #6366f1);   /* match the header accent line */
    border-left: 1px solid var(--st-grid-border, #dee2e6);
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
th.st-grid-insert-end .st-grid-insert-end-plus {
    font-weight: 700;
    color: var(--st-text-muted, #adb5bd);
    opacity: 0.6;
}
th.st-grid-insert-end:hover .st-grid-insert-end-plus {
    opacity: 1;
    color: var(--st-text-body, #212529);
}
td.st-grid-insert-end {
    padding: 0;
    background-color: inherit;
    border-bottom: 1px solid var(--st-grid-border, #dee2e6);
    pointer-events: none;
    /* Same false-caret fix as td.st-grid-spacer above - pointer-events:none routes the click to
       tr.st-grid-row, but caret-from-point placement still anchors inside this empty <td> unless
       explicitly blocked. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}


/* --------------------------------------------------------------------------- */
/* Body rows + cells                                                            */
/* --------------------------------------------------------------------------- */

/* Gives every row a real (opaque) stylesheet-level default instead of relying on the browser's         */
/* initial background-color value (transparent). td.st-grid-cell's `background-color: inherit` below    */
/* then always inherits something opaque - either this default, or a SetGridRowStyles-applied inline     */
/* override on this same <tr> (SetGridRowStyles sets it via GridRow.css("background-color", ...) in      */
/* standardtime-grid.js, which beats this stylesheet rule the normal way an element's own inline style    */
/* always does). This is also what keeps the pinned/fixed column opaque - see the "Fixed (pinned) column" */
/* section below, which depends on this rule rather than a hardcoded value of its own.                    */
tr.st-grid-row {
    background-color: var(--st-bg-body, #ffffff);
}

/* Group/summary rows (VG_GROUP == "True") get a slightly heavier default shade than plain rows - but      */
/* ONLY as a stylesheet-level DEFAULT, exactly like tr.st-grid-row's own default above. A SetGridRowStyles  */
/* custom row color (e.g. a "Totals" row's orange, or a per-project summary color) is applied as an INLINE */
/* style on this same <tr> (GridRow.css("background-color", ...) in standardtime-grid.js), and an inline    */
/* style on an element always overrides any stylesheet rule for that same element/property, regardless of   */
/* selector specificity - so declaring the alt shade here (on the <tr>, same as the plain-row default)        */
/* rather than as a literal on td.st-grid-cell (see the note below) lets a custom row color win exactly the   */
/* same way it already does for plain rows. tr.st-grid-group-row and tr.st-grid-row have equal specificity    */
/* and both always match the same <tr> (_buildRowHtml adds group as a SECOND class, not a replacement - see    */
/* standardtime-gridengine.js), so source order decides here: this rule comes after tr.st-grid-row's and      */
/* therefore wins for group rows with no custom color, while still losing to either rule's own inline         */
/* override the normal way.                                                                                    */
tr.st-grid-group-row {
    background-color: var(--st-grid-alt-row-bg, #f8f9fa);
}

td.st-grid-cell {
    box-sizing: border-box;
    /* Vertical padding is a density var (see standardtime-skin-variables.css) so a compact skin can   */
    /* shrink row height; horizontal padding stays fixed since it affects column-width math elsewhere. */
    padding: var(--st-grid-cell-padding-y, 3px) 8px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
    border-right: 1px solid var(--st-grid-border, #dee2e6);
    border-bottom: 1px solid var(--st-grid-border, #dee2e6);
    background-color: inherit;   /* inherit the row background so styling set on  */
                                 /* the <tr> (SetGridRowStyles) shows through     */
    /* Left at the default user-select:auto, right-clicking the cell's value text (the .searchableitem
       span with the actual data - confirmed via getSelection().type === "Caret" anchored in its text
       node) placed a false text-selection caret, same bug class as the other non-editable UI chrome
       already fixed. Grid copy does not depend on native selection - Ctrl+C reads cell text
       programmatically (_buildClipboardText/_clipboardCellText in standardtime-gridengine.js) - so
       there is no reason to keep native drag-select enabled here the way dialog/toast message text and
       property-grid values are (those have no equivalent programmatic copy path). */
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* Row hover and cell selection below set an opaque LITERAL background-color directly on td.st-grid-cell   */
/* (not "inherit"), so - unlike the plain-state inherit rule above - neither of these two states can ever   */
/* show a SetGridRowStyles custom row color underneath: the literal value always wins over inheritance for  */
/* the element it's declared on, regardless of what the parent <tr>'s own background resolves to. This is   */
/* intentional here (hover/selection are meant to read as a consistent, theme-driven color so the            */
/* interaction state itself stays legible), not a specificity fight with the row's custom color - there      */
/* isn't one; the td's own literal declaration is used unconditionally, the same way it would be even if the */
/* <tr> had no inline style at all. Group/summary rows are DIFFERENT - see the rule below - a custom row      */
/* color must show through on them (e.g. a "Totals" row), so that state deliberately does NOT follow this     */
/* literal-background pattern.                                                                              */
tr.st-grid-row:hover > td.st-grid-cell {
    background-color: var(--st-grid-hover-bg, #eef);
    color: var(--st-grid-hover-text, inherit);
}

/* Group / summary rows (VG_GROUP == "True"): bold text so the hierarchy reads. The background is NOT      */
/* declared here (unlike hover/selected/edited below) - it comes from td.st-grid-cell's own `inherit` rule    */
/* above, picking up whatever tr.st-grid-group-row resolves to (its own alt-shade default, or a              */
/* SetGridRowStyles inline override - see the tr.st-grid-group-row rule's comment). A literal background      */
/* here would permanently hide any custom row color on every group/summary row (e.g. a "Totals" row's         */
/* orange), which is the bug this comment used to describe as intentional and isn't.                          */
tr.st-grid-group-row > td.st-grid-cell {
    font-weight: 600;
}

/* Selected cell highlight (Mode = Cell selection). */
td.st-grid-cell.st-grid-cell-selected {
    background-color: var(--st-accent, #6366f1);
    color: var(--st-accent-text, #ffffff);
    outline: 1px solid var(--st-accent, #6366f1);
    outline-offset: -1px;
}

/* Selection must stay visible even when the row is also hovered or is a group/summary row. Without       */
/* these, it silently isn't: `tr.st-grid-row:hover > td.st-grid-cell` above is (0,0,3,2) and                */
/* `tr.st-grid-group-row > td.st-grid-cell` is (0,0,2,2), both of which outrank the plain                   */
/* `.st-grid-cell-selected` rule's (0,0,2,1) - so a selected cell loses its highlight the instant the       */
/* pointer sits over its row (the single most likely moment for this to happen, right after clicking to     */
/* select), or whenever the selected cell happens to be in a group/summary row. These compound rules         */
/* out-specificity both cases ((0,0,4,2) and (0,0,3,2) respectively) so selection always wins.               */
tr.st-grid-row:hover > td.st-grid-cell.st-grid-cell-selected,
tr.st-grid-group-row > td.st-grid-cell.st-grid-cell-selected {
    background-color: var(--st-accent, #6366f1);
    color: var(--st-accent-text, #ffffff);
}

/* Every cell now carries tabindex="-1" and is focused programmatically on selection (see             */
/* selectCellElement in standardtime-gridengine.js - needed so F2/Enter has something to bubble from). */
/* Suppress the browser's default focus ring: the selected-cell highlight above already communicates   */
/* this, and a native outline on every clicked cell would be a new, unwanted visual side-effect.        */
td.st-grid-cell:focus {
    outline: none;
}
td.st-grid-cell.st-grid-cell-selected:focus {
    outline: 1px solid var(--st-focus-ring, #6366f1);
    outline-offset: -1px;
}

/* Edited cell: the yellow "changed but not yet reloaded" flag. Class name       */
/* (editedgridcell) is unchanged from the igGrid era so existing JS that adds it */
/* keeps working.                                                               */
td.st-grid-cell.editedgridcell {
    background-color: var(--st-grid-edited-bg, #fff3cd);
    color: var(--st-grid-edited-text, #000000);
}

/* Same specificity fight as the selected-cell rules above (editedgridcell is also (0,0,2,1)) and the     */
/* same fix: keep the "unsaved edit" flag visible over hover/group tinting rather than letting it silently */
/* disappear in exactly the states a user is likely to be in right after editing a cell.                    */
tr.st-grid-row:hover > td.st-grid-cell.editedgridcell,
tr.st-grid-group-row > td.st-grid-cell.editedgridcell {
    background-color: var(--st-grid-edited-bg, #fff3cd);
    color: var(--st-grid-edited-text, #000000);
}


/* --------------------------------------------------------------------------- */
/* Inline editor                                                                */
/* --------------------------------------------------------------------------- */

td.st-grid-cell.st-grid-cell-editing {
    padding: 0;
}

.st-grid-cell-input {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    min-height: var(--st-grid-cell-editor-min-height, 22px);
    padding: 1px 7px;
    border: 2px solid var(--st-accent, #6366f1);
    font: inherit;
    color: var(--st-text-body, #212529);
    background-color: var(--st-bg-body, #ffffff);
    outline: none;
}


/* --------------------------------------------------------------------------- */
/* Fixed (pinned) column - only the "Name" column, matching the old grid        */
/* --------------------------------------------------------------------------- */
/* Horizontal sticky pins the column to the left while the body scrolls right.   */
/* left:0 works because it is the only fixable column; a multi-column fix would  */
/* need cumulative left offsets.                                                 */

.st-grid-col-fixed {
    position: sticky;
    left: 0;
    z-index: 2;                                        /* above normal body cells */
    box-shadow: 1px 0 0 var(--st-grid-border, #dee2e6);
}

/* A literal `background-color` declared directly on td.st-grid-cell.st-grid-col-fixed would stop the      */
/* pinned column being transparent, but it can never reflect a SetGridRowStyles custom row color either -   */
/* unlike every other column in the same row (which gets the color via inherit), the pinned column would    */
/* sit at a fixed value regardless of what color the rest of the row was set to. The fix lives upstream:    */
/* `tr.st-grid-row` (see "Body rows + cells" above) carries its own opaque stylesheet-level default, so      */
/* plain `background-color: inherit` on td.st-grid-cell is *always* opaque - either that default, or        */
/* SetGridRowStyles' inline override on the same <tr> - with no separate rule needed here at all.            */
/* td.st-grid-cell's own inherit rule already covers .st-grid-col-fixed cells (they carry both classes),     */
/* so no override is declared in this section for the plain (non-hover/group/selected) state.                */

/* A fixed HEADER cell is sticky in both axes (the top-left corner), so it must   */
/* out-rank both the sticky header (z-index:3) and a sticky body column (z:2).    */
/* Header rows have no SetGridRowStyles custom coloring, so a literal background is fine here.   */
/* position:sticky + left:0 are RESTATED here (not just inherited from .st-grid-col-fixed) because      */
/* `th.st-grid-header-cell { position: relative }` above is more specific than `.st-grid-col-fixed`, so  */
/* without this the pinned header cell stays `relative` and scrolls away horizontally while the body     */
/* cells (td.st-grid-cell sets no position, so .st-grid-col-fixed's sticky wins there) stay pinned - the */
/* header then appears to scroll "into" the pinned column instead of being clipped by it.                */
th.st-grid-header-cell.st-grid-col-fixed {
    position: sticky;
    left: 0;
    z-index: 4;
    background-color: var(--st-grid-header-bg, #f1f3f5);
}

/* No hover/group/selected overrides needed for .st-grid-col-fixed: those three states (see "Body rows +  */
/* cells" above) already set an opaque LITERAL background directly on td.st-grid-cell, which every fixed-   */
/* column cell also matches (it carries both classes) - a separate .st-grid-col-fixed variant of each        */
/* would just repeat the identical value; they don't use "inherit" in the first place, so the specificity    */
/* problem the plain-state fix above addresses never applies to these three.                                 */


/* --------------------------------------------------------------------------- */
/* Frozen rows (COL_FROZENROW) - top and bottom                                  */
/* --------------------------------------------------------------------------- */
/* See FrozenRows.md (Feature enhancement md's/Frozen rows) for the full spec. Every <td>                 */
/* in a frozen row is individually sticky - NOT the <tr> itself. Table-row sticky positioning has         */
/* inconsistent cross-engine support, and every other sticky element in this stylesheet (the header,      */
/* the fixed Name column) is already cell-level for the same reason, so this stays consistent with that.  */
/* The offset is a CSS custom property the engine computes per row in _syncFrozenRowOffsets: the top      */
/* offset is the header's height plus the height of any earlier row in the same top block; the bottom     */
/* offset is the height of any later row in the same bottom block (nothing below the tbody needs to be    */
/* cleared the way the header clears space above the top block, so the last row in a bottom block gets    */
/* bottom: 0 directly).                                                                                   */
/* Opacity is already guaranteed and needs no rule here: tr.st-grid-row / tr.st-grid-group-row give every */
/* row an opaque stylesheet default (or SetGridRowStyles' inline override, e.g. the Totals row's orange), */
/* and all three <td> kinds a row can contain - td.st-grid-cell, td.st-grid-spacer, td.st-grid-insert-end */
/* - declare background-color: inherit, so a frozen row fully occludes the rows scrolling beneath it.     */
.st-grid-frozen-top-row > td {
    position: sticky;
    top: var(--st-grid-frozen-top, 0px);
    z-index: 1;                                        /* above normal scrolling body cells */
}
.st-grid-frozen-bottom-row > td {
    position: sticky;
    bottom: var(--st-grid-frozen-bottom, 0px);
    z-index: 1;
}

/* Real data cells (not the trailing spacer/insert-end filler cells, which only need the base sticky      */
/* rule above so they move with the row) sit one tier above that base rule - matches the existing         */
/* sticky-column tier (.st-grid-col-fixed, z-index: 2) they can appear alongside within the same row.     */
.st-grid-frozen-top-row > td.st-grid-cell,
.st-grid-frozen-bottom-row > td.st-grid-cell {
    z-index: 2;
}

/* The Name column cell of a frozen row is sticky on BOTH axes at once: left:0 comes from                 */
/* .st-grid-col-fixed above, top/bottom comes from the rules above - CSS applies both independently       */
/* since they set different properties, no conflict. This is the same "frozen corner" idea as             */
/* th.st-grid-header-cell.st-grid-col-fixed (which does this at the header/column intersection), just at  */
/* the frozen-row/column intersection instead. Needs to out-rank the plain-cell tier (2) it straddles,    */
/* while staying below the sticky header (3) and the header's own corner (4) - those never occupy the     */
/* same screen space as a body-row corner, but leaving headroom below them costs nothing.                 */
.st-grid-frozen-top-row > td.st-grid-cell.st-grid-col-fixed,
.st-grid-frozen-bottom-row > td.st-grid-cell.st-grid-col-fixed {
    z-index: 3;
}

/* Shared by every registered frozen-wide row (StGrid.registerFrozenWideRow - standardtime-gridengine.js).
   No height/min-height on purpose - see FrozenRowMiniWipResizable-COMPLETE.md and
   FrozenRowClockedInOut.md's "Resizable row" section (bug #1): a <td>'s own explicit height always wins
   as a floor for the whole row in table layout, no matter how small a later drag/restore asks the <tr> to
   be. Each renderer's own defaultHeightPx is applied once as the <tr>'s own inline style instead
   (_mountFrozenWideRows). Intentionally dark in EVERY skin via the generic --st-frozenrow-bg/-text pair
   (standardtime-skin-variables.css) - a shop-floor/status-strip look, not themed grid content. */
.st-grid-frozenwide-cell {
    padding: 0 !important;
    background: var(--st-frozenrow-bg, #343c4a);
    /* Needed here (not just on each renderer's own mount) so the resize handle - a sibling <div> appended
       directly into this <td> by StGrid._buildRowResizeHandleHtml, not a descendant of the mount -
       inherits the light frozen-row text color via currentColor instead of the grid's normal dark body
       text, which reads as near-invisible against this row's dark background. */
    color: var(--st-frozenrow-text, #f4f6f8);
    border: none;
    overflow: hidden;
}

/* Hairline separator on the cell's own free edge (bottom for a top-frozen row, top for a bottom-frozen
   one) - without it, two stacked frozen rows (e.g. Clocked-In/Out directly above Mini WIP, both sharing
   the same --st-frozenrow-bg) read as one continuous block with no visible boundary between them, and a
   single frozen row reads as fused to the normal grid body below/above it. An inset box-shadow rather than
   a real `border` - a real border adds to the cell's box in table layout and would need `box-sizing:
   border-box` to avoid growing the row by 1px, where `box-shadow: inset` is guaranteed zero layout impact,
   matching this rule's own "no height/min-height" discipline above. Fixed low-opacity white rather than a
   skin variable - this strip is always dark by construction in every skin (see the rule above), so a faint
   white hairline reads correctly against it regardless of which skin is active. */
.st-grid-frozen-top-row > td.st-grid-frozenwide-cell {
    box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.10);
}
.st-grid-frozen-bottom-row > td.st-grid-frozenwide-cell {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}


/* --------------------------------------------------------------------------- */
/* Generic frozen-row resize handle (COL_ROWRESIZABLE) - see                     */
/* Feature enhancement md's/Frozen rows/FrozenRowMiniWipResizable.md             */
/* --------------------------------------------------------------------------- */
/* Anchors the resize handle (position: absolute) to whichever cell hosts it - the row's last visible
   column for a normal frozen row, or its one colspan cell for a Mini-WIP-style row. Does NOT touch
   overflow - the handle is sized/positioned to stay fully inside this cell's existing overflow:hidden
   box (see FrozenRowMiniWipResizable.md's "Design decisions" for why a full-row-width bar was rejected).
   Deliberately declares NO `position` here - see the comment below for why that would be actively
   harmful, not just redundant, on this particular selector. */
td.st-grid-row-resize-anchor {
    /* intentionally empty - do not add `position: relative` (or any position) here. Every cell this
       class is applied to is already a `.st-grid-frozen-top-row > td` or `.st-grid-frozen-bottom-row >
       td`, which sets `position: sticky` at the exact same specificity (0,1,1) as
       `td.st-grid-row-resize-anchor` itself. Adding `position: relative` here would, on whichever rule
       is physically later in the stylesheet, REPLACE that sticky positioning instead of just adding a
       (redundant) containing block for the handle's `position: absolute` - `position: sticky` already
       establishes that containing block on its own, so no separate `position` declaration is needed at
       all. This is the same same-specificity cascade hazard `th.st-grid-header-cell.st-grid-col-fixed`
       above already had to be explicitly patched against once in this file. */
}

.st-grid-row-resize-handle {
    position: absolute;
    right: 2px;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    cursor: ns-resize;
    touch-action: none; /* prevents the browser's own touch-scroll gesture from fighting the drag on touch/pen */
    opacity: 0.35;
    background-color: currentColor;
    /* Three thin horizontal bars via a repeating mask - avoids a Unicode glyph per CLAUDE.md's "never
       render UI arrows as Unicode glyph characters" rule (same class of problem: some Windows font
       configurations substitute a fixed-color icon font that ignores currentColor). */
    -webkit-mask-image: repeating-linear-gradient(to bottom, black 0, black 2px, transparent 2px, transparent 5px);
    mask-image: repeating-linear-gradient(to bottom, black 0, black 2px, transparent 2px, transparent 5px);
}
.st-grid-row-resize-handle[data-direction="s"] { bottom: 2px; }
.st-grid-row-resize-handle[data-direction="n"] { top: 2px; }
.st-grid-row-resize-handle:hover,
.st-grid-row-resize-handle:active {
    opacity: 0.85;
}


/* --------------------------------------------------------------------------- */
/* Generic frozen-row Close/Minimize/Restore controls (any registered            */
/* frozen-wide row - see StGrid.registerFrozenWideRow, standardtime-gridengine.js) */
/* Feature enhancement md's/Frozen rows/CloseMinimize.svg + Restore.svg are the  */
/* original sketches this was built from.                                       */
/* --------------------------------------------------------------------------- */
.st-frozenrow-controls {
    position: absolute;
    top: 4px;
    right: 4px;
    display: flex;
    align-items: center;
    gap: 2px;
    z-index: 2; /* above this row's own mount content */
}
/* Bottom-frozen rows put the resize handle in the top-right corner (data-direction="n") - mirror this
   cluster to the bottom-right instead, so the two never overlap. See _buildFrozenRowControlsHtml's own
   comment (standardtime-gridengine.js). */
.st-frozenrow-controls-bottom {
    top: auto;
    bottom: 4px;
}

.st-frozenrow-min-btn,
.st-frozenrow-restore-btn,
.st-frozenrow-close-btn {
    box-sizing: border-box;
    width: 16px;
    height: 16px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: 3px;
    color: var(--st-frozenrow-text, #f4f6f8);
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
}
.st-frozenrow-min-btn   { font-size: 10px; }
.st-frozenrow-close-btn { font-size: 12px; } /* close reads slightly larger, matches .st-dialog-close-btn's own convention */

.st-frozenrow-min-btn:hover,
.st-frozenrow-restore-btn:hover,
.st-frozenrow-close-btn:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.15);
}

/* Restore only ever shows once the row is minimized (see the modifier block below) - hidden by default
   so a freshly-rendered, non-minimized row never shows it alongside Minimize/Close. */
.st-frozenrow-restore-btn {
    display: none;
}

/* Minimized state - collapse everything in the cell down to a thin sliver except the controls cluster
   itself, and swap which button that cluster shows (Restore only). Toggled by StGrid._setFrozenRowMinimized. */
tr.st-frozenwide-minimized > td.st-grid-frozenwide-cell > *:not(.st-frozenrow-controls) {
    display: none;
}
tr.st-frozenwide-minimized .st-frozenrow-min-btn,
tr.st-frozenwide-minimized .st-frozenrow-close-btn {
    display: none;
}
tr.st-frozenwide-minimized .st-frozenrow-restore-btn {
    display: flex;
}


/* --------------------------------------------------------------------------- */
/* Cell content helpers                                                          */
/* --------------------------------------------------------------------------- */

/* The collapse/expand rocker image in hierarchy (group) rows. */
td.st-grid-cell .CollapseExpandImg {
    cursor: pointer;
    flex: 0 0 16px;
    margin-right: 2px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* Gantt placeholder cell keeps its intrinsic sizing; the gantt renderer         */
/* (standardtime-gantt.js) draws into it after render.                           */
td.st-grid-cell .ganttcelldiv {
    position: relative;
    height: 100%;
    min-height: 20px;
}

/* Shared wrapper for text/image/checkbox/objectHtml cell content (_renderText, _renderImage,           */
/* _renderCheckbox, _renderObjectHtml in standardtime-gridengine.js). white-space:nowrap here matches    */
/* what td.st-grid-cell already declares (white-space is inherited, so this is belt-and-suspenders, not  */
/* load-bearing on its own) - centralizing it here replaces what used to be an identical inline          */
/* style="white-space:nowrap;" string repeated on every single cell of every row.                        */
.st-grid-cell-content {
    white-space: nowrap;
}

/* hAlign modifiers (_renderText) - replace the old per-cell inline text-align. */
.st-grid-cell-content.st-align-center {
    text-align: center;
}
.st-grid-cell-content.st-align-right {
    text-align: right;
}

/* Image cell (_renderImage) - centers the image within its cell, replacing the old per-cell inline
   style="display:block;margin:auto;" on the <img>. */
.st-grid-cell-image > img {
    display: block;
    margin: auto;
}

/* Checkbox cell (_renderCheckbox) - centers the checkbox within its cell, replacing the old per-cell
   inline style="display:block;margin:auto;" on the <input>. */
.st-grid-cell-checkbox > input[type="checkbox"] {
    display: block;
    margin: auto;
}

/* --------------------------------------------------------------------------- */
/* Mini WIP frozen row (COL_MINIWIP) - shop-floor summary strip                  */
/* --------------------------------------------------------------------------- */
/* See FrozenRowMiniWip.md (Feature enhancement md's/Frozen rows) for the full spec. Sticky        */
/* positioning is inherited for free from FrozenRows-COMPLETED.md's .st-grid-frozen-{top,bottom}-row   */
/* > td rule (this row also carries that class) - only the colspan cell's own look lives here.         */
/* Intentionally dark in EVERY skin, light or dark - this is a shop-floor status strip meant to be read */
/* up close on one screen, not themed grid content. Background/text use the generic --st-frozenrow-bg / */
/* --st-frozenrow-text pair (standardtime-skin-variables.css) rather than the general grid --st-* vars -  */
/* every skin overrides that pair to its own dark --st-tab-active-bg/--st-tab-text color, so this row    */
/* still reads as "always dark" while picking up the active skin's hue. No @media (prefers-color-scheme) */
/* branching needed - the pair is dark by construction in every skin, including the default. */

/* Registers --pct as an animatable number so .st-miniwip-ring's transition (below) actually interpolates
   frame-by-frame instead of flipping instantly. Unsupported browsers (pre-2022 Safari) simply skip the
   transition and show the final value immediately - a graceful, non-broken fallback, not an error. */
@property --pct {
    syntax: '<number>';
    inherits: true;
    initial-value: 0;
}

/* The outer colspan cell no longer gets its own per-feature rule - StGrid now emits one shared class,
   .st-grid-frozenwide-cell (standardtime-gridengine.css), for every registered row type's colspan <td>,
   including this one (byte-for-byte the same properties this rule used to declare here). Only the mount
   and everything below it - the part that's genuinely specific to Mini WIP's own content - stays here. */

.st-miniwip-mount {
    /* `position: absolute; inset: 0` instead of `height/width: 100%` - a <td>'s default
       `vertical-align: middle` (the browser's own UA default, not set anywhere in this stylesheet) makes
       a `height: 100%` child shrink-wrap to its own content and get vertically CENTERED in the cell
       instead of stretching to fill it, once the cell's own height comes purely from the resizable <tr>'s
       inline style rather than a literal CSS `height` on the cell itself (see
       FrozenRowMiniWipResizable-COMPLETE.md and the shared `.st-grid-frozenwide-cell` rule's own comment,
       standardtime-gridengine.css, for why the cell no longer sets one). Symptom this fixed: the countdown
       sliver (`position: absolute; bottom: 0` relative to THIS element) drifted up into the middle of a
       resized row instead of staying flush against its true bottom edge, because the mount box it's
       anchored to was shorter than the row and floating in its vertical center. `.st-grid-frozenwide-cell`
       is always `position: sticky` (every Mini WIP row is unconditionally a frozen row - InsertMiniWipRow
       always sets COL_FROZENROW), so it's always a valid containing block for this `inset: 0` - no separate
       `position: relative` needed on the cell itself. */
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    display: flex;
    align-items: stretch;
    padding: 8px 12px;
    gap: 10px;
    overflow: hidden;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
    color: var(--st-frozenrow-text, #f4f6f8);
    font-family: inherit;
}

/* The jobs area is the ONE part of this row expected to overflow routinely - 0 to 100+ jobs (see the   */
/* spec's Goal section) all have to fit here, real estate permitting, while .st-miniwip-viewall-btn      */
/* below stays a fixed-size flex sibling that never shrinks or scrolls away regardless of job count.     */
.st-miniwip-jobs {
    flex: 1 1 auto;
    min-width: 0;                  /* required for flex children to actually be allowed to shrink/scroll */
    display: flex;
    align-items: center;
    gap: 8px;
}

.st-miniwip-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    opacity: 0.6;
    font-style: italic;
    font-size: 12px;
}

/* "View Full WIP" - pinned outside the scrolling jobs area, opens the real WIP page in the same       */
/* project/job grouping mode this row's own job aggregation mirrors (ShowWipJobGridView(), see          */
/* standardtime-showcontent.js:90 and this spec's "What already exists" section). Icon is an inline SVG  */
/* with stroke="currentColor" per CLAUDE.md's "never render UI arrows as Unicode glyphs" rule - some     */
/* Windows font configurations substitute a fixed-color icon font for an arrow character that ignores    */
/* the CSS color property entirely.                                                                      */
/* Stacks the toggle and "Full WIP" buttons vertically instead of side by side - narrower footprint, more
   width left for the scrolling jobs area. Same wrapper shape .st-clockedinout-btns uses (standardtime-
   frozenrowclockedinout.css) - align-items:stretch (the flex column default) makes both buttons match the
   wider one's width, so their edges line up; the mount's own align-items:stretch gives this wrapper the
   row's full height, and justify-content:center here centers the pair within it. */
.st-miniwip-btns {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
}

/* Same base pill look shared with the Running/Idle/Both toggle button below - the toggle is the Mini
   WIP-side symmetric counterpart to Clocked-In/Out's own toggle (see standardtime-frozenrowclockedinout.css
   and _miniWipEnsureShell's own doc comment, standardtime-frozenrowminiwip.js). */
.st-miniwip-viewall-btn,
.st-miniwip-toggle-btn {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 6px 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--st-frozenrow-text, #f4f6f8);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-miniwip-viewall-btn:hover,
.st-miniwip-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.16);
}
.st-miniwip-viewall-btn:active,
.st-miniwip-toggle-btn:active {
    background: rgba(255, 255, 255, 0.24);
}
.st-miniwip-viewall-icon,
.st-miniwip-viewall-btn svg,
.st-miniwip-toggle-btn svg {
    flex: 0 0 auto;
}
/* Mode-active accent - same color language the ring/status dot already use elsewhere in this row (green =
   running, gray = idle/not-running - see _miniWipStatusColor). "Both" (the default) is deliberately
   unaccented, same rationale Clocked-In/Out's own default "in" state being unaccented documents - only the
   non-default states get a color shift. */
.st-miniwip-toggle-btn.st-miniwip-mode-running {
    border-color: rgba(61, 220, 132, 0.5);
    color: #3ddc84;
}
.st-miniwip-toggle-btn.st-miniwip-mode-idle {
    border-color: rgba(138, 147, 161, 0.5);
    color: #8a93a1;
}

/* Tier 1: ring cards - one per job, name/hours/percent/last-task, single non-wrapping row.             */
/* _miniWipPickTier only ever chooses "rings" when every job already fits with no scrolling - overflow-x */
/* here is defensive only (guards a rare mis-measurement/reflow-timing edge case), not how this tier is  */
/* meant to display an over-count of jobs. Too many jobs downgrades to the chips tier instead of         */
/* scrolling this one - a ring card sliced in half by a scroll boundary would read as broken UI.         */
.st-miniwip-jobs.st-miniwip-tier-rings {
    overflow-x: auto;
    overflow-y: hidden;
}
.st-miniwip-card {
    flex: 0 0 auto;
    width: 104px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 6px 4px;
    border-radius: 8px;
    cursor: pointer;   /* click opens a new Time Logs tab for this job - see _miniWipOnJobCardClick */
    background: linear-gradient(160deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.03));
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    transition: transform 220ms ease, box-shadow 220ms ease;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-miniwip-card:hover {
    transform: perspective(400px) rotateX(4deg) translateY(-2px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.45);
}
.st-miniwip-ring {
    width: 54px;
    height: 54px;
    border-radius: 50%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    /* --pct (0-100) and --ring-color set inline per job by _miniWipRenderRings */
    background: conic-gradient(var(--ring-color, #3ddc84) calc(var(--pct, 0) * 1%), rgba(255, 255, 255, 0.12) 0);
    transition: --pct 700ms cubic-bezier(0.22, 1, 0.36, 1);
}
.st-miniwip-ring::before {
    content: "";
    position: absolute;
    inset: 5px;
    border-radius: 50%;
    background: var(--st-frozenrow-bg, #343c4a);   /* matches the shared .st-grid-frozenwide-cell background so the ring's hole blends in */
}
.st-miniwip-ring-label {
    position: relative;
    z-index: 1;
    font-size: 13px;
    font-weight: 700;
}
.st-miniwip-card-name {
    margin-top: 4px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11px;
    font-weight: 600;
    text-align: center;
}
.st-miniwip-card-sub {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 9.5px;
    text-align: center;
    opacity: 0.75;
}
.st-miniwip-card.st-miniwip-running .st-miniwip-card-sub {
    color: #3ddc84;
    opacity: 1;
}
/* CSS-drawn dot (not a Unicode glyph) so it always takes the running color - some Windows font   */
/* configs substitute a colored icon font for solid-shape glyphs (●, ▶, etc.) that ignores CSS     */
/* `color`, same failure mode as the StTree caret/Gantt nav arrows (see CLAUDE.md).                */
.st-miniwip-running-dot {
    display: inline-block;
    width: 5px;
    height: 5px;
    margin-right: 2px;
    background: currentColor;
    border-radius: 50%;
    vertical-align: middle;
}

/* Pulsing glow on a card with an active timer - deliberately slow (2.4s) and low-amplitude, since a    */
/* shop-floor status row left on screen for hours needs a glow that reads as "alive" at a glance, not    */
/* one that's distracting to work next to all day.                                                       */
@keyframes st-miniwip-pulse {
    0%, 100% { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 0 rgba(61, 220, 132, 0.35); }
    50%      { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 8px 2px rgba(61, 220, 132, 0.35); }
}
.st-miniwip-card.st-miniwip-running {
    animation: st-miniwip-pulse 2400ms ease-in-out infinite;
}

/* Ring fill-in on load / smooth transition on update - see _miniWipRenderRings' double-rAF pass, which */
/* paints the starting --pct value first so this transition always has a real "from -> to" to animate.  */
@keyframes st-miniwip-card-enter {
    from { opacity: 0; transform: scale(0.85) translateY(4px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}
.st-miniwip-card-entering {
    animation: st-miniwip-card-enter 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes st-miniwip-flash {
    0%   { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 0 rgba(255, 255, 255, 0.5); }
    40%  { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 4px rgba(255, 255, 255, 0.25); }
    100% { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 0 rgba(255, 255, 255, 0); }
}
.st-miniwip-card-updated {
    animation: st-miniwip-flash 900ms ease-out both;
}

/* Tier 2: compact chips - name + percent + a plain status dot, no ring geometry, for job counts that   */
/* don't fit as full ring cards but are still few enough to name individually. Clickable the same way   */
/* ring cards are - click opens a new Time Logs tab for this job (see _miniWipOnJobCardClick and the     */
/* shared delegated listener in _miniWipEnsureShell, standardtime-frozenrowminiwip.js).                  */
.st-miniwip-jobs.st-miniwip-tier-chips {
    flex-wrap: wrap;
    align-content: center;
    overflow: hidden;
}
.st-miniwip-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    font-size: 11px;
    white-space: nowrap;
    cursor: pointer;
    transition: background 120ms ease;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-miniwip-chip:hover {
    background: rgba(255, 255, 255, 0.16);
}
.st-miniwip-chip:active {
    background: rgba(255, 255, 255, 0.24);
}
.st-miniwip-chip-dot {
    width: 8px;
    height: 8px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--dot-color, #999);
}

/* Tier 3: CSV-style fallback - a single scrolling line of text, for job counts too high for either of  */
/* the above to stay legible in a ~168px-tall strip.                                                    */
.st-miniwip-jobs.st-miniwip-tier-csv {
    align-items: center;
    overflow-x: auto;
    white-space: nowrap;
    font-family: Consolas, "Courier New", monospace;
    font-size: 12px;
}
.st-miniwip-csv-sep {
    margin: 0 6px;
    opacity: 0.5;
}

/* Hairline refresh-countdown sliver - empties over MINIWIP_REFRESH_MS and resets every time a poll     */
/* actually fires, so the row always shows at a glance roughly how stale its current numbers are.        */
.st-miniwip-countdown {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
}
.st-miniwip-countdown-fill {
    height: 100%;
    width: 100%;
    background: rgba(255, 255, 255, 0.35);
    transform-origin: left;
}
@keyframes st-miniwip-countdown-shrink {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

@media (prefers-reduced-motion: reduce) {
    .st-miniwip-ring { transition-duration: 0.01ms; }
    .st-miniwip-card-entering { animation: none; }
    .st-miniwip-card-updated { animation: none; }
    .st-miniwip-card.st-miniwip-running { animation: none; }
    .st-miniwip-card:hover { transform: none; }
    .st-miniwip-countdown-fill { animation-duration: 0.01ms !important; }
}

/* --------------------------------------------------------------------------- */
/* Clocked-In / Not-Clocked-In frozen row (COL_CLOCKEDIN / COL_NOTCLOCKEDIN)     */
/* --------------------------------------------------------------------------- */
/* See FrozenRowClockedInOut.md. Sticky positioning AND the outer cell's own look (no height, dark        */
/* --st-frozenrow-* background/text, no border, overflow: hidden) are both inherited for free from the    */
/* shared .st-grid-frozen-{top,bottom}-row > td / .st-grid-frozenwide-cell rules (standardtime-           */
/* gridengine.css) every registered frozen-wide row shares. Only this row's own mount and its inner       */
/* content live in this file.                                                                              */

.st-clockedinout-mount {
    /* `position: absolute; inset: 0` instead of `height/width: 100%` - a <td>'s default
       `vertical-align: middle` (the browser's own UA default, not set anywhere in this stylesheet) makes
       a `height: 100%` child shrink-wrap to its own content and get vertically CENTERED in the cell
       instead of stretching to fill it, once the cell's own height comes purely from the resizable <tr>'s
       inline style rather than a literal CSS height on the cell itself. This is the same structural
       exposure Mini WIP's own mount hit once its cell's literal CSS height was removed - applied here
       pre-emptively. `.st-grid-frozenwide-cell` is always `position: sticky` (every registered frozen-wide
       row is unconditionally a frozen row - InsertClockedInOutRow always sets COL_FROZENROW), so it's
       always a valid containing block for this `inset: 0` - no separate `position: relative` needed on
       the cell itself. */
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    display: flex;
    align-items: stretch;
    padding: 8px 12px;
    gap: 10px;
    overflow: hidden;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    color: var(--st-frozenrow-text, #f4f6f8);
    font-family: inherit;
}

.st-clockedinout-users {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.st-clockedinout-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    opacity: 0.6;
    font-style: italic;
    font-size: 12px;
}

/* The two pinned-corner buttons stack vertically in this column wrapper instead of sitting side by side -
   narrower footprint, more width left for the scrolling users area. The wrapper is the flex child of
   .st-clockedinout-mount (flex:0 0 auto, vertically centered via the mount's own align-items:stretch plus
   this justify-content:center along the column axis); the buttons inside it no longer need their own
   align-self since they're not direct children of the row anymore. align-items:stretch (the flex column
   default) makes both buttons match the wider one's width, so their edges line up. */
.st-clockedinout-btns {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
}

/* Toggle button and the "Employee Status" link button - both pinned outside the scrolling users area,
   same "never scrolls away" treatment .st-miniwip-viewall-btn gets, and both share this one base pill
   look. Label text ("Clocked In"/"Clocked Out") carries the toggle's mode indication; the toggle's icon
   itself does not change shape between modes. The Employee Status button is static (no mode, no accent
   class) - it just opens ShowWipEmployeeGridView(), same as Mini WIP's own "Full WIP" button opens
   ShowWipJobGridView(). */
.st-clockedinout-toggle-btn,
.st-clockedinout-viewall-btn {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 6px 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--st-frozenrow-text, #f4f6f8);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.st-clockedinout-toggle-btn:hover,
.st-clockedinout-viewall-btn:hover { background: rgba(255, 255, 255, 0.16); }
.st-clockedinout-toggle-btn:active,
.st-clockedinout-viewall-btn:active { background: rgba(255, 255, 255, 0.24); }
/* Mode-active accent - a color shift instead of a second icon shape, same rationale documented in the JS
   file. Three states now (Clocked In / Clocked Out / Both) cycled by one click each - Clocked In (the
   default) uses the row's plain, unaccented color; .st-clockedinout-mode-out and .st-clockedinout-mode-both
   are the other two. */
.st-clockedinout-toggle-btn.st-clockedinout-mode-out {
    border-color: rgba(234, 179, 8, 0.5);
    color: #eab308;
}
.st-clockedinout-toggle-btn.st-clockedinout-mode-both {
    border-color: rgba(56, 189, 248, 0.5);
    color: #38bdf8;
}

/* Tier 1: timer-icon cards, one per user, single non-wrapping row. Icon-over-username-over-elapsed-hours,
   not an initials avatar - initials aren't a usable fallback when Fullname is blank (the common case),
   so the running/not-running state itself is the card's primary visual instead of a decorative ring. */
.st-clockedinout-users.st-clockedinout-tier-cards {
    overflow-x: auto;
    overflow-y: hidden;
}
/* Card look copied verbatim from standardtime-frozenrowminiwip.css's .st-miniwip-card (same width, same
   gradient/blur/border/shadow, same hover tilt) so both shop-floor cards - job rings and user timer icons -
   read as one consistent style. Only the size class differs by content (icon vs. ring), not the card shell. */
.st-clockedinout-card {
    flex: 0 0 auto;
    width: 104px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 6px 4px;
    border-radius: 8px;
    cursor: pointer;
    background: linear-gradient(160deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.03));
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    transition: transform 220ms ease, box-shadow 220ms ease;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.st-clockedinout-card:hover {
    transform: perspective(400px) rotateX(4deg) translateY(-2px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.45);
}
/* Same pulsing-glow treatment .st-miniwip-card.st-miniwip-running gets for an active timer - reuses the
   same green and the same slow, low-amplitude 2.4s cadence so a card with a running clock reads with the
   identical "alive" cue Mini WIP's own running jobs already use. */
@keyframes st-clockedinout-pulse {
    0%, 100% { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 0 rgba(61, 220, 132, 0.35); }
    50%      { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 8px 2px rgba(61, 220, 132, 0.35); }
}
.st-clockedinout-card.st-clockedinout-running {
    animation: st-clockedinout-pulse 2400ms ease-in-out infinite;
}
/* Same diameter as .st-miniwip-ring (54px) so the two shop-floor cards - job progress rings and user
   timer icons - carry the same visual weight side by side. Source bitmap is fetched at 256px
   (data-image-size, see standardtime-frozenrowclockedinout.js) and downscaled to this box - the 32px
   source looked visibly stretched/soft at 54px display size; only 16/32/256 exist as embedded resources
   for this icon (stdata\images\enabled|disabled\delay@*px.png), so 256 is the sharp choice. */
.st-clockedinout-timericon {
    width: 54px;
    height: 54px;
    /* AjaxFillImage sets src async (cache miss = one AjaxGetImageBase64Data round-trip) - fixed
       width/height above reserves the box so the card doesn't reflow once the image lands. */
}
.st-clockedinout-card-name {
    margin-top: 4px;
    font-size: 11px;
    font-weight: 600;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.st-clockedinout-card-sub {
    font-size: 10px;
    opacity: 0.75;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Tier 2: chips - name only, wraps onto multiple rows within the row's fixed height. */
.st-clockedinout-users.st-clockedinout-tier-chips {
    flex-wrap: wrap;
    overflow-y: auto;
}
.st-clockedinout-chip {
    flex: 0 0 auto;
    padding: 3px 8px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.08);
    font-size: 11px;
    cursor: pointer;
    white-space: nowrap;
}
.st-clockedinout-chip:hover { background: rgba(255, 255, 255, 0.16); }
.st-clockedinout-chip.st-clockedinout-running { box-shadow: inset 0 0 0 1px #3ddc84; }

/* Tier 3: CSV fallback - the one tier allowed to scroll/clip mid-word, same reasoning
   standardtime-frozenrowminiwip.css documents for its own CSV tier. Running vs. not-running has no icon
   at this density, so a dimmed style on Not-Clocked-In names is the only thing that still distinguishes
   the two groups when "Both" mode mixes them into one CSV line. */
.st-clockedinout-users.st-clockedinout-tier-csv {
    overflow-x: auto;
    white-space: nowrap;
    font-size: 11px;
}
.st-clockedinout-csv-notrunning {
    opacity: 0.55;
}
.st-clockedinout-csv-sep {
    margin: 0 6px;
    opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
    .st-clockedinout-card.st-clockedinout-running { animation: none; }
    .st-clockedinout-card:hover { transform: none; }
}

/* --------------------------------------------------------------------------- */
/* Mini Resource Allocation frozen row (COL_RESALLOC) - "Team Capacity" strip  */
/* --------------------------------------------------------------------------- */
/* See FrozenRowMiniResAlloc-COMPLETED.md for the full spec. Sticky positioning AND the outer cell's own    */
/* look (no height, dark --st-frozenrow-* background/text, no border, overflow: hidden) are both inherited  */
/* for free from the shared .st-grid-frozen-{top,bottom}-row > td / .st-grid-frozenwide-cell rules           */
/* (standardtime-gridengine.css) every registered frozen-wide row shares. Only this row's own mount and its */
/* inner content live in this file. */

/* `.st-resalloc-mount` below is written directly against the proven, post-fix shape of
   standardtime-frozenrowminiwip.css's own `.st-miniwip-mount` - a literal cell height would defeat the
   shrink direction of a drag-resize, and a `height: 100%` mount would silently fail to fill the cell once
   that literal height is gone. Both fixes are applied here pre-emptively. */

.st-resalloc-mount {
    /* `position: absolute; inset: 0` instead of `height/width: 100%` - a <td>'s default
       `vertical-align: middle` (the browser's own UA default, not set anywhere in this stylesheet) makes
       a `height: 100%` child shrink-wrap to its own content and get vertically CENTERED in the cell
       instead of stretching to fill it, once the cell's own height comes purely from the resizable <tr>'s
       inline style rather than a literal CSS height on the cell itself. This cell is always
       `position: sticky` (via the generic `.st-grid-frozen-top-row > td` / `.st-grid-frozen-bottom-row >
       td` rule, since every row this builder inserts is unconditionally frozen -
       radata.MiniResAllocRowBuilder.InsertRow always sets COL_FROZENROW), so it's always a valid
       containing block for this `inset: 0` - no separate `position: relative` needed on the cell itself. */
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    display: flex;
    align-items: stretch;
    padding: 8px 12px;
    gap: 12px;
    overflow: hidden;
    color: var(--st-frozenrow-text, #f4f6f8);
    font-family: inherit;
}

.st-resalloc-label {
    flex: 0 0 auto;
    align-self: center;
    writing-mode: horizontal-tb;
    font-size: 11px;
    font-weight: 700;
    opacity: 0.85;
    max-width: 110px;
}

.st-resalloc-bars {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: stretch;
    gap: 6px;
}

.st-resalloc-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    opacity: 0.6;
    font-style: italic;
    font-size: 12px;
}

.st-resalloc-bar-col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding: 4px 2px;
    border-radius: 6px;
    cursor: pointer; /* every bar is clickable (highlight + toast, see standardtime-frozenrowminiresalloc.js's
                         _miniResAllocOnBarClick) even when it has no contributing records, matching the
                         real chart's own HighlightClickedChartBar being unconditional too - a discoverable
                         affordance in place of Chart.js's own onHover cursor-swap (standardtime-chart.js),
                         which this row has no Chart.js instance to hook. */
    outline: 2px solid transparent; /* reserves the box so adding the 2px accent outline on selection
                                        (below) never shifts layout/reflows sibling bars */
    outline-offset: -2px;
}
.st-resalloc-bar-col.st-resalloc-current {
    background: rgba(255, 255, 255, 0.08);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
}
/* Click-to-highlight - mirrors the real chart's HighlightClickedChartBar (standardtime-chart.js), which
   gives the clicked bar a 3px accent-colored border and clears whichever bar was highlighted before it in
   the same chart. Here that's a 2px accent OUTLINE (not border, which would shift this column's own
   flex-basis width by 2x the border width and jostle its neighbors) on the SAME element the real chart's
   own accent color already reuses (--st-accent, also td.st-grid-cell-selected's color -
   standardtime-gridengine.css) - swapped in/out via a single class
   (st-resalloc-bar-col-selected) by _miniResAllocOnBarClick, not a per-render inline style, so a later
   _miniResAllocRender rebuild (poll tick) cleanly drops it along with the rest of the old DOM. Layers
   correctly on top of .st-resalloc-current above - a bar can be both "this week" (background tint) and
   "selected" (outline) at once, the two rules touch different properties. */
.st-resalloc-bar-col.st-resalloc-bar-col-selected {
    outline-color: var(--st-accent, #6366f1);
}

.st-resalloc-bar-pct {
    font-size: 10px;
    font-weight: 700;
    margin-bottom: 3px;
}

.st-resalloc-bar-track {
    width: 100%;
    max-width: 28px;
    flex: 1 1 auto;
    display: flex;
    align-items: flex-end;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 3px;
    overflow: hidden;
}
.st-resalloc-bar-fill {
    width: 100%;
    border-radius: 3px 3px 0 0;
    transition: height 0.2s ease-out;
}

.st-resalloc-bar-label {
    margin-top: 4px;
    font-size: 9px;
    opacity: 0.75;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* Pinned button column - same shared shape .st-miniwip-btns/.st-clockedinout-btns already establish
   (standardtime-frozenrowminiwip.css/standardtime-frozenrowclockedinout.css): a flex column, centered
   against the mount's own align-items:stretch, whose align-items:stretch (the flex column default) makes
   every button inside it match the widest one's width so their edges line up. Only one button lives here
   today (this row has no mode-toggle), but the wrapper is adopted now rather than later so a future second
   button needs no markup rework. */
.st-resalloc-btns {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
}

/* "View Full Resource Allocation" and the Percent/Hours toggle share one base pill look - the toggle sits
   above "Full Chart" in the same .st-resalloc-btns column (standardtime-frozenrowminiresalloc.js). Opens
   the real page (ShowResourceAllocationBarView(), standardtime-showcontent.js). Inline SVGs with
   stroke="currentColor" per CLAUDE.md's "never render UI arrows as Unicode glyphs" rule. No align-self of
   their own - the wrapper's own align-items:stretch/justify-content:center already position them, same as
   .st-miniwip-viewall-btn/.st-clockedinout-viewall-btn and .st-miniwip-toggle-btn/.st-clockedinout-toggle-btn. */
.st-resalloc-viewall-btn,
.st-resalloc-toggle-btn {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 6px 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--st-frozenrow-text, #f4f6f8);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-resalloc-viewall-btn:hover,
.st-resalloc-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.16);
}
.st-resalloc-viewall-btn:active,
.st-resalloc-toggle-btn:active {
    background: rgba(255, 255, 255, 0.24);
}
/* Mode-active accent - same "only the non-default state gets a color shift" convention
   .st-miniwip-toggle-btn.st-miniwip-mode-running/.st-clockedinout-toggle-btn.st-clockedinout-mode-out use.
   "percent" (the default, matching the real chart's own semantics) is deliberately unaccented; "hours"
   reuses --st-accent (the same accent color the bar-selection outline and Full Chart hover already draw
   from) rather than inventing a second color language for a view-mode switch. */
.st-resalloc-toggle-btn.st-resalloc-mode-hours {
    border-color: var(--st-accent, #6366f1);
    color: var(--st-accent, #6366f1);
}

/* Hairline refresh-countdown sliver - adopted verbatim from standardtime-frozenrowminiwip.css's own
   .st-miniwip-countdown/.st-miniwip-countdown-fill. Empties over MINIRESALLOC_REFRESH_MS and resets every
   time a poll actually fires, via _miniResAllocRestartCountdown (standardtime-frozenrowminiresalloc.js), so
   the row always shows at a glance roughly how stale its current bars are. */
.st-resalloc-countdown {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
}
.st-resalloc-countdown-fill {
    height: 100%;
    width: 100%;
    background: rgba(255, 255, 255, 0.35);
    transform-origin: left;
}
@keyframes st-resalloc-countdown-shrink {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

@media (prefers-reduced-motion: reduce) {
    .st-resalloc-countdown-fill { animation-duration: 0.01ms !important; }
}

/* ------------------------------------------------------------------ */
/* Empty Grid Discovery (Feature enhancement md's\EmptyGridDiscovery.md) */
/* Follows the app's skin-variable system (--st-*) rather than          */
/* UnavailablePartialView's hardcoded whitesmoke/darkgray - this is a   */
/* helpful/onboarding surface, not an error surface.                     */
/* ------------------------------------------------------------------ */

.st-griddiscovery-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    height: 100%;
    width: 100%;
    padding: 32px 24px;
    box-sizing: border-box;
    overflow-y: auto;
    color: var(--st-text-body);
}

.st-griddiscovery-header {
    font-size: calc(11pt + 0.25vw);
    font-weight: 700;
    margin-bottom: 8px;
}

.st-griddiscovery-typeline {
    font-size: calc(9pt + 0.25vw);
    color: var(--st-text-muted);
    max-width: 560px;
    margin-bottom: 20px;
}

.st-griddiscovery-message {
    font-size: calc(9pt + 0.25vw);
    margin-bottom: 16px;
}

.st-griddiscovery-btnrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 12px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-griddiscovery-btn {
    min-width: 120px;
    padding: 8px 18px;
    font-size: inherit;
    font-family: inherit;
    cursor: pointer;
    border: 1px solid #aaa;
    border-radius: var(--st-border-radius, 4px);
    background: var(--st-accent, #6366f1);
    color: var(--st-accent-text, #fff);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.st-griddiscovery-btn:hover {
    background: var(--st-accent-hover, #ebebff);
    color: var(--st-text-body, #212529);
}
.st-griddiscovery-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* Idea 4's prominent "add the first record" CTA - reuses the existing green toast-success skin */
/* variable rather than introducing a new hardcoded color. */
.st-griddiscovery-btn-primary {
    background: var(--st-toast-success, #16a34a);
    border-color: var(--st-toast-success, #16a34a);
    color: #fff;
}
.st-griddiscovery-btn-primary:hover {
    background: color-mix(in srgb, var(--st-toast-success, #16a34a) 85%, black);
    border-color: color-mix(in srgb, var(--st-toast-success, #16a34a) 85%, black);
    color: #fff;
}

/* Tier 2 suggested-filter buttons - secondary styling (same convention as StDialog's .st-btn-cancel). */
.st-griddiscovery-suggestions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 4px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.st-griddiscovery-suggestion-btn {
    background: var(--st-bg-toolbar, #E8E8E8);
    border-color: #aaa;
    color: var(--st-text-body, #212529);
}
.st-griddiscovery-suggestion-btn:hover {
    background: var(--st-grid-hover-bg, #ccc);
    color: var(--st-grid-hover-text, inherit);
}

/* Tier 2's "Thinking..." state (idea 6) - reuses the AiChatWindowPartialView spinner-border pattern. */
.st-griddiscovery-thinking {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 120px;
    padding: 8px 18px;
    font-size: inherit;
    color: var(--st-text-muted);
}

/* Idea 4's brief highlight on the real toolbar #GridAddButton when the panel appears, connecting it   */
/* visually to the panel's own CTA. Mirrors the .st-autofilter-glyph pulse (standardtime-toolbar.css). */
@keyframes st-griddiscovery-addbtn-pulse {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.35); }
    55%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}
#GridAddButton.st-griddiscovery-addbtn-pulse {
    animation: st-griddiscovery-addbtn-pulse 0.6s ease-out 2;
}

/* ================================================================================================
   StContextMenu - styles for the vanilla-JS context menu engine (standardtime-contextmenuengine.js).
   Replaces Content/contextmenujs-master/contextmenu.css (+ its light/dark themes).

   Skin-aware: every color/metric resolves from a --st-menu-* custom property that falls back to the
   existing global skin variables in standardtime-skin-variables.css, which in turn fall back to a
   hard default. So the menu themes correctly under every skin (including dark skins, which already
   override --st-bg-body / --st-text-body / --st-border-color) with no skin-file edits required.
   To centrally re-theme just the menu, a skin may optionally define the --st-menu-* vars directly.

   The --st-menu-* DEFAULTS are declared on :root, deliberately NOT on .st-contextmenu-container.
   A custom property set directly on an element always wins over one inherited from :root, no matter
   the source order of the stylesheets - so with the defaults on the container, a skin's own
   `:root { --st-menu-bg: ... }` could never take effect and the "a skin may optionally define the
   --st-menu-* vars directly" promise above would silently be a lie. On :root, ordinary cascade order
   applies instead, and #st-skin-link is rendered AFTER ~/bundles/standardtime-css in
   _HeadScripts.cshtml, so a skin's declaration wins as intended. [review finding #14]

   Note this engine is the only *engine* CSS file in the app that adds a token-indirection layer of
   its own - standardtime-treeengine.css / -gridengine.css / -propertygridengine.css all consume the
   global --st-* skin variables directly. The extra layer is kept here because a context menu is a
   free-floating surface that a skin may reasonably want to theme apart from the body/grid it sits
   over; it is a deliberate deviation, not an oversight. [review finding #14]
   ================================================================================================ */

:root {
    /* --- themeable tokens (override any of these in a skin for menu-specific control) --- */
    --st-menu-bg:            var(--st-bg-body, #ffffff);
    --st-menu-text:          var(--st-text-body, #212529);
    --st-menu-border:        var(--st-border-color, #cccccc);
    --st-menu-hover-bg:      var(--st-grid-hover-bg, var(--st-accent, #6366f1));
    --st-menu-hover-text:    var(--st-grid-hover-text, var(--st-text-body, #212529));
    --st-menu-disabled-text: var(--st-text-muted, #999999);
    --st-menu-divider:       var(--st-border-color, #dddddd);
    --st-menu-radius:        var(--st-border-radius, 4px);
    --st-menu-shadow:        0 4px 16px rgba(0, 0, 0, 0.28);
}

.st-contextmenu-container {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 1000000;

    font-family: var(--st-font-family, inherit);
    font-size: calc(8pt + 0.10vw);
    font-weight: var(--st-font-weight, normal);
    color: var(--st-menu-text);

    /* Appear animation uses OPACITY ONLY - never transform. A transformed ancestor would become the
       containing block for the position:fixed submenu <ul>s and break their viewport positioning. */
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.10s ease-out;
}

.st-contextmenu-container.st-open {
    opacity: 1;
    pointer-events: auto;
}

.st-contextmenu-container,
.st-contextmenu-container * {
    box-sizing: border-box;
}

/* ---- menus (root <ul> and every submenu <ul>) ---- */
.st-contextmenu-menu {
    list-style: none;
    margin: 0;
    padding: 4px 0;
    background-color: var(--st-menu-bg);
    color: var(--st-menu-text);
    border: 1px solid var(--st-menu-border);
    border-radius: var(--st-menu-radius);
    box-shadow: var(--st-menu-shadow);
    min-width: 180px;
    /* Set here (not just on .st-contextmenu-item) because divider rows are pointer-events:none -
       a click that lands on one hits this <ul> as the actual target, not the divider, so the
       item-level user-select:none alone left a false text-selection caret on divider clicks. */
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* The root <ul> flows inside the fixed container. */
.st-contextmenu-container > .st-contextmenu-menu {
    max-height: 90vh;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Submenus are positioned in JS (fixed, viewport-relative) and hidden until .st-open. Kept as
   visibility/opacity (not display:none) so the engine can measure offsetWidth/offsetHeight before
   showing them, and so the parent<->child DOM nesting drives mouseenter/mouseleave hover intent.
   Deliberately NO max-height here (unlike the root <ul> rule above): positionSubmenu() in the engine
   computes and sets an inline max-height itself, per-submenu, only when the submenu is actually taller
   than the viewport (vh - 2 * VIEWPORT_MARGIN). A static max-height here smaller than that threshold
   (90vh was previously used, copied from the root rule) would cap offsetHeight before the engine ever
   measures it, making that branch of positionSubmenu() unreachable. overflow-y stays as a permanent
   safety net for whichever case applies. [review finding #8] */
.st-contextmenu-menu .st-contextmenu-item > .st-contextmenu-menu {
    position: fixed;
    left: 0;
    top: 0;
    overflow-y: auto;
    overflow-x: hidden;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.10s ease-out;
}

.st-contextmenu-menu .st-contextmenu-item > .st-contextmenu-menu.st-open {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
}

/* ---- item rows ---- */
.st-contextmenu-item {
    position: relative;
    display: flex;
    align-items: center;
    padding: 5px 10px;
    padding-right: 1.9em;   /* room for the submenu arrow */
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
}

/* Hover and keyboard focus share one highlight style. */
.st-contextmenu-item:hover,
.st-contextmenu-item.st-focus,
.st-contextmenu-item.st-contextmenu-open {
    background-color: var(--st-menu-hover-bg);
    color: var(--st-menu-hover-text);
}

/* While keyboard nav is active (an arrow/Enter/etc. key was just handled), suspend pointer interaction on
   every row until the next REAL mouse movement. Without this, a stationary mouse left resting on a row
   keeps matching :hover independently of .st-focus (two rows visibly highlighted at once), and worse:
   scrollIntoView() moving list content under that motionless cursor makes the browser fire a genuine
   mouseenter for whatever row ends up under it, which silently steals focus back - arrow-key navigation
   can never make net progress through a scrolled list. pointer-events:none here means :hover simply cannot
   apply and no further mouseenter can fire until the mouse actually moves. [review finding #10] */
.st-contextmenu-container.st-kbd-nav .st-contextmenu-item {
    pointer-events: none;
}

.st-contextmenu-icon {
    flex: 0 0 auto;
    width: 1.5em;
    min-width: 1.5em;
    margin-right: 8px;
    text-align: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.st-contextmenu-icon img {
    max-width: 16px;
    max-height: 16px;
    vertical-align: middle;
}

/* Checkmark for checkable/radio-style items (e.g. a Gantt Interval submenu's Days/Weeks/Months/Quarters/
   Years choices). Drawn as a CSS border-shape, never a Unicode glyph - same reason as the submenu caret
   below and StTree's caret: some Windows font configs substitute a colored icon font for check/tick
   glyphs that ignores `color`, forcing solid blue regardless of skin. `currentColor` means it follows the
   row's text color automatically through hover, focus, and disabled states with no extra rules needed. */
.st-contextmenu-checkmark {
    display: inline-block;
    width: 5px;
    height: 9px;
    border-style: solid;
    border-color: currentColor;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg) translate(-1px, -1px);
}

.st-contextmenu-text {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Submenu caret. Drawn as a CSS border-triangle (never a Unicode glyph): on some Windows font configs
   the browser substitutes a colored icon font for arrow glyphs that ignores `color`, forcing solid
   blue regardless of skin. This is the same reason StTree's caret is a border-triangle. */
.st-contextmenu-arrow {
    position: absolute;
    right: 0.7em;
    top: 50%;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 4px 0 4px 5px;
    border-color: transparent transparent transparent currentColor;
    opacity: 0;   /* only shown on rows that have a submenu */
    transform: translateY(-50%);
}

.st-contextmenu-item.st-contextmenu-has-sub > .st-contextmenu-arrow {
    opacity: 0.7;
}

/* ---- disabled rows ---- */
.st-contextmenu-disabled {
    color: var(--st-menu-disabled-text);
    cursor: default;
    pointer-events: none;
}

.st-contextmenu-disabled:hover {
    background-color: transparent;
    color: var(--st-menu-disabled-text);
}

/* ---- divider rows ---- */
.st-contextmenu-divider {
    height: 0;
    margin: 5px 8px;
    padding: 0;
    border-bottom: 1px solid var(--st-menu-divider);
    cursor: default;
    pointer-events: none;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* ------------------------------------------------------------------------- */
/* Filter tree - appearance to match the previous Infragistics tree           */
/* Layered on the engine base styles (standardtime-treeengine.css); scoped to */
/* #FilterTree. Load order in the CSS bundle:                                 */
/*   standardtime-skin-variables.css                                         */
/*   -> standardtime-treeengine.css                                          */
/*   -> standardtime-filtertree.css                                          */
/*                                                                           */
/* Colors use --st-* skin variables (not hard-coded) so every skin themes    */
/* correctly; the values below reproduce the light-skin look in the          */
/* reference screenshot.                                                     */
/* ------------------------------------------------------------------------- */


#FilterTree {
    /* Same font size the old FilterTreePartialView used */
    font-size: calc(7pt + 0.25vw);

    /* Small left gutter before the first-level carets, plus top/bottom room */
    padding: 4px 0 6px 6px;

    color: var(--st-text-body, #212529);
}


/* Row height/spacing close to the old tree's rows */
#FilterTree .st-tree-row {
    padding: 4px 6px;
    gap: 6px; /* a touch more space between icon and label than the engine default */
}


/* Indentation step per nested level (the old tree stepped ~22px per level) */
#FilterTree .st-tree-children {
    padding-left: 22px;
}


/* Caret: small, like the IG expander triangle (color comes from the engine base) */
#FilterTree .st-tree-toggle {
    font-size: 9px;
}


/* Entity icon (calendar / project / client, etc.) sits just left of the label */
#FilterTree .st-tree-icon {
    margin-right: 2px;
}


/* The filter tree is not a checkbox tree, so no checkbox rules are needed.    */
/* Search highlighting (.searchselected / .searchcurrent on .searchableitem)   */
/* comes from standardtime-search.css and needs nothing here.                 */


/* ------------------------------------------------------- */
/* Standard Time application styles                        */
/* ------------------------------------------------------- */


/* ------------------------------------------------------- */
/* Main page body                                          */
/* ------------------------------------------------------- */
body {
    padding-top: 0px;
    padding-bottom: 0px;
    height: 100vh;
    overflow: hidden;
    font-family: var(--st-font-family);
    font-weight: var(--st-font-weight);
    line-height: var(--st-line-height);
}

::selection {
    background: var(--st-selection-bg);
    color: var(--st-selection-text);
}

/* ------------------------------------------------------- */
/* Real content areas                                      */
/* ------------------------------------------------------- */
.contentareacolor {
    background-color: var(--st-bg-body);
}


/* ------------------------------------------------------- */
/* The main page controls, under ribbon, above footer      */
/* ------------------------------------------------------- */
.maincontentcontainer {
    height: 80%;
    height: calc(100% - 148px - 24px);
    overflow: hidden;
}


/* ------------------------------------------------------- */
/* Override bootstrap because the max-width was so small   */
/* ------------------------------------------------------- */
.container {
    max-width: 10000px !important;
}


/* ------------------------------------------------------- */
/* Small area at the top for ribbon controls               */
/* ------------------------------------------------------- */
.maincontentribboncontainer {
    height: 4%;
    min-height: 148px;
    width: 100%;
    font-size: var(--st-font-size-base);
    background-color: var(--st-bg-ribbon);
}


/* ------------------------------------------------------- */
/* Bottom of page                                          */
/* ------------------------------------------------------- */
.maincontentfootercontainer {
    height: 2%;
    min-height: 24px;
    position: fixed;
    bottom: 0;
    width: 100%;
    display:inline-table;
    background-color: var(--st-bg-footer);
    color: var(--st-text-footer);
}

.progressbarcontainer {
    height: 100%;
    /*display: inline-block;*/
    display: flex;
    width: fit-content;
    float: right;
}



.lightgrayhover { }
.lightgrayhover:hover { background-color: lightgray !important; }







/* ------------------------------------------------------- */
/* Tables within a report                                  */
/* See stdata.Globals.DataTableToHtml()                    */
/* ------------------------------------------------------- */

.reporttable, .reporttable th, .reporttable td {
    border: 1px solid var(--st-grid-border);
    border-collapse: collapse;
}

.reporttableheaderrow {
    background-color: var(--st-grid-header-bg);
    color: var(--st-grid-header-text);
    font-weight: 700;
}

.reporttablefooterrow {
    background-color: var(--st-grid-header-bg);
    color: var(--st-grid-header-text);
    font-weight:700;
}

.reporttablerows:nth-child(even) {
    background-color: var(--st-grid-alt-row-bg);
}

.reporttablerows:hover {
    background-color: var(--st-grid-hover-bg);
    color: var(--st-grid-hover-text, inherit);
}

.reporttablecols:nth-child(1) {
    background-color: var(--st-reporttable-col1-bg);
    font-weight: 700;
}






/* ------------------------------------------------------- */
/* Become visible after a preiod of time                   */
/* ------------------------------------------------------- */
.transitiontovisible1 {
    opacity: 0;
    transition: opacity 0.5s ease-in;
}

.transitiontovisible2 {
    opacity: 1;
}








/* ------------------------------------------------------- */
/* JQuery UI modal dialog overlay background color         */
/* ------------------------------------------------------- */
.ui-widget-overlay {
    opacity: .70 !important;
    filter: Alpha(Opacity=50) !important;
    background: var(--st-bg-dialog-overlay) !important;
}


/* --------------------------------------------------------------------- */
/* Dropdown panel for custom properties like Folder, Attachments, etc.   */
/* --------------------------------------------------------------------- */
.custom-dropdown-panel {
    position: fixed;
    z-index: 1001;
    width: 500px;
    height: 400px;
    background-color: white;
    border-width: 1px;
    border-color: darkgray;
    border-style: solid;
    overflow: hidden;
    border-radius: 8px;
}


.whitetextshadow {
    text-shadow: -1px -1px 0px white, 1px -1px 0px white, -1px 1px 0px white, 1px 1px 0px white;
}

/* Timesheet cells where hours are entered*/
.timesheettimeperiodcell {
    border-width: 1px;
    border-color: var(--st-ts-cell-bg-alt);
    border-style: solid;
}

/* Timesheet "today" column helps focus on data entry*/
.timesheettodaycolumncell {
    background-color: var(--st-ts-cell-bg);
    mix-blend-mode: darken;
    border-width: 1px;
    border-color: var(--st-ts-cell-bg-alt);
    border-style: solid;
}

.timesheettimeperiodcell:hover { border-color: var(--st-ts-cell-bg-sel); }
.timesheettodaycolumncell:hover { border-color: var(--st-ts-cell-bg-sel); }



/* Signify that an item is selected by user click */
.clickselected {
    background-color: lightblue !important;
}

.draghandle {
    width: 100%; /* Set equal width and height */
    height: 100%;
    background-color: white; /* Optional: Add a background color */
    border-width:1px;
    border-style:solid;
    border-color:orange;
    border-radius: 50%; /* This makes the square element a circle */
}

.draghandle:hover { background-color: cornflowerblue; border-width:2px; }

/* Directional resize cursors per handle position (draghandlebit set in BuildDragHandle) */
.draghandle[draghandlebit="1"]   { cursor: nw-resize; } /* Top-left */
.draghandle[draghandlebit="2"]   { cursor: n-resize;  } /* Top-middle */
.draghandle[draghandlebit="4"]   { cursor: ne-resize; } /* Top-right */
.draghandle[draghandlebit="8"]   { cursor: e-resize;  } /* Right-middle */
.draghandle[draghandlebit="16"]  { cursor: se-resize; } /* Bottom-right */
.draghandle[draghandlebit="32"]  { cursor: s-resize;  } /* Bottom-middle */
.draghandle[draghandlebit="64"]  { cursor: sw-resize; } /* Bottom-left */
.draghandle[draghandlebit="128"] { cursor: w-resize;  } /* Left-middle */

.floatingmodelessdiv {
    position: relative;
    z-index: -1;
    background: #888;
    border-top-right-radius: 0;
    border-top-left-radius: 0;
    font-size: calc(8pt + 0.25vw);
    border: 1px solid #777;
    color: #FFF;
    padding: 0.4em 1em;
    white-space: nowrap;
    line-height: 1.2em;
    cursor: move;
    display: block;
    outline: 0px;
}

/* Popup list used to select records or items */
.popuplistdiv {
    position: fixed;
    z-index: 2001;
    width: 400px;
    height: 300px;
    background-color: white;
    border-style: solid;
    border-color: darkgray;
    border-width: 1px;
    overflow: hidden;
    border-radius: 4px;
    white-space: nowrap;
}

.popuplistminihtmltreeviewholder {
    width: 100%;
    height: 100%;
    list-style-type: none;
    overflow: scroll;
    cursor: default;
}


.popuplistul {
    width: 100%;
    height: 100%;
    list-style-type: none;
    overflow: scroll;
    cursor: default;
}

.multilinetextarea {
    font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace !important;
}


/* ------------------------------------------------------- */
/* Ribbon button text color                                */
/* ------------------------------------------------------- */
.ribbonbutton, .ribbonbuttonsmall { color: var(--st-text-body); }


/* ------------------------------------------------------- */
/* AI chat bubbles                                         */
/* ------------------------------------------------------- */
.ai-bubble {
    width: 78%;
    border-radius: 14px;
    padding: 6px 10px;
    color: var(--st-ai-bubble-text);
    font-size: 9pt;
    font-family: inherit;
    border: none;
    resize: none;
    overflow: hidden;
    word-break: break-word;
    white-space: pre-wrap;
    margin-bottom: 6px;
    display: block;
    box-sizing: border-box;
}

.ai-bubble-you {
    background-color: var(--st-ai-bubble-you-bg);
    margin-left: auto;
}

.ai-bubble-ai {
    background-color: var(--st-ai-bubble-ai-bg);
}

.ai-bubble-app {
    background-color: var(--st-ai-bubble-app-bg);
}

.ai-bubble-error-row {
    position: relative;
    display: block;
    width: 78%;
    margin-bottom: 6px;
}

.ai-bubble-error-row .ai-bubble {
    width: 100%;
    margin-bottom: 0;
}

.ai-error-info-icon {
    position: absolute;
    bottom: 5px;
    right: 6px;
    cursor: pointer;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
    font-size: 0.9em;
    color: white;
    background: var(--st-accent);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1em;
    height: 1em;
    user-select: none;
    transition: transform 0.15s ease;
}

.ai-error-info-icon:hover {
    transform: scale(1.2);
}

/* ------------------------------------------------------------------ */
/* Native <dialog> base                                                  */
/* ------------------------------------------------------------------ */
.st-dialog {
    outline: none;  /* suppress native browser focus ring — dialog is not a focusable interactive element */
    border: 1px solid rgba(0, 0, 0, 0.20);
    border-radius: 6px;
    padding: 0;
    background: var(--st-bg-body, #f5f5f5);
    color: var(--st-text-body, #212529);
    font-size: calc(8pt + 0.25vw);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
    min-width: 320px;
    max-width: 60vw;
    max-height: 90vh;
    /* overflow must be visible so jQuery UI resize handles (injected as
       children at the edges) are not clipped. Scrolling is on .st-dialog-body. */
    overflow: visible;
    /* Explicit top/left centering applied by StDialog.center() via inline style.
       Do NOT set position here — jQuery UI draggable requires position:fixed to
       be set at open time so it can read/write top+left in viewport coords. */
    /* flex-direction lives here (unscoped) rather than in the dialog[open] rule
       below, even though it only takes effect once display becomes flex. The
       close animation's `display` transition (allow-discrete) intentionally
       holds the computed display at "flex" for the full transition duration
       after [open] is removed, so the layout must stay column the whole time
       too — flex-direction isn't itself transitioned, so if it were scoped to
       dialog[open] it would snap to its initial "row" the instant [open] is
       removed, splitting the titlebar and body side-by-side for the duration
       of the close animation ("titlebar jumps to the left" bug). */
    flex-direction: column;
    /* Same false-caret bug class as .st-dialog-body's own user-select:none below, and the
       resize-handle fix in standardtime-resizeengine.css: .st-dialog-body already opts its own
       subtree out of being a caret-from-point landing candidate, but the outer <dialog> element
       itself (titlebar, borders) was not covered, so a click that misses real content - e.g. the
       backdrop near a resizable modal dialog, once its resize-handle and any nearby toast are
       also excluded - can still anchor a false blinking caret directly on the <dialog> element
       (confirmed live via getSelection(), anchorNode the <dialog class="st-dialog"> itself, type
       "Caret"). Per spec this does not affect a descendant <textarea>/<input>'s own editable
       surface regardless of this ancestor rule, so the multiline editor's textarea stays fully
       editable. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* Apply flex layout only when the dialog is open. The [open] attribute is
   added by showModal()/show() and removed by close(). Without this scope,
   display:flex overrides the browser's default display:none for closed
   <dialog> elements, making all three shells visible on page load. */
dialog[open].st-dialog {
    display: flex;
}

@keyframes st-titlebar-flash {
    0%   { background: var(--st-dock-header-bg, #293955); }
    15%  { background: var(--st-new-tab-flash, yellow); }
    30%  { background: var(--st-dock-header-bg, #293955); }
    50%  { background: var(--st-new-tab-flash, yellow); }
    100% { background: var(--st-dock-header-bg, #293955); }
}

.st-dialog-titlebar.st-titlebar-flash {
    animation: st-titlebar-flash 0.8s ease-out;
}

.st-dialog::backdrop {
    background: var(--st-bg-dialog-overlay, rgb(50, 50, 70));
    opacity: 0.65;
}

/* ------------------------------------------------------------------ */
/* Open/close fade + scale animation, CSS-only via @starting-style.     */
/* Browsers without @starting-style/allow-discrete support (or users     */
/* with prefers-reduced-motion) just pop open/closed as before — no      */
/* JS changes, no functional dependency on this block.                  */
/* ------------------------------------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
    /* Unscoped .st-dialog carries the *closed* opacity/transform target —
       this is what the transition animates TOWARD when [open] is removed
       (close), not just the pre-render value used by @starting-style on
       open. Without a closed target here, closing had nothing to animate
       to and the dialog stayed at opacity:1 for the whole hold-open
       duration of the display:none transition, then vanished with no
       visible fade at all. */
    .st-dialog {
        opacity: 0;
        transform: scale(0.96);
        transition:
            opacity 0.18s ease-out,
            transform 0.18s ease-out,
            overlay 0.18s ease-out allow-discrete,
            display 0.18s ease-out allow-discrete;
    }

    dialog[open].st-dialog {
        opacity: 1;
        transform: scale(1);
    }

    @starting-style {
        dialog[open].st-dialog {
            opacity: 0;
            transform: scale(0.96);
        }
    }

    /* Same before/after split for the backdrop — see above. */
    .st-dialog::backdrop {
        opacity: 0;
        transition:
            opacity 0.18s ease-out,
            display 0.18s ease-out allow-discrete,
            overlay 0.18s ease-out allow-discrete;
    }

    dialog[open].st-dialog::backdrop {
        opacity: 0.65;
    }

    @starting-style {
        dialog[open].st-dialog::backdrop {
            opacity: 0;
        }
    }
}

/* ------------------------------------------------------------------ */
/* Title bar — doubles as drag handle                                    */
/* ------------------------------------------------------------------ */
.st-dialog-titlebar {
    background: var(--st-dock-header-bg, #293955);
    color: var(--st-dock-text, #fff);
    padding: 8px 14px;
    font-weight: 600;
    font-size: calc(8pt + 0.3vw);
    display: flex;
    align-items: center;
    justify-content: space-between;
    user-select: none;
    flex-shrink: 0;
    border-radius: 6px 6px 0 0;
    cursor: move;  /* signals drag affordance */
}

/* Window control buttons grouped on the right of the title bar */
.st-dialog-titlebar-buttons {
    display: flex;
    gap: 2px;
    align-items: center;
    flex-shrink: 0;
}

.st-dialog-min-btn,
.st-dialog-max-btn,
.st-dialog-close-btn {
    background: none;
    border: none;
    color: var(--st-dock-text, #fff);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 3px;
    opacity: 0.8;
}
.st-dialog-min-btn:hover,
.st-dialog-max-btn:hover,
.st-dialog-close-btn:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.15);
}
.st-dialog-close-btn { font-size: 18px; }  /* close is primary — slightly larger */

/* ------------------------------------------------------------------ */
/* Body                                                                  */
/* ------------------------------------------------------------------ */
.st-dialog-body {
    padding: 20px;
    overflow-y: auto;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    /* Left at the default user-select:auto, clicking a non-text spot inside the body - e.g. the
       padding around the icon, or the atomic <img> itself (stDialogMessageBoxImage/-WarnDeleteImage/
       etc.) - placed a false text-selection caret, same bug class as the grid's .st-grid-scroll and
       the context menu's .st-contextmenu-menu. Deliberately NOT scoped narrower (e.g. re-enabling
       user-select:text on just .st-dialog-message): Chrome's caret-from-point placement snaps a click
       in this dead space to the NEAREST still-selectable text in the subtree regardless of geometric
       distance, so re-enabling selection on the message text brought the same false caret right back
       for clicks anywhere in the body's padding - confirmed live (a click 20px above/left of the icon,
       nowhere near the message text, still anchored a caret in .st-dialog-message). This affects every
       StDialog body (task links, images, favorites, odata, google export, report design tools, zapier,
       date range picker, etc. - all share this one class), so message text is no longer natively
       drag-selectable anywhere in this engine. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* ------------------------------------------------------------------ */
/* Icon + message row                                                    */
/* ------------------------------------------------------------------ */
.st-dialog-icon-row {
    display: flex;
    gap: 16px;
    align-items: flex-start;
}

.st-dialog-icon {
    width: 64px;
    height: 64px;
    flex-shrink: 0;
}

.st-dialog-message {
    white-space: pre-line;
    overflow-y: auto;
    max-height: 55vh;
    flex: 1;
}

/* ------------------------------------------------------------------ */
/* Prompt textarea (read-only prompt text)                               */
/* ------------------------------------------------------------------ */
.st-dialog-prompt-label {
    width: 100%;
    border: none;
    resize: none;
    background: transparent;
    color: inherit;
    font-size: inherit;
    font-family: inherit;
    overflow-y: auto;  /* show scrollbar if text overflows the fixed row height */
}

/* ------------------------------------------------------------------ */
/* Value input                                                           */
/* ------------------------------------------------------------------ */
.st-dialog-value-input {
    width: 100%;
    margin-top: 8px;
    padding: 4px 6px;
    font-size: inherit;
    border: 1px solid #aaa;
    border-radius: 3px;
    box-sizing: border-box;
    resize: none;  /* single-line default; overridden for multiline via .st-multiline */
}
/* Applied by JS (.toggleClass) only when prompt.bMultiline is true.
   Cannot use [rows] here — rows="1" is always present in the HTML, so [rows]
   would match even for single-line prompts and make them vertically resizable. */
.st-dialog-value-input.st-multiline {
    resize: vertical;
}

/* ------------------------------------------------------------------ */
/* Button row                                                            */
/* ------------------------------------------------------------------ */
.st-dialog-button-row {
    display: flex;
    justify-content: center;
    gap: 12px;
    margin-top: auto;   /* flex: pushes to bottom of body; non-flex parent: resolves to 0 */
    padding-top: 16px;  /* visual gap above buttons in all contexts */
    flex-shrink: 0;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-dialog-button-row input[type="button"],
.st-dialog-button-row button {
    min-width: 90px;
    padding: 6px 16px;
    font-size: inherit;
    font-family: inherit;
    cursor: pointer;
    border: 1px solid #aaa;
    border-radius: 4px;
    background: var(--st-accent, #6366f1);
    color: var(--st-accent-text, #fff);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.st-dialog-button-row input[type="button"]:hover,
.st-dialog-button-row button:hover {
    background: var(--st-accent-hover, #ebebff);
    color: var(--st-text-body, #212529);
}

/* Cancel / secondary button */
.st-dialog-button-row input[type="button"].st-btn-cancel,
.st-dialog-button-row button.st-btn-cancel {
    background: var(--st-bg-toolbar, #E8E8E8);
    color: var(--st-text-body, #212529);
}
.st-dialog-button-row input[type="button"].st-btn-cancel:hover,
.st-dialog-button-row button.st-btn-cancel:hover {
    background: var(--st-grid-hover-bg, #ccc);
    color: var(--st-grid-hover-text, inherit);
}

/* Disabled state — otherwise .prop("disabled", true) blocks clicks but leaves the button looking identical to enabled */
.st-dialog-button-row input[type="button"]:disabled,
.st-dialog-button-row button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ------------------------------------------------------------------ */
/* Warn-delete large icon variant                                        */
/* ------------------------------------------------------------------ */
.st-dialog-icon-large {
    display: block;
    width: 60%;
    max-width: 256px;
    margin: 0 auto 12px;
}

/* ------------------------------------------------------------------ */
/* jQuery UI resize handles — override defaults so they sit on top of   */
/* the dialog border and are visible against the skin background.        */
/* ------------------------------------------------------------------ */
.st-dialog .ui-resizable-handle {
    z-index: 10;
}
.st-dialog .ui-resizable-se {
    /* Bottom-right corner grip — keep the default jQuery UI icon */
    width: 14px;
    height: 14px;
    right: 0;
    bottom: 0;
}
.st-dialog .ui-resizable-s,
.st-dialog .ui-resizable-n  { height: 6px; cursor: ns-resize; }
.st-dialog .ui-resizable-e,
.st-dialog .ui-resizable-w  { width: 6px;  cursor: ew-resize; }
.st-dialog .ui-resizable-ne,
.st-dialog .ui-resizable-nw,
.st-dialog .ui-resizable-sw { width: 10px; height: 10px; }

/* ------------------------------------------------------------------ */
/* Minimized state — body hidden, title bar only, drag still active      */
/* ------------------------------------------------------------------ */
.st-dialog.st-dialog-minimized {
    min-height: 0;
    max-height: none;
    overflow: hidden;  /* clips jQuery UI resize handle divs that sit outside the title bar */
}
.st-dialog.st-dialog-minimized .st-dialog-body {
    display: none;
}
.st-dialog.st-dialog-minimized .ui-resizable-handle { display: none; }

/* ------------------------------------------------------------------ */
/* Maximized state — full viewport, drag and resize suppressed           */
/* ------------------------------------------------------------------ */
.st-dialog.st-dialog-maximized {
    top: 0 !important;
    left: 0 !important;
    width: 100vw !important;
    height: 100vh !important;
    max-width: none !important;
    max-height: none !important;
    border-radius: 0;
}
.st-dialog.st-dialog-maximized .st-dialog-body {
    /* flex: 1 1 auto on .st-dialog-body fills remaining height automatically;
       no explicit height needed and no hardcoded title-bar subtraction. */
    max-height: none;
    overflow-y: auto;
}
.st-dialog.st-dialog-maximized .ui-resizable-handle { display: none; }

/* ------------------------------------------------------------------ */
/* Modeless variant — opened with .show(), no ::backdrop                 */
/* Needs stronger visual treatment to stand out from page content        */
/* because the browser does not dim the background for .show() dialogs.  */
/* ------------------------------------------------------------------ */
.st-dialog.st-dialog-modeless {
    z-index: 9999;  /* showModal() uses the top layer; show() does not — explicit z-index required */
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.50);
}

/* ------------------------------------------------------------------ */
/* StResizable handles — vanilla replacement for jQuery UI's           */
/* .ui-resizable-handle / .ui-resizable-{n,s,e,w,ne,nw,se,sw} classes.  */
/* Wired via standardtime-resizeengine.js into standardtime-dialogengine.js  */
/* (see Feature enhancement md's\ReplacejQueryUI\ReplaceResizable.md).  */
/*                                                                      */
/* Runtime-verified (2026-08-03): today's handle position/size/cursor  */
/* CSS is NOT self-contained in this app's own stylesheets. Only 5 of   */
/* the ~13 rules that make the 8 handles work at all live in            */
/* Content/standardtime-dialog.css (cursor + size overrides); the rest  */
/* (position: absolute, the per-direction top/left/right/bottom         */
/* offsets, and the 4 corner cursors) come from                         */
/* infragistics.theme.css, loaded from the Infragistics CDN for the     */
/* unrelated grid/dock widgets — confirmed by fetching that stylesheet  */
/* directly and finding verbatim stock jQuery UI resizable rules in it, */
/* and by reading computed styles on a live dialog's handles. No        */
/* jquery-ui.css is loaded anywhere (the commented-out <link> tags in   */
/* _HeadScripts.cshtml are correctly dead). This file inlines the       */
/* complete, previously-borrowed ruleset so the handles no longer       */
/* depend on Infragistics CSS staying loaded once Infragistics is fully */
/* removed from the app.                                                */
/*                                                                      */
/* All offsets below are the exact values measured on the live         */
/* Filter Favorites dialog's handles today (getComputedStyle), so this  */
/* is pixel-for-pixel what currently ships, not a redesign.             */
/* ------------------------------------------------------------------ */

.st-dialog .st-resizable-handle {
    position: absolute;
    z-index: 10;
    touch-action: none;  /* the handle owns the gesture; the page must not pan/scroll under a touch drag */
    /* Same false-caret bug class already fixed on .st-dialog-body (standardtime-dialog.css) and
       the grid's dead-space cells (standardtime-gridengine.css): these handles have no text
       content of their own, but clicking one (or clicking the ::backdrop near a resizable modal
       dialog, which can hit-test onto its nearest edge handle) still triggers Chrome's
       caret-from-point placement, which then walks the DOM for the nearest element that still
       allows text selection and anchors a false blinking caret there - confirmed live via
       getSelection() on stDialogMultilineEdit (type "Caret", anchorNode the top .st-resizable-n
       handle) after a click on the dialog's own backdrop landed here instead. user-select:none
       excludes these handles from being a caret-landing candidate, for every resizable StDialog
       at once since this is the shared base rule. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.st-dialog .st-resizable-n,
.st-dialog .st-resizable-s {
    left: 0;
    width: 100%;
    height: 6px;
    cursor: ns-resize;
}
.st-dialog .st-resizable-n { top: -5px; }
.st-dialog .st-resizable-s { bottom: -5px; }

.st-dialog .st-resizable-e,
.st-dialog .st-resizable-w {
    top: 0;
    height: 100%;
    width: 6px;
    cursor: ew-resize;
}
.st-dialog .st-resizable-e { right: -5px; }
.st-dialog .st-resizable-w { left: -5px; }

.st-dialog .st-resizable-se {
    right: 0;
    bottom: 0;
    width: 14px;
    height: 14px;
    cursor: se-resize;
    /* Intentionally no visible grip glyph: jQuery UI's own corner icon
       (.ui-icon-gripsmall-diagonal-se) does not actually render on this app's
       dialogs today either (verified live — its ::before content resolves
       empty), so this stays an invisible hit region, matching current
       on-screen behavior exactly rather than adding a new affordance. */
}

.st-dialog .st-resizable-sw,
.st-dialog .st-resizable-nw,
.st-dialog .st-resizable-ne {
    width: 10px;
    height: 10px;
}
.st-dialog .st-resizable-sw { left: -5px; bottom: -5px; cursor: sw-resize; }
.st-dialog .st-resizable-nw { left: -5px; top: -5px;    cursor: nw-resize; }
.st-dialog .st-resizable-ne { right: -5px; top: -5px;   cursor: ne-resize; }

/* Minimized/maximized: hide all handles. Same technique the app already
   uses today (.ui-resizable-handle equivalents at
   standardtime-dialog.css lines 261/281), just renamed.

   st-resizable-disabled: mirrors jQuery UI's own
   ".ui-resizable-disabled .ui-resizable-handle { display: none; }" rule
   (jquery-ui.css) that disable() must replicate. Without this, a dialog that
   transitions from resizable to non-resizable in the same session (confirmed
   live via stDialogMessageBox: PopupResizableMessageBox opens it resizable,
   a later plain PopupMessageBox call on the same element opens it
   non-resizable) leaves all 8 handle divs visibly on the border with live
   resize cursors, even though StResizable.disable() already blocks the drag
   itself. standardtime-resizeengine.js's enable()/disable() toggle this class. */
.st-dialog.st-dialog-minimized .st-resizable-handle,
.st-dialog.st-dialog-maximized .st-resizable-handle,
.st-dialog.st-resizable-disabled .st-resizable-handle {
    display: none;
}

/* ------------------------------------------------------------------ */
/* StDraggable — vanilla replacement for jQuery UI's $(el).draggable({...}). */
/* Design reference for ReplaceDraggable.md, paired with                */
/* standardtime-draggableengine.js. Not wired into the live app — no    */
/* existing stylesheet is changed by this commit.                       */
/*                                                                       */
/* Deliberately small. Unlike standardtime-resizeengine.css (which had  */
/* ~13 position/size/cursor rules to inline because StResizable creates */
/* 8 brand-new, fixed-class handle divs), StDraggable's "handle" is     */
/* almost always a pre-existing, consumer-defined element (a titlebar   */
/* div, a whole Gantt bar, a whole report-designer handle div) with no  */
/* shared class name this file could predict — so the two things        */
/* jQuery UI's own CSS would otherwise supply for such an element        */
/* (touch-action: none, and a forced cursor while dragging) are applied  */
/* as inline styles by standardtime-draggableengine.js itself instead    */
/* of as rules here. See that file's header comment ("touch-action: none */
/* is applied via inline style") for why. There is nothing left for a   */
/* shared stylesheet to own except the one hook class below.            */
/* ------------------------------------------------------------------ */

/* Applied to the dragged element for the duration of an active drag (i.e. only after the
   delay/distance threshold is met — never during a tentative pre-threshold press, and never on an
   element that is merely draggable-capable but not currently being dragged). Mirrors jQuery UI's own
   `ui-draggable-dragging` class, which today's ESC-key handler
   (standardtime-keyboardaccelerators.js:40) queries by class name; StDraggable.cancelActiveDrag()
   replaces that query with a direct call instead (see standardtime-draggableengine.js's "ESC-cancel
   contract" section), so nothing in this engine actually depends on this class being queryable —
   it exists as a stable hook for feature-specific CSS in the 3 consuming stylesheets (e.g. a dialog
   titlebar or a Gantt bar wanting a "currently grabbed" look), the same reason jQuery UI shipped one.
   Intentionally no rules on it here: today's 3 consumers each already provide their own visual
   feedback during a drag through other means (the dialog simply follows the pointer; Gantt bars show
   a floating date label via #GanttDragLabel; report-designer handles reposition the selected object
   live) without needing a default appearance on the dragged element itself. */
.st-draggable-dragging {
}

/* ------------------------------------------------------------------ */
/* StTabs — vanilla replacement for jQuery UI's .ui-tabs/.ui-tabs-nav/  */
/* .ui-tabs-tab/.ui-tabs-anchor/.ui-state-hover/.ui-state-active/       */
/* .ui-tabs-panel classes. Design reference for ReplaceTabs.md, paired  */
/* with standardtime-tabsengine.js.                                     */
/*                                                                       */
/* All 4 usages are cut over to StTabs (Stage 4/Ribbon shipped last).   */
/* The old jQuery-UI-class-targeting CSS this file replaces has been    */
/* deleted from its old homes, not left duplicated:                     */
/*   - Content/standardtime-main.css's .ui-tabs-mainribbon/             */
/*     .ui-tabs-panel-mainribbon block, its generic .ui-tabs .ui-tabs-  */
/*     nav..panel block, its .ui-corner-all utility (only ever applied  */
/*     by jQuery UI's tabs widget itself), and its #DesignTab/          */
/*     #PreviewTab white-canvas rule (reproduced below) are all removed. */
/*   - Content/standardtime-ribbon.css's #MainRibbonTabs .ui-state-active/ */
/*     .ui-state-hover block is removed — it was always redundant with  */
/*     this file's generic .st-tabs-tab-active/:hover rules (jQuery     */
/*     UI's `classes` API can't rename ui-state-* classes, so that      */
/*     override styled the same --st-tab-* vars the generic rule set).  */
/*                                                                       */
/* Must load after standardtime-skin-variables.css in the bundle order  */
/* (per CLAUDE.md, that file stays first) — every color below is a      */
/* --st-tab-* custom property defined there.                            */
/* ------------------------------------------------------------------ */

.st-tabs {
    /* jQuery UI's tabs widget always tagged "ui-widget ui-widget-content" onto the tabs root
       regardless of theme, and Infragistics' still-loaded theme CSS (Content/Infragistics/css/themes/
       infragistics/infragistics.theme.css) happens to define ".ui-widget { font-size: 1.1em }" — the
       same hidden Infragistics-theme dependency the Eighth finding already found for .ui-tabs-nav's
       corner-radius and .ui-tabs-anchor's padding, just missed for font-size until a live before/after
       screenshot comparison caught it post-Stage-4. Every old .tabs() instance rendered ~10% larger
       than its own inherited context as a result; StTabs never replicated jQuery UI's ui-widget/
       ui-widget-content class-tagging, so text (and the em-based nav/anchor padding/border-radius that
       scale with it) silently shrank back to the un-boosted base size. Restoring the multiplier here
       (not a fixed px value) reproduces the original *relative* effect for all 4 usages regardless of
       each one's own inherited base font-size. */
    font-size: 1.1em;
}

.st-tabs-nav {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--st-tab-bg);
    /* Matches standardtime-main.css's app-wide .ui-corner-all utility (4px), which jQuery UI's tabs
       widget always tagged onto the old .ui-tabs-nav <ul> regardless of theme. */
    border-radius: 4px;
    /* Tab strip is pure navigation chrome (like .st-tree-row/.st-toolbar-row) - clicking it should
       never place a text-selection caret. Unlike .st-tabs-panel, this is safe unscoped across every
       StTabs usage (ribbon, report view, project assistant, report design tools) since it never holds
       user content, only tab labels. */
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-tabs-tab {
    background: var(--st-tab-bg);
    border: 1px solid transparent;
    border-bottom: none;
    /* Matches .st-tabs-nav's own 4px radius so a differently-colored tab (active, or hovered) at the
       first/last position doesn't poke a square corner past the strip's rounded corner. Harmless on
       inactive/unhovered tabs since their background matches the strip's, so the rounding is invisible
       until a color boundary exists. */
    border-radius: 4px 4px 0 0;
}

.st-tabs-anchor {
    display: block;
    padding: 0.5em 1em;
    /* !important needed: Bootstrap's `a:hover { color: #0a58ca; }` (Content/bootstrap.css) has
       higher specificity (type+pseudo-class) than a bare class selector and otherwise wins on
       hover, overriding the skin's tab text color with Bootstrap's blue link-hover color. */
    color: var(--st-tab-text) !important;
    text-decoration: none;
    cursor: pointer;
    outline: none;
}

/* Keyboard focus only — jQuery UI's tabs don't draw a focus ring on mouse click either      */
/* (only on keyboard Tab-focus), so scope this the same way rather than showing a ring on     */
/* every mouse click.                                                                          */
.st-tabs-anchor:focus-visible {
    outline: 2px solid var(--st-tab-border);
    outline-offset: -2px;
}

.st-tabs-tab:hover:not(.st-tabs-tab-active) {
    background: var(--st-tab-hover-bg);
}

.st-tabs-tab-active {
    background: var(--st-tab-active-bg);
    border: 1px solid var(--st-tab-border);
    border-bottom: none;
    margin-top: 1px;
    margin-bottom: 0;
    padding-bottom: 0;
}

.st-tabs-tab-active .st-tabs-anchor {
    color: var(--st-tab-text);
}

.st-tabs-panel {
    display: none;
    background: var(--st-bg-body);
    color: var(--st-text-body);
    border: none;
    /* Matches the padding Infragistics' generic .ui-tabs .ui-tabs-panel theme rule used to supply for
       any usage without its own zeroing override (Eighth finding, ReplaceTabs.md) — mainribbon and
       reportdesigntools zero this back out below via a more specific selector; report view and project
       assistant panels rely on this default. */
    padding: 1em 1.4em;
}

.st-tabs-panel.st-tabs-panel-active {
    display: block;
}

/* ------------------------------------------------------------------ */
/* heightStyle: "fill" opt-in (usages #3 ReportPartialView, #4 Ribbon)  */
/* Pure-CSS flex-column equivalent of jQuery UI's JS pixel math — see   */
/* standardtime-tabsengine.js's header comment for the height-context   */
/* caveat (the ROOT element must already resolve to a definite height   */
/* from its own container for this to have anything to fill).           */
/* ------------------------------------------------------------------ */
.st-tabs-fill {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.st-tabs-fill > .st-tabs-nav {
    flex: 0 0 auto;
}

.st-tabs-fill > .st-tabs-panel.st-tabs-panel-active {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: auto;
}

/* ------------------------------------------------------------------ */
/* Usage-specific overrides, ported from standardtime-main.css          */
/* ------------------------------------------------------------------ */

/* DialogProjectAssistant.cshtml / DialogReportDesignTools.cshtml both already do their own     */
/* flex-based panel sizing in their own inline <style> blocks (not jQuery UI heightStyle math),  */
/* unchanged by this migration — no port needed here for those two beyond the classes below.     */

/* The 3rd selector is required, not decorative: .st-tabs-fill > .st-tabs-panel.st-tabs-panel-active */
/* above (3 classes) otherwise outranks the first two selectors here (2 and 1 classes) on the Ribbon's */
/* active panel -- the only panel ever actually visible -- silently swapping overflow:hidden for       */
/* overflow:auto there and letting a scrollbar appear inside the ~148px ribbon budget. The original     */
/* .ui-tabs-mainribbon .ui-tabs-panel / .ui-tabs-panel-mainribbon rules in standardtime-main.css used    */
/* !important specifically to guarantee clipped (not scrolling) overflow in the Ribbon; matching that    */
/* here needs equal-or-higher specificity instead, since .st-tabs-fill has no !important to out-rank.    */
.st-tabs-mainribbon .st-tabs-panel,
.st-tabs-panel-mainribbon,
.st-tabs-fill.st-tabs-mainribbon > .st-tabs-panel.st-tabs-panel-active {
    padding: 0;
    overflow: hidden;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-tabs-reportdesigntools .st-tabs-panel,
.st-tabs-panel-reportdesigntools {
    padding: 0;
    overflow-y: scroll;
}

/* Report design/preview tab panels are a page/paper canvas: report objects (searchableitem divs  */
/* in ReportPartialView.cshtml) render with colors chosen against a white page - rptdata's         */
/* DisplayObject treats a white object background as "transparent", assuming a white canvas        */
/* underneath - so these two panels must stay literal white regardless of skin, the same way a      */
/* document page stays white even in a dark-themed app. Deliberately targets #DesignTab/#PreviewTab */
/* (sized directly by the heightStyle:"fill" flex chain above) rather than the nested                */
/* #DesignTabReportDiv/#PreviewTabReportDiv - those rely on a height:100% cascade through the        */
/* scrolling wrapper div that does not reliably resolve to the tab pane's full height, so painting   */
/* white on them exposes a collapsed box instead of covering the whole pane. ID selectors already     */
/* outrank the generic .st-tabs-panel rule above without needing !important.                          */
#DesignTab, #PreviewTab {
    background: white;
    color: #000000;
}


/* ------------------------------------------------------- */
/* Standard Time ribbon styles                             */
/* ------------------------------------------------------- */

.ribbonbutton {
    font-size: 9pt !important;
    line-height: 90px !important;
    height: 75px !important;
    border: none !important;
    transition-duration: 0.3s;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.ribbonbutton:focus-visible {
    outline: 2px solid var(--st-focus-ring, #6366f1);
    outline-offset: -2px;
    border-radius: 10px;
}

/* Enlarge button image slightly during hover*/
.ribbonbutton:hover {
    background-color: var(--st-accent-hover) !important;
    background-size: 34px !important;
    border-radius: 10px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    transform: translateY(-1px);
}

.ribbonbutton:active {
    box-shadow: none;
    transform: translateY(0);
    filter: brightness(0.95);
}

.ribbonpanelcontainer {
    width: max-content;
    display: grid;
    grid-auto-flow: column;
    overflow-x: auto;
    overflow-y: hidden;
}

.ribbonpanel {
    font-size: 12px;
    color: var(--st-text-muted);
    padding-top: 5px;
    padding-left: 4px;
    padding-right: 4px;
    width: max-content;
    border-right: 1px solid var(--st-grid-border, #dee2e6);
}

.ribbonpanellabel {
    text-align: center;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}


.ribbonbuttonsmall {
    background-color: transparent;
    border: none !important;
    text-align: left;
    transition-duration: 0.3s;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.ribbonsmallbuttoncontainer {
    height: 75px !important;
    display: grid;
    grid-template-columns: auto auto auto auto auto;
}


/* ------------------------------------------------------- */
/* Ribbon dropdown button                                   */
/* ------------------------------------------------------- */

.ribbon-dropdown-wrap {
    position: relative;
    display: inline-block;
}

.ribbon-dropdown-menu {
    position: fixed;
    z-index: 9999;
    background-color: var(--st-bg-ribbon);
    border: 1px solid var(--st-border-color);
    border-radius: 4px;
    box-shadow: 0 4px 8px rgba(0,0,0,0.15);
    white-space: nowrap;
    padding: 4px 0;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.ribbon-dropdown-item {
    display: block;
    width: 100%;
    text-align: left;
    background-color: transparent;
    border: none !important;
    padding: 6px 16px 6px 28px;
    font-size: 9pt;
    cursor: pointer;
    transition-duration: 0.3s;
    line-height: normal !important;
    height: auto !important;
    background-position: 8px center !important;
    background-size: 16px !important;
}

.ribbon-dropdown-item:hover {
    background-color: var(--st-accent) !important;
    color: var(--st-accent-text) !important;
    background-size: 16px !important;
}




/* ------------------------------------------------------- */
/* Standard Time search bar styles                         */
/* ------------------------------------------------------- */


.searchbutton {
    font-size: 9pt !important;
    line-height: 90px !important;
    width: 32px !important;
    height: 32px !important;
    border: none !important;
    transition-duration: 0.3s;
}

/* Enlarge button image slightly during hover*/
.searchbutton:hover {
    transform: scale(1.1);
}


.searchcontainer {
    margin-left: auto;
    margin-right: 0;
}

/* Collapsed by default (jQuery .animate() opens/closes this on focus). This element - not the
   input - now owns the rounded-pill look: background + border-radius live here, and overflow:hidden
   clips the input and clear button to that same rounded shape (a clipping box follows its own
   border-radius), so the two children read as one continuous box instead of separate pieces. */
.searchinputwrap {
    display: inline-flex;
    align-items: center;
    overflow: hidden;
    width: 0px;
    height: 28px;
    opacity: 0;
    vertical-align: middle;
    background: #fff;
    border-radius: 10px;
}

.searchinputtext {
    border: none;
    outline: none;
    box-shadow: none;
    appearance: none;
    -webkit-appearance: none;
    box-sizing: border-box;
    flex: 1 1 auto;
    min-width: 0;
    height: calc(100% - 6px);
    margin: 3px 0;
    background: transparent;
    padding: 0 4px 0 10px;
}

/* "x" clear button - only shown once there's text, via :placeholder-shown (needs the placeholder attribute).
   No background of its own - it sits on .searchinputwrap's background so it reads as part of the same box. */
.searchclearbtn {
    display: none;
    flex: 0 0 auto;
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    color: var(--st-text-muted, #888);
    padding: 0 8px;
    user-select: none;
}

.searchclearbtn:hover {
    color: var(--st-text-body, #333);
}

.searchinputtext:not(:placeholder-shown) ~ .searchclearbtn {
    display: inline-block;
}


/* jQuery will search for this class, then set background color to signify that it's selected */
.searchableitem {
    /*color: black !important;*/
    /*background-color: lightgreen !important;*/
}

/* Signify that an item is selected */
.searchselected {
    color: white !important;
    background-color: var(--st-text-search-sel) !important;
}

/* The current search item, F3 to select next */
.searchcurrent {
    color: black !important;
    background-color: var(--st-text-search-cur) !important;
}


/* Go up each parent until a searchable div is found, then search for searchableitem class */
.searchablediv {
}



/* ------------------------------------------------------- */
/* Standard Time toolbar styles                            */
/* ------------------------------------------------------- */

/* ------------------------------------------------------- */
/* Toolbar area above content                              */
/* ------------------------------------------------------- */
.toolbarheadercolor {
    background-color: var(--st-bg-toolbar);
}

/* ------------------------------------------------------- */
/* Toolbar area above views (grids, charts, etc)           */
/* ------------------------------------------------------- */
.maincontenttoolbar {
    height: 4%;
    min-height: 24px;
    width: 100%;
    font-size: 12pt;
    background-color: var(--st-bg-body);
}


.toolbarbutton16 {
    width: 16px !important;
    height: 16px !important;
    border: none !important;
    background-size: contain !important;
    transition-duration: 0.3s;
}

.toolbarbutton20 {
    width: 20px !important;
    height: 20px !important;
    border: none !important;
    background-size: contain !important;
    transition-duration: 0.3s;
}

.toolbarbutton24 {
    width: 24px !important;
    height: 24px !important;
    border: none !important;
    background-size: contain !important;
    transition-duration: 0.3s;
}

.toolbarbutton32 {
    width: 32px !important;
    height: 32px !important;
    border: none !important;
    background-size: contain !important;
    transition-duration: 0.3s;
}

.toolbarbutton48 {
    width: 48px !important;
    height: 48px !important;
    border: none !important;
    background-size: contain !important;
    transition-duration: 0.3s;
}

/* Icons rendered as <img> (not <button>) have no src until the lazy image-load
   Ajax call fills them in — hide until then so the browser's broken-image icon
   doesn't flash. Scoped to img only: <button class="toolbarbutton24"> elements
   (e.g. GridRefreshButton in BasicButtonsView.cshtml) use background-image and
   never carry a src attribute at all, so an unscoped :not([src]) selector would
   match them permanently and hide every toolbar button. Mirrors
   .propertyimg:not([src]) in PropertyGridPartialView.cshtml. */
img.toolbarbutton16:not([src]),
img.toolbarbutton20:not([src]),
img.toolbarbutton24:not([src]),
img.toolbarbutton32:not([src]),
img.toolbarbutton48:not([src]) {
    opacity: 0;
}




.toolbarbutton24:hover {
    /*background-size: 105% !important;*/
    transform: scale(1.1) !important;
}

.toolbarbutton16:hover {
    /*background-size: 105% !important;*/
    transform: scale(1.1) !important;
}


/* ------------------------------------------------------- */
/* Auto-filter indicator (grid/report toolbars)             */
/* ------------------------------------------------------- */
.st-autofilter-label {
    color: var(--st-text-autofilter);
    margin-right: 10px;
}

.st-autofilter-glyph {
    width: 16px !important;
    height: 16px !important;
    vertical-align: middle;
    margin-right: 4px;
    animation: st-autofilter-flash 0.6s ease-out 1;
}

@keyframes st-autofilter-flash {
    0%   { opacity: 0; transform: scale(0.4); }
    35%  { opacity: 1; transform: scale(1.3); }
    60%  { transform: scale(0.9); }
    100% { opacity: 1; transform: scale(1); }
}



.homeiconbutton {
    font-size: 0.75vw !important;
    /*line-height: 90% !important;*/
    height: 100%;
    width: 100%;
    border: none !important;
    transition-duration: 0.1s;
    background-size: contain !important;
    background-position-y: 10% !important;
    display: inline-flex;
    align-items: flex-end;
    justify-content: center;
    /*-webkit-text-stroke: 5px black;*/
    text-shadow: -1px -1px 0px white, 1px -1px 0px white, -1px 1px 0px white, 1px 1px 0px white;
    -webkit-print-color-adjust: exact;
}

.smallapphomeicon {
    background-position-y: 50% !important;
    font-size: 2vw !important;
}


/* Lift + shadow + accent underline on hover */
.homeiconbutton {
    position: relative;
    overflow: hidden;
    transition: transform 150ms ease-out,
                box-shadow 150ms ease-out,
                background-color 150ms ease-out;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.homeiconbutton:hover {
    transform: translateY(-3px) scale(1.07);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--st-accent, #0d6efd) 20%, transparent);
    background-color: color-mix(in srgb, var(--st-accent, #0d6efd) 9%, transparent) !important;
    border-radius: 10px;
}
.homeiconbutton::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 2px;
    background: var(--st-accent, #0d6efd);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 150ms ease-out;
    border-radius: 0 0 4px 4px;
}
.homeiconbutton:hover::after {
    transform: scaleX(1);
}

.ten-column-grid-container {
    display: grid;
    grid-template-columns: 9% 9% 9% 9% 9% 9% 9% 9% 9% 9%;
    gap: 1%;
    padding: 0px 10px 20px 10px;
    width: 100%;
    height: 95%;
}

.five-column-grid-container {
    display: grid;
    grid-template-columns: 19% 19% 19% 19% 19%;
    gap: 1%;
    padding: 10px;
    width: 100%;
    height: 90%;
}

.centered-icon-grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(25%, 1fr));
    gap: 1%;
    padding: 0px 10px 20px 10px;
    width: 100%;
    height: 95%;
}

.homeiconbuttonrow {
    display: flex;
    flex-direction: row;
    padding-left: 10px;
    padding-right: 10px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* ---- Home icon layout: Cards ---- */
.icon-cards-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    padding: 12px;
    align-content: start;
}
.icon-card {
    border: 1px solid color-mix(in srgb, var(--st-accent, #0d6efd) 18%, transparent);
    border-radius: 6px;
    padding: 10px 12px;
    background: color-mix(in srgb, var(--st-accent, #0d6efd) 5%, transparent);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
    transition: border-color 150ms ease-out, box-shadow 150ms ease-out;
    will-change: transform;
    position: relative;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
@property --card-beam1-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}
@property --card-beam2-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}
/* Shared beam style — masked to border strip only */
.icon-card::before,
.icon-card::after,
.icon-list-section::before,
.icon-list-section::after {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: 7px;
    padding: 2px;
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    opacity: 0;
    pointer-events: none;
    z-index: 1;
}
/* Beam 1 — clockwise down the right side */
.icon-card::before,
.icon-list-section::before {
    background: conic-gradient(from var(--card-beam1-angle),
        white 0%,
        var(--st-accent, #0d6efd) 3%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 55%, transparent) 10%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 15%, transparent) 22%,
        transparent 28%,
        transparent 100%);
}
/* Beam 2 — counter-clockwise down the left side (angle decreases 0 → -180) */
.icon-card::after,
.icon-list-section::after {
    background: conic-gradient(from var(--card-beam2-angle),
        white 0%,
        var(--st-accent, #0d6efd) 3%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 55%, transparent) 10%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 15%, transparent) 22%,
        transparent 28%,
        transparent 100%);
}
@keyframes card-laser-beam1 {
    from { --card-beam1-angle: 0deg;    opacity: 1; }
    95%  {                              opacity: 1; }
    to   { --card-beam1-angle: 180deg;  opacity: 0; }
}
@keyframes card-laser-beam2 {
    from { --card-beam2-angle: 0deg;    opacity: 1; }
    95%  {                              opacity: 1; }
    to   { --card-beam2-angle: -180deg; opacity: 0; }
}
.icon-card:has(.iconcardwrap:hover)::before,
.icon-list-section:has(.iconlistwrap:hover)::before {
    animation: card-laser-beam1 0.3s linear 1 forwards;
}
.icon-card:has(.iconcardwrap:hover)::after,
.icon-list-section:has(.iconlistwrap:hover)::after {
    animation: card-laser-beam2 0.3s linear 1 forwards;
}
.icon-card:has(.iconcardwrap:hover),
.icon-list-section:has(.iconlistwrap:hover) {
    border-color: var(--st-accent, #0d6efd);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--st-accent, #0d6efd) 12%, transparent);
}
.icon-card-title {
    font-size: calc(7pt + 0.2vw);
    font-weight: bold;
    color: var(--st-text-muted, #666);
    margin-bottom: 8px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--st-border-color, #eee);
}
.icon-card-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* ---- Home icon layout: List ---- */
.icon-list-container {
    columns: 2;
    column-gap: 32px;
    padding: 12px;
}
.icon-list-section {
    break-inside: avoid;
    margin-bottom: 16px;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}
.icon-list-header {
    font-size: calc(7pt + 0.2vw);
    font-weight: bold;
    color: var(--st-text-muted, #666);
    margin-bottom: 4px;
    padding-bottom: 2px;
    border-bottom: 1px solid var(--st-border-color, #eee);
}



/* Cards — icon stacked above label chip, fixed width so buttons tile evenly */
/* Wrapper div so SetupElementImagesInDivByParent can recurse in and set the <img> src */
.iconcardwrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    width: 84px;
    padding: 4px;
    cursor: pointer;
    border-radius: 3px;
    text-align: center;
    font-size: calc(7pt + 0.2vw);
    color: var(--st-text-body, inherit);
    position: relative;
    overflow: hidden;
    transition: transform 150ms ease-out,
                box-shadow 150ms ease-out,
                background-color 150ms ease-out;
}
.iconcardwrap:hover {
    transform: translateY(-3px) scale(1.07);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--st-accent, #0d6efd) 20%, transparent);
    background-color: color-mix(in srgb, var(--st-accent, #0d6efd) 9%, transparent);
    border-radius: 10px;
}
.iconcardwrap::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 2px;
    background: var(--st-accent, #0d6efd);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 150ms ease-out;
    border-radius: 0 0 4px 4px;
}
.iconcardwrap:hover::after {
    transform: scaleX(1);
}
.iconcardimg {
    width: 64px;
    height: 64px;
    display: block;
}
.iconcardlabel {
    display: block;
    background: color-mix(in srgb, var(--st-accent, #0d6efd) 12%, transparent);
    color: var(--st-accent, #0d6efd);
    border-radius: 4px;
    padding: 2px 5px;
    line-height: 1.3;
    width: 100%;
    box-sizing: border-box;
    transition: background 150ms ease-out;
}
/* List — section container */
.icon-list-section {
    background: color-mix(in srgb, var(--st-accent, #0d6efd) 5%, transparent);
    border: 1px solid color-mix(in srgb, var(--st-accent, #0d6efd) 18%, transparent);
    border-radius: 6px;
    padding: 6px 8px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
    transition: border-color 150ms ease-out, box-shadow 150ms ease-out;
    will-change: transform;
    position: relative;
}
/* List — compact icon+text rows */
.iconlistwrap {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 3px 4px;
    cursor: pointer;
    border-radius: 3px;
    font-size: calc(7pt + 0.15vw);
    color: var(--st-text-body, inherit);
    transition: background 150ms ease-out;
}
.iconlistwrap:hover {
    background: var(--st-grid-hover-bg, rgba(0,0,0,0.05));
    color: var(--st-grid-hover-text, inherit);
}
.iconlistimg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* ---- Home icon layout: Planetary ---- */
@property --planet-beam1-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}
@property --planet-beam2-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}
.planet-beam-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    pointer-events: none;
}
.planet-beam-ring::before,
.planet-beam-ring::after {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: 50%;
    padding: 2px;
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    opacity: 0;
    pointer-events: none;
    z-index: 2;
}
.planet-beam-ring::before {
    background: conic-gradient(from var(--planet-beam1-angle),
        white 0%,
        var(--st-accent, #0d6efd) 3%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 55%, transparent) 10%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 15%, transparent) 22%,
        transparent 28%,
        transparent 100%);
}
.planet-beam-ring::after {
    background: conic-gradient(from var(--planet-beam2-angle),
        white 0%,
        var(--st-accent, #0d6efd) 3%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 55%, transparent) 10%,
        color-mix(in srgb, var(--st-accent, #0d6efd) 15%, transparent) 22%,
        transparent 28%,
        transparent 100%);
}
@keyframes planet-laser-beam1 {
    from { --planet-beam1-angle: 0deg;    opacity: 1; }
    95%  {                                opacity: 1; }
    to   { --planet-beam1-angle: 180deg;  opacity: 0; }
}
@keyframes planet-laser-beam2 {
    from { --planet-beam2-angle: 0deg;    opacity: 1; }
    95%  {                                opacity: 1; }
    to   { --planet-beam2-angle: -180deg; opacity: 0; }
}
.planet:has(.planet-icon:hover) .planet-beam-ring::before {
    animation: planet-laser-beam1 0.3s linear 1 forwards;
}
.planet:has(.planet-icon:hover) .planet-beam-ring::after {
    animation: planet-laser-beam2 0.3s linear 1 forwards;
}
/*
 * Each .planet is a fixed 220x220px square. Icons are absolutely positioned
 * at top:50% left:50% (the center), then pushed to their orbit position via
 * an inline transform: rotate(Adeg) translate(82px) rotate(-Adeg).
 * The negative counter-rotation keeps the icon image upright.
 * The 48x48px button box is offset by -24px so its center sits on the orbit ring.
 * Geometry: orbit 82 + half-button 24 = 106px < container half 110px (4px clearance).
 */
.planetary-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 20px;
    padding: 16px;
    align-content: start;
}
.planet {
    position: relative;
    width: 220px;
    height: 220px;
    isolation: isolate;
}
/* Hover ring — z-index:1 keeps it above orbit icons */
.planet::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid transparent;
    pointer-events: none;
    z-index: 1;
    transition: border-color 150ms ease-out, box-shadow 150ms ease-out;
}
.planet:has(.planet-icon:hover)::before {
    border-color: color-mix(in srgb, var(--st-accent, #0d6efd) 50%, transparent);
    box-shadow: 0 0 12px color-mix(in srgb, var(--st-accent, #0d6efd) 20%, transparent);
}
/* Faint background circle — z-index:-1 sits behind all children */
.planet::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--st-accent, #0d6efd) 5%, transparent);
    border: 1px solid color-mix(in srgb, var(--st-accent, #0d6efd) 18%, transparent);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
    pointer-events: none;
    z-index: -1;
}
@keyframes planet-core-pulse {
    0%   { transform: scale(1);   opacity: 0; }
    15%  { opacity: 0.55; }
    100% { transform: scale(2.4); opacity: 0; }
}
.planet-core {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: var(--st-accent, #0d6efd);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-size: calc(6pt + 0.15vw);
    font-weight: bold;
    padding: 4px;
    box-sizing: border-box;
    cursor: default;
    line-height: 1.2;
    transition: transform 250ms ease-out;
}
.planet-core:hover {
    transform: translate(-50%, -50%) scale(1.35);
}
/* Sonar pulse ring — expands from core edge and fades out */
.planet-core::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--st-accent, #0d6efd);
    opacity: 0;
    pointer-events: none;
}
.planet-core:hover::after {
    animation: planet-core-pulse 1.4s ease-out 1;
}
/* Short label (default) / full label (on hover) cross-fade */
.planet-core-short,
.planet-core-full {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    text-align: center;
    line-height: 1.2;
    word-break: break-word;
    transition: opacity 200ms ease-out;
}
.planet-core-short { opacity: 1; }
.planet-core-full  { opacity: 0; font-size: calc(5pt + 0.1vw); }
.planet-core:hover .planet-core-short { opacity: 0; }
.planet-core:hover .planet-core-full  { opacity: 1; }
.planet-icon {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 56px;
    margin: -24px 0 0 -28px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 2px;
    cursor: pointer;
    border-radius: 4px;
    transition: background 150ms ease-out, box-shadow 150ms ease-out,
                translate 150ms ease-out, scale 150ms ease-out;
}
.planet-icon:hover {
    background: color-mix(in srgb, var(--st-accent, #0d6efd) 9%, transparent);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--st-accent, #0d6efd) 20%, transparent);
    border-radius: 10px;
    translate: 0 -3px;
    scale: 1.07;
}
.planet-icon-img {
    width: 36px;
    height: 36px;
    display: block;
    pointer-events: none;
    flex-shrink: 0;
}
.planet-icon-label {
    font-size: 6pt;
    color: var(--st-text-body, inherit);
    text-align: center;
    line-height: 1.2;
    word-break: break-word;
    pointer-events: none;
}

/* ---- Layout toggle buttons: icon-only, 28x28 ---- */
/* AjaxSetButtonBackgroundImage always sets background-position to top center via inline style. */
/* !important overrides the inline position so the icon renders centered in the empty button. */
#divHomeLayoutButtons {
    margin-right: 0.5rem;   /* replaces the old Bootstrap .me-2 utility class */
}
#divHomeLayoutButtons .st-btn {
    width: 28px;
    height: 28px;
    padding: 0;
    background-position: center center !important;
    background-repeat: no-repeat !important;
    background-size: 16px 16px !important;
}
#divHomeLayoutButtons .st-btn.active {
    /* !important needed for the same reason as .st-btn's background-position/repeat/size above:
       AjaxSetButtonBackgroundImage sets the `background` shorthand inline to apply the icon, which
       silently resets background-color to transparent alongside it. */
    background-color: var(--st-accent) !important;
    border-color: var(--st-accent);
}
#divHomeLayoutButtons .st-btn-outline:hover {
    /* Same inline-shorthand-reset issue as .active above — background-color needs !important here too. */
    background-color: color-mix(in srgb, var(--st-accent) 20%, transparent) !important;
}



/* ------------------------------------------------------- */
/* StDock - vanilla JS/CSS dock layout engine styles       */
/* Replaces the Infragistics igc-dockmanager theme CSS     */
/* (standardtime-dockmanager.css)                          */
/* ------------------------------------------------------- */
/*
   Skin variables consumed (all defined in standardtime-skin-variables.css
   and overridden per skin in Content/skins/st-*.css):

     --st-dock-header-bg     chrome background (tab strips, pane headers, gaps)
     --st-dock-text          chrome text color (tabs, headers, edge tabs)
     --st-dock-border        borders between chrome and content
     --st-dock-pane-bg       pane/tab content background
     --st-dock-splitter      splitter drag bar color
     --st-dock-active-tab    selected tab / active header background
     --st-new-tab-flash      new-tab flash animation color

   Icons are drawn with CSS mask-image + background-color: currentColor so they
   always follow the skin text color. Do NOT replace them with Unicode glyphs:
   on some Windows font configurations the browser substitutes a colored icon
   font that ignores the CSS color property entirely (same problem that forced
   the StTree caret to be a CSS border-triangle).
*/


/* ------------------------------------------------------- */
/* Root and persistent chrome                               */
/* ------------------------------------------------------- */

.st-dock {
    display: flex;
    flex-direction: row;
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
    background-color: var(--st-dock-header-bg);
    color: var(--st-dock-text);
    font-size: calc(8pt + 0.15vw);
}

/* Hidden parking lot for slot divs not currently shown in a pane.
   display:none (not visibility) so lazy-loader IntersectionObservers
   do not fire until the content actually appears in a pane. */
.st-dock-store {
    display: none;
}

.st-dock-frame {
    display: flex;
    flex-direction: row;
    flex: 1 1 0px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

/* Top-level branches (one per layout.rootPane.panes[i]) - hidden until they have content */
.st-dock-branch {
    display: none;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.st-dock-branch.st-dock-visible {
    display: flex;
    flex-direction: column;
}


/* ------------------------------------------------------- */
/* Split containers and splitters                           */
/* ------------------------------------------------------- */

.st-dock-split {
    display: flex;
    flex: 1 1 0px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.st-dock-split-h {
    flex-direction: row;
}

.st-dock-split-v {
    flex-direction: column;
}

.st-dock-splitter {
    flex: 0 0 8px;
    background-color: var(--st-dock-splitter);
    touch-action: none;
    z-index: 2;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

/* Root-frame splitters are hidden until both neighbors are visible */
.st-dock-frame > .st-dock-splitter {
    display: none;
}

.st-dock-frame > .st-dock-splitter.st-dock-visible {
    display: block;
}

.st-dock-splitter-col {
    cursor: ew-resize;
    position: relative;
}

/* Centered "grabber" line hinting the vertical splitter is draggable. Absolutely
   positioned (not flex-centered) so it does not fight the .st-dock-frame > .st-dock-splitter
   display:block/none show-hide rule on root-frame splitters. */
.st-dock-splitter-col::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 2px;
    height: 88px;
    border-radius: 1px;
    background-color: color-mix(in srgb, var(--st-dock-text) 90%, transparent);
    pointer-events: none;
}

.st-dock-splitter-row {
    cursor: ns-resize;
    position: relative;
}

/* Centered horizontal "grabber" line for the horizontal splitter (mirrors the vertical
   splitter's grabber, rotated 90 degrees). Absolutely positioned, same as the column one. */
.st-dock-splitter-row::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 88px;
    height: 2px;
    border-radius: 1px;
    background-color: color-mix(in srgb, var(--st-dock-text) 90%, transparent);
    pointer-events: none;
}

.st-dock-splitter:hover {
    filter: brightness(1.25);
}

/* While dragging a splitter, keep the resize cursor everywhere and stop text selection */
body.st-dock-resizing-col {
    cursor: ew-resize !important;
    user-select: none;
}

body.st-dock-resizing-row {
    cursor: ns-resize !important;
    user-select: none;
}


/* ------------------------------------------------------- */
/* Panes (docked tool panes: Filter / Properties / Settings)*/
/* ------------------------------------------------------- */

.st-dock-pane,
.st-dock-tabgroup {
    display: flex;
    flex-direction: column;
    flex: 1 1 0px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    background-color: var(--st-dock-pane-bg);
    border: 1px solid var(--st-dock-border);
}

/* The flyout title bar (standardtime-dockengine.js _ensureChrome) carries both
   st-dock-pane-header and st-dock-flyout-header - intentionally no separate rule below for the
   latter, the flyout header is meant to look identical to a docked pane header. */
.st-dock-pane-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    /* Line the Filter/Properties column top-bars up with the document tab strip
       (.st-dock-tabstrip-top, a 39px box). Those tool columns are wrapped in
       .st-dock-pane / .st-dock-tabgroup, which carries a 1px border on ALL sides
       (the document column's .st-dock-docgroup has no border), so the wrapper's 1px
       TOP border sits above this header. 38px header + that 1px top border = 39px,
       matching the document strip; a solid 39px here made the tool top-bars read 1px
       too tall. The border-bottom mirrors the tab strip's own 1px separator. */
    flex: 0 0 38px;
    padding: 0 4px 0 8px;
    background-color: var(--st-dock-header-bg);
    color: var(--st-dock-text);
    border-bottom: 1px solid var(--st-dock-border);
    overflow: hidden;
    user-select: none;
}

.st-dock-pane-title {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.st-dock-header-spacer {
    flex: 1 1 0px;
}

.st-dock-pane-body {
    flex: 1 1 0px;
    min-height: 0;
    overflow: hidden;
    position: relative;
}

/* Slot divs fill their pane body */
.st-dock-pane-body > [slot],
.st-dock-flyout-body > [slot],
.st-dock-doc-body > [slot] {
    width: 100%;
    height: 100%;
}

/* In shared bodies (document host, tool tab groups) only the active slot shows */
.st-dock-doc-body > [slot],
.st-dock-pane-body > [slot] {
    display: none;
}

.st-dock-doc-body > [slot].st-dock-slot-active,
.st-dock-pane-body > [slot].st-dock-slot-active,
.st-dock-pane-body > [slot]:only-child {
    display: block;
}

.st-dock-flyout-body > [slot] {
    display: block;
}


/* ------------------------------------------------------- */
/* Document host and document tabs                          */
/* ------------------------------------------------------- */

.st-dock-dochost,
.st-dock-docgroup {
    display: flex;
    flex-direction: column;
    flex: 1 1 0px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.st-dock-tabstrip {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    flex: 0 0 30px;
    background-color: var(--st-dock-header-bg);
    border-bottom: 1px solid var(--st-dock-border);
    overflow: hidden;
    user-select: none;
}

.st-dock-tabstrip-bottom {
    border-bottom: none;
    border-top: 1px solid var(--st-dock-border);
}

/* The document tab strip (standardtime-dockengine.js _buildDocGroup) carries
   st-dock-tabstrip-top. Restore the pre-migration document-tab metrics: a ~32px tab
   with a 6px gap above. Box-sizing is border-box (Bootstrap global), so the 39px basis
   resolves to 6px padding-top + 32px stretched tab + 1px border-bottom - the same 39px
   box the tool-pane headers use. The base 30px basis (which nets 29px tabs and no top
   gap) stays in force for the bottom tool-pane strip. The visible top edge belongs on
   each TAB (see .st-dock-tab border-top), not on the strip. */
.st-dock-tabstrip-top {
    flex: 0 0 39px;
    padding-top: 6px;
}

.st-dock-tabs {
    display: flex;
    flex-direction: row;
    flex: 1 1 0px;
    min-width: 0;
    overflow-x: hidden;
    scroll-behavior: smooth;
    /* positioned so tab offsetLeft is measured against the strip (see StDock._scrollTabIntoView) */
    position: relative;
}

.st-dock-tab {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex: 0 0 auto;
    max-width: 220px;
    padding: 0 6px 0 12px;
    color: var(--st-dock-text);
    background-color: transparent;
    border-right: 1px solid var(--st-dock-border);
    /* Each tab gets its own 1px dark top edge, matching border-right, so the tab reads
       as a subtly outlined cell - the pre-migration Infragistics look. Same
       var(--st-dock-border) as the sides; spans only the tabs, not the full strip. */
    border-top: 1px solid var(--st-dock-border);
    cursor: pointer;
    white-space: nowrap;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-dock-tab:hover {
    background-color: color-mix(in srgb, var(--st-dock-active-tab) 45%, transparent);
}

.st-dock-tab.st-active {
    background-color: var(--st-dock-active-tab);
    /* Fat accent highlight along the bottom of the selected tab (pre-migration look).
       An inset box-shadow draws it over the tab bg without touching the box model, so
       the selected tab's height and label position stay identical to inactive tabs. */
    box-shadow: inset 0 -3px 0 0 var(--st-accent);
    /* Selected tab text takes on the accent, lightened toward white so it stays legible
       on the dark active-tab background and reads clearly different from the white
       inactive-tab text. */
    color: color-mix(in srgb, var(--st-accent) 70%, white);
}

.st-dock-tab.st-dock-tab-dragging {
    opacity: 0.65;
    cursor: grabbing;
}

/* While a tab reorder drag is in progress, force the grab cursor everywhere (mirrors the
   splitter body-cursor pattern). grabbing - a move/reorder hint, NOT a resize cursor - is
   the right affordance for dragging a tab. */
body.st-dock-dragging-tab,
body.st-dock-dragging-tab * {
    cursor: grabbing !important;
    user-select: none;
}

.st-dock-tab-label {
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: none;
}

.st-dock-doc-body {
    flex: 1 1 0px;
    min-height: 0;
    overflow: hidden;
    position: relative;
    background-color: var(--st-dock-pane-bg);
}

/* New-tab flash - keyframes live here (no shadow DOM anymore, so ordinary page CSS reaches the tab) */
@keyframes st-dock-tab-pulse {
    0%   { background-color: var(--st-dock-active-tab); }
    30%  { background-color: var(--st-new-tab-flash, yellow); }
    100% { background-color: var(--st-dock-active-tab); }
}

.st-dock-tab.st-dock-tab-flash {
    animation: st-dock-tab-pulse 1s ease-out;
}


/* ------------------------------------------------------- */
/* Buttons and icons (CSS mask, colored by currentColor)    */
/* ------------------------------------------------------- */

.st-dock-btn {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-left: 2px;
    padding: 0;
    border: none;
    border-radius: 3px;
    background-color: transparent;
    color: inherit;
    cursor: pointer;
    position: relative;
}

.st-dock-btn:hover {
    background-color: color-mix(in srgb, currentColor 22%, transparent);
}

.st-dock-btn::before {
    content: "";
    position: absolute;
    inset: 3px;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* X (close) - two crossing strokes */
.st-dock-btn-close::before,
.st-dock-tab-close::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4 L12 12 M12 4 L4 12' stroke='black' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4 L12 12 M12 4 L4 12' stroke='black' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
}

/* Pushpin - head, needle, base line */
.st-dock-btn-pin::before,
.st-dock-btn-unpin::before {
    /* Enlarge the pushpin: the shared .st-dock-btn::before inset is 3px (14px mask box);
       the pin shape only fills part of its viewBox so it read small. A 1px inset grows the
       mask box to 18px. Scoped to pin/unpin only - the pane-header close X keeps 3px. */
    inset: 1px;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 2 L10 2 L10 7 L12 9 L4 9 L6 7 Z M7.3 9 L8.7 9 L8 14 Z' fill='black'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 2 L10 2 L10 7 L12 9 L4 9 L6 7 Z M7.3 9 L8.7 9 L8 14 Z' fill='black'/%3E%3C/svg%3E");
}

/* Docked pane shows the pin rotated (VS convention: click to unpin / lay the pin down) */
.st-dock-btn-unpin::before {
    transform: rotate(45deg);
}

/* Tab close X - sits inside the tab (sized to match the pre-migration Infragistics X) */
.st-dock-tab-close {
    width: 18px;
    height: 18px;
    margin-left: 6px;
    border: none;
    border-radius: 3px;
    padding: 0;
    background-color: transparent;
    color: inherit;
    cursor: pointer;
    position: relative;
    flex: 0 0 auto;
}

.st-dock-tab-close:hover {
    background-color: color-mix(in srgb, currentColor 22%, transparent);
}

.st-dock-tab-close::before {
    content: "";
    position: absolute;
    inset: 1px;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
    /* Tab-close X spans a wider slice of the viewBox (3..13 of 16) than the shared
       .st-dock-btn-close X above (4..12), so the visible glyph reads ~10-11px to match
       the larger, thinner pre-migration Infragistics tab close X. Scoped to the tab
       close only - the pane-header close button keeps the shared narrower X. */
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3 L13 13 M13 3 L3 13' stroke='black' stroke-width='1.6' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3 L13 13 M13 3 L3 13' stroke='black' stroke-width='1.6' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
}

/* Overflow ("all tabs") chevron button - hidden until tabs overflow */
.st-dock-tab-more {
    display: none;
    align-self: center;
}

.st-dock-tab-more.st-dock-visible {
    display: block;
}

.st-dock-tab-more::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 6 L8 11 L13 6' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 6 L8 11 L13 6' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
}

/* "+" New Tab button - a child of .st-dock-tabs (not the strip), sitting immediately after the
   last tab, Chrome-style; always visible, unlike the overflow chevron above. Chrome-style circular
   bluish hover highlight, overriding .st-dock-btn's shared square-ish currentColor hover.
   Sized up to 28px (vs the shared 20px) for a bigger, softer-looking circle, closer to Chrome's own
   proportions; ::before's inset grows to match (7px vs the shared 3px) so the plus glyph itself
   stays the same 14px visual size instead of scaling up with the circle. */
.st-dock-tab-new {
    align-self: center;
    margin-left: 6px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

/* box-shadow blur (no spread) feathers the circle's edge into the tab strip instead of cutting off
   sharply - box-shadow's blur/color both interpolate smoothly via the transition above, unlike a
   radial-gradient background (gradients don't transition reliably cross-browser). Kept small (2px)
   so it just softens the boundary rather than reading as a diffuse glow/halo. */
.st-dock-tab-new:hover {
    background-color: var(--st-accent-hover);
    box-shadow: 0 0 2px 0 var(--st-accent-hover);
}

/* --st-accent-hover is a low-contrast TINT calibrated against each skin's own page background, not
   against the dock's currentColor (which is calibrated against the dark dock header instead) - on
   dark skins --st-accent-hover is itself dark (e.g. st-dark.css: #313244), so currentColor (light,
   for readability on the dark dock header) would render a light plus glyph on a light-tinted circle
   in light skins - the "faint plus" contrast problem - or a light glyph on a dark circle in dark
   skins. --st-text-body is the paired variable already used for this exact situation elsewhere
   (see --st-grid-hover-text's own comment) - it flips dark/light per skin to match --st-accent-hover
   consistently, which currentColor cannot do. */
.st-dock-tab-new:hover::before {
    background-color: var(--st-text-body);
}

.st-dock-tab-new::before {
    inset: 7px;
    transition: background-color 0.3s ease;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3 L8 13 M3 8 L13 8' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3 L8 13 M3 8 L13 8' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
}


/* ------------------------------------------------------- */
/* Tab overflow menu                                        */
/* ------------------------------------------------------- */

.st-dock-tab-menu {
    position: absolute;
    z-index: 60;
    min-width: 180px;
    max-width: 320px;
    max-height: 60%;
    overflow-y: auto;
    background-color: var(--st-dock-pane-bg);
    color: var(--st-text-body, #000);
    border: 1px solid var(--st-dock-border);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.st-dock-tab-menu-item {
    padding: 6px 12px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.st-dock-tab-menu-item:hover {
    background-color: color-mix(in srgb, var(--st-dock-active-tab) 30%, transparent);
}

.st-dock-tab-menu-item.st-active {
    background-color: var(--st-dock-active-tab);
    color: var(--st-dock-text);
}


/* ------------------------------------------------------- */
/* Edge strips (unpinned pane tabs) and flyout              */
/* ------------------------------------------------------- */

.st-dock-edge {
    display: none;
    flex-direction: column;
    flex: 0 0 38px;
    background-color: var(--st-dock-header-bg);
    overflow: hidden;
    user-select: none;
}

.st-dock-edge.st-dock-visible {
    display: flex;
}

.st-dock-edge-left {
    border-right: 1px solid var(--st-dock-border);
}

.st-dock-edge-right {
    border-left: 1px solid var(--st-dock-border);
}

.st-dock-edge-tab {
    writing-mode: vertical-rl;
    /* Horizontal padding centers the vertical text in the ~38px-wide strip (physical
       left/right padding regardless of writing-mode). */
    padding: 12px 11px;
    margin: 2px 0;
    color: var(--st-dock-text);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-height: 200px;
}

.st-dock-edge-tab:hover {
    background-color: color-mix(in srgb, var(--st-dock-active-tab) 45%, transparent);
}

.st-dock-edge-tab.st-active {
    background-color: var(--st-dock-active-tab);
}

.st-dock-flyout {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 50;
    background-color: var(--st-dock-pane-bg);
    border: 1px solid var(--st-dock-border);
    overflow: hidden;
}

.st-dock-flyout.st-dock-open {
    display: flex;
}

.st-dock-flyout-left {
    box-shadow: 6px 0 14px rgba(0, 0, 0, 0.38);
}

.st-dock-flyout-right {
    box-shadow: -6px 0 14px rgba(0, 0, 0, 0.38);
}

.st-dock-flyout-body {
    flex: 1 1 0px;
    min-height: 0;
    overflow: hidden;
    position: relative;
}


/* ------------------------------------------------------- */
/* Slot content classes (carried over unchanged from        */
/* standardtime-dockmanager.css - referenced by             */
/* DockManagerPartialView.cshtml and                        */
/* AddNewDockManagerSlotContentDiv)                         */
/* ------------------------------------------------------- */

.dockManagerContent {
    padding: 0.0rem;
    background-color: var(--st-bg-body);
    color: var(--st-text-body);
    height: 100%;
    overflow: hidden;
}

.dockManagerPartialView {
    height: 100%;
    overflow: hidden;
    background-color: var(--st-bg-body);
    color: var(--st-text-body);
    font-size: calc(8pt + 0.25vw);
}


/* ------------------------------------------------------- */
/* Standard Time Gantt chart styles                        */
/* ------------------------------------------------------- */

/* IG grid sets padding:4px and vertical-align:middle on all <td> cells.
   For gantt cells that combination offsets bars ~8px down (4px padding +
   4px centering when row height > ganttcelldiv height). Override both. */
td:has(.ganttcelldiv) {
    padding: 2px 0 0 0 !important;
    vertical-align: top !important;
}

.ganttitem {
    /*Used to find all gantt items on the entire page used*/
    /*Put actual styles in other classes*/
}

/* ------------------------------------------------------- */
/* Plain Gantt bar                                         */
/* ------------------------------------------------------- */
.ganttbar {
    background-color: var(--st-gantt-bar-bg);
    height: 10px;
    border-radius: 3px;
    cursor: ew-resize;
    transform: translateY(50%);
    -webkit-print-color-adjust: exact;
    color: var(--st-text-body);
    font-size: 8pt;
    font-weight: 700;
    vertical-align: top;
    text-align: center;
    white-space: nowrap;
}

/* Enlarge button image slightly during hover*/
.ganttbar:hover {
    border-width:1px;
    border-style:dotted;
    border-color: var(--st-text-body);
    /*background-color: #ebebff !important;*/
    /*transform: translateY(50%) scale(1.1);*/
}


/* ------------------------------------------------------- */
/* Critical path bar classes                               */
/* ------------------------------------------------------- */
.ganttbar-critical {
    background: linear-gradient(to right,
        var(--st-gantt-critical-bar-start),
        var(--st-gantt-critical-bar-end)) !important;
    color: #ffffff;
}

.ganttbar-noncritical {
    background: linear-gradient(to right,
        var(--st-gantt-noncritical-bar-start),
        var(--st-gantt-noncritical-bar-end)) !important;
    color: #ffffff;
}

.ganttsummarybar.ganttbar-noncritical {
    background: var(--st-gantt-summary-bg) !important;
}


/* ------------------------------------------------------- */
/* Float (slack) indicator bar                             */
/* ------------------------------------------------------- */
.ganttfloatbar {
    background-color: var(--st-gantt-float-bar-bg);
    border: 1.5px dashed var(--st-gantt-float-bar-stroke);
    height: 10px;
    border-radius: 2px;
    position: relative;
    transform: translateY(50%);
    -webkit-print-color-adjust: exact;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.ganttfloatbar-label {
    color: var(--st-gantt-float-bar-text);
    font-size: 9px;
    font-weight: 400;
    white-space: nowrap;
    pointer-events: none;
}


/* ------------------------------------------------------- */
/* Baseline comparison ghost bar                           */
/* ------------------------------------------------------- */
.ganttbar-baseline {
    height: 4px;
    background-color: var(--st-gantt-baseline-bar);
    border: 1px solid var(--st-gantt-baseline-bar);
    border-radius: 2px;
    pointer-events: none;
    opacity: 0.7;
    -webkit-print-color-adjust: exact;
}

/* Baseline milestone ghost diamond — outline only, no fill */
.ganttbarmilestone-baseline {
    height: 12px;
    width: 12px;
    border-radius: 2px;
    transform: translateY(50%) rotate(45deg);
    border: 2px solid var(--st-gantt-baseline-bar);
    background-color: transparent;
    pointer-events: none;
    opacity: 0.7;
}


/* ------------------------------------------------------- */
/* Weekend shading — scale header cells (Days scale only)  */
/* ------------------------------------------------------- */
/* Cell rows use a CSS repeating-linear-gradient set in JS (no extra DOM nodes).
   Scale header cells use a CSS class because they are individual divs. */
.ganttscalecell-weekend {
    background-color: var(--st-gantt-weekend-scale-bg);
}


/* ------------------------------------------------------- */
/* Today marker line                                       */
/* ------------------------------------------------------- */
.gantttoday {
    border-right: 2px solid var(--st-gantt-today-color);
    height: 100%;
    width: 0;
    pointer-events: none;
    -webkit-print-color-adjust: exact;
}

.ganttscalecell-today {
    background-color: var(--st-gantt-today-color);
    color: #ffffff;
    font-weight: bold;
}

.gantttoday-label {
    position: absolute;
    top: 1px;
    left: 3px;
    display: inline-flex;
    align-items: center;
    height: 11px;
    font-size: 7px;
    font-weight: bold;
    color: #ffffff;
    background-color: var(--st-gantt-today-color);
    padding: 0 3px;
    border-radius: 3px;
    white-space: nowrap;
    pointer-events: none;
    line-height: 1;
    -webkit-print-color-adjust: exact;
}


/* ------------------------------------------------------- */
/* Summary Gantt bar                                       */
/* ------------------------------------------------------- */
.ganttsummarybar {
    background-color: var(--st-gantt-summary-bg);
    height: 12px;
    cursor: ew-resize;
    transform: translateY(50%);
    -webkit-print-color-adjust: exact;
    color: var(--st-text-body);
    font-size: 8pt;
    font-weight: 700;
    vertical-align: top;
    text-align: center;
    white-space: nowrap;
}

.ganttsummarybar-sub {
    height: 10px;
}

/* Enlarge button image slightly during hover*/
.ganttsummarybar:hover {
    border-width:1px;
    border-style:dotted;
    border-color: var(--st-text-body);
    /*background-color: #FFD580 !important;*/
    /*transform: translateY(50%) scale(1.1);*/
}

.ganttpercentbar {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    height: 3px;
    background-color: var(--st-gantt-percent-bg);
    border-radius: 3px;
    pointer-events: none;
    -webkit-print-color-adjust: exact;
}

.gantt-bar-resize-handle {
    position: absolute;
    top: 0;
    width: 6px;
    height: 100%;
    cursor: ew-resize;
    z-index: 1;
}



/* ------------------------------------------------------- */
/* Milestone Gantt diamond                                 */
/* ------------------------------------------------------- */
.ganttmilestonediamond {
    width: 0;
    height: 0;
    border: 7px solid transparent;
    border-bottom-color: var(--st-gantt-milestone-color);
    position: relative;
    top: -7px;
    transform: translateY(10%);
    -webkit-print-color-adjust: exact;
}
.ganttmilestonediamond:after {
    content: '';
    position: absolute;
    left: -7px;
    top: 7px;
    width: 0;
    height: 0;
    border: 7px solid transparent;
    border-top-color: var(--st-gantt-milestone-color);
}

.ganttbarmilestone {
    border-width: 1px;
    border-style: solid;
    border-color: var(--st-gantt-milestone-color);
    background-color: var(--st-gantt-milestone-bg);
    height: 12px;
    width: 12px;
    border-radius: 2px;
    cursor: ew-resize;
    transform: translateY(50%) rotate(45deg);
    -webkit-print-color-adjust: exact;
    color: var(--st-text-body);
    font-size: 8pt;
    font-weight: 700;
    vertical-align: top;
    text-align: center;
    white-space: nowrap;
}

.ganttbarmilestone:hover {
    border-width: 2px;
    border-style: dotted;
    border-color: var(--st-text-body);
    /*background-color: #FFD580 !important;*/
    /*transform: translateY(50%) scale(1.1);*/
}


/* ------------------------------------------------------- */
/* Gantt Scale                                             */
/* ------------------------------------------------------- */
.ganttscale {
}

.ganttscalecell {
    /*color: black;*/
    /*background-color: white;*/
    font-size: calc(4pt + 0.25vw);
    border-right: solid;
    border-width: 1px;
    border-collapse: collapse;
    border-color: var(--st-gantt-scale-border);
    text-align: center;
    overflow: hidden;
}

.ganttgridline {
    border-right: solid;
    border-width: 1px;
    border-collapse: collapse;
    border-color: var(--st-gantt-gridline);
    -webkit-print-color-adjust: exact;
}

.ganttscaleheadercell {
    font-size: calc(4pt + 0.25vw);
    border-right: solid;
    border-width: 1px;
    border-collapse: collapse;
    border-color: var(--st-gantt-scale-border);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    overflow: hidden;
    -webkit-print-color-adjust: exact;
}

.ganttscalerowcell {
    font-size: calc(4pt + 0.25vw);
    border-right: solid;
    border-width: 1px;
    border-collapse: collapse;
    border-color: var(--st-gantt-gridline);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    overflow: hidden;
    -webkit-print-color-adjust: exact;
}

.ganttsummarytriangle {
    position: fixed;
    width: 0;
    height: 0;
    padding: 0px;
    margin: 0px;
    top: 0px;
    border: 7px solid transparent;
    border-top: 15px solid var(--st-gantt-summary-triangle);
    border-bottom: 0;
    transform: translateY(20%);
    -webkit-print-color-adjust: exact;
}

/* ------------------------------------------------------- */
/* Summary bar child milestone diamond                     */
/* ------------------------------------------------------- */
.gantt-summary-milestone {
    background-color: #ffffff;
    border: 1.5px solid #000000;
    height: 8px;
    width: 8px;
    border-radius: 1px;
    transform: rotate(45deg);
    cursor: default;
    -webkit-print-color-adjust: exact;
}




/* ------------------------------------------------------- */
/* Plain Gantt bar while dragging                          */
/* ------------------------------------------------------- */
.ganttbardragging {
    background-color: var(--st-gantt-drag-bg);
    color: var(--st-accent-text);
    font-size: 8pt;
    font-weight: 700;
    vertical-align: top;
    text-align: center;
    white-space: nowrap;
    height: 10px;
    border-radius: 3px;
    cursor: ew-resize;
    -webkit-print-color-adjust: exact;
}

.ganttlinkline {
    stroke: var(--st-gantt-link-color);
    stroke-width: 4px;
    opacity: 50%;
    fill: none;
    animation: dash 1s linear forwards;
    stroke-dasharray: 200;
    stroke-dashoffset: 200;
}

.ganttlinkline-critical {
    stroke: var(--st-gantt-critical-arrow);
    opacity: 0.75;
}

.ganttlinkline-noncritical {
    stroke: var(--st-gantt-noncritical-arrow);
    opacity: 0.5;
}

/* Applied to predecessor and successor bar divs while their connecting arrow is hovered. */
/* outline (not box-shadow) so the ring is not clipped by ganttcelldiv's overflow:hidden. */
.ganttbar-link-highlight {
    outline: 2px solid var(--st-accent);
    outline-offset: 1px;
    position: relative;
    z-index: 5;
}

/* Applied to the visible SVG path while its hit area is hovered. */
.ganttlinkline-highlight {
    opacity: 1 !important;
    stroke-width: 6px !important;
}

.fade-in {
    opacity: 1;
    animation-name: fadeInOpacity;
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    animation-duration: 2s;
}

@keyframes fadeInOpacity {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes dash {
    to {
        stroke-dashoffset: 0;
    }
}


/* ------------------------------------------------------- */
/* Gantt scale hover navigation buttons                    */
/* ------------------------------------------------------- */
.gantt-nav-left,
.gantt-nav-right {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: 1px;
    z-index: 10;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none;    /* Firefox */
    -ms-user-select: none;     /* IE 10+ */
    user-select: none;
}

.gantt-nav-left  { left: 2px; }
/* left:100% places the group's left edge at the <th> right boundary;
   translateX(-100%-2px) pulls it back by its own width + margin — no JS needed. */
.gantt-nav-right { left: 100%; transform: translate(calc(-100% - 2px), -50%); }

th:has(.ganttscale):hover .gantt-nav-left,
th:has(.ganttscale):hover .gantt-nav-right,
.gantt-nav-left:hover,
.gantt-nav-right:hover {
    opacity: 1;
    pointer-events: auto;
}

.gantt-nav-btn {
    background: rgba(255, 255, 255, 0.85);
    color: #333333;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: 2px;
    padding: 0 4px;
    font-size: 16px;
    font-weight: bold;
    line-height: 1;
    cursor: pointer;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.gantt-nav-btn-wide {
    width: 34px;
}

.gantt-nav-circle {
    display: inline-block;
    width: 12px;
    height: 12px;
    background: currentColor;
    border-radius: 50%;
    flex-shrink: 0;
}

.gantt-nav-glyph {
    display: flex;
    align-items: center;
    gap: 1px;
    line-height: 1;
}

.gantt-nav-glyph svg {
    width: 20px;
    height: 20px;
    display: block;
}

.gantt-nav-glyph-flip {
    transform: scaleX(-1);
}

.gantt-nav-btn:hover {
    background: rgba(0, 0, 0, 0.55);
    color: #ffffff;
    border-color: rgba(0, 0, 0, 0.4);
}

.gantt-zoom-label {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 9px;
    background: rgba(255, 255, 255, 0.70);
    color: #666666;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 3px;
    padding: 1px 5px;
    pointer-events: none;
    white-space: nowrap;
    -webkit-print-color-adjust: exact;
}


/* ***********************************************************************************
   ** Gantt mini-map ("Special rows" > Gantt mini-map) - drawing/interaction styles ***
   *********************************************************************************** */

/* ------------------------------------------------------- */
/* Resize drag helper pill - follows the cursor while dragging a handle, removed on drop */
/* ------------------------------------------------------- */
.ganttminimap-resize-pill {
    position: fixed;
    z-index: 9999;
    background-color: var(--st-gantt-today-color, #c2580a);
    color: #ffffff;
    font-size: 11px;
    font-weight: bold;
    padding: 3px 8px;
    border-radius: 10px;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    -webkit-print-color-adjust: exact;
}

/* ------------------------------------------------------- */
/* Compressed bar - one thin translucent band per real row */
/* ------------------------------------------------------- */
.ganttminimap-bar {
    background-color: var(--st-gantt-minimap-bar-bg);
    -webkit-print-color-adjust: exact;
    pointer-events: none;
}

/* ------------------------------------------------------- */
/* Viewport rectangle - draggable window onto the real Gantt */
/* ------------------------------------------------------- */
.ganttminimap-viewport {
    background-color: var(--st-gantt-minimap-viewport-bg);
    border: 2px solid var(--st-gantt-minimap-viewport-border);
    border-radius: 1px;
    box-sizing: border-box;
    cursor: grab;
    -webkit-print-color-adjust: exact;
}

.ganttminimap-viewport:active {
    cursor: grabbing;
}

/* Solid edge tabs so the rectangle reads as a grabbable "window" rather than just an outline -
   matches the left/right drag-handle rects in MiniMapFeatureSuggestion.svg's viewport indicator.
   Independently draggable (BuildGanttMiniMapCell wires a separate StDraggable.make() per handle,
   on top of the viewport rectangle's own pan drag) to resize the window - ew-resize cursor and
   real pointer-events (not none, unlike every other decorative element in this file) reflect that. */
.ganttminimap-viewport-handle {
    position: absolute;
    top: 20%;
    bottom: 20%;
    width: 7px;
    background-color: var(--st-gantt-minimap-viewport-border);
    border-radius: 1px;
    cursor: ew-resize;
    -webkit-print-color-adjust: exact;
}

.ganttminimap-viewport-handle-left {
    left: -1px;
}

.ganttminimap-viewport-handle-right {
    right: -1px;
}

.ganttminimap-viewport-label {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 9px;
    white-space: nowrap;
    color: var(--st-gantt-minimap-viewport-border);
    pointer-events: none;
    -webkit-print-color-adjust: exact;
}

/* ------------------------------------------------------- */
/* Name-cell summary lines (Window Start / End / Days)      */
/* ------------------------------------------------------- */
/* Appended by UpdateGanttMiniMapOverviewLabel (standardtime-frozenrowganttminimap.js) below the
   "Overview" label, inside the row's own Name cell - a sibling of .st-grid-cell-content (the
   icon+label flex row _renderHierarchyName already builds, standardtime-gridengine.js), not a child of
   it, so it stacks BELOW that row instead of extending it sideways. white-space:pre-line renders the
   \n's UpdateGanttMiniMapOverviewLabel writes via .text() as real line breaks without ever going
   through .html() / needing <br> markup. font-weight:normal overrides tr.st-grid-group-row > td.st-
   grid-cell's own font-weight:600 (standardtime-gridengine.css, this row carries COL_GROUP=true) -
   these are secondary detail lines, not a second heading; font-size/opacity reinforce the same "smaller,
   quieter than the heading" hierarchy. margin-left is NOT set here - UpdateGanttMiniMapOverviewLabel
   sets it inline, per-render, measured off the actual rendered "Overview" text position (see that
   function's own comment) so these lines stay left-aligned with the word "Overview" - which starts past
   the icon+indent, not at this cell's raw left edge - regardless of density/font-size. */
.ganttminimap-daterange {
    white-space: pre-line;
    font-weight: normal;
    font-size: 0.65em;
    opacity: 0.75;
    margin-top: 4px;
}

/* Shown in place of .ganttminimap-daterange (never both - the "stgrid-rendered" listener in
   standardtime-frozenrowganttminimap.js that appends this only runs when there's no Gantt column at
   all, in which case BuildGanttMiniMapCell - the only thing that ever appends .ganttminimap-daterange -
   never runs either). Same muted, quieter-than-the-heading treatment. */
.ganttminimap-nocolumn-message {
    font-weight: normal;
    font-size: 0.7em;
    font-style: italic;
    opacity: 0.65;
    margin-top: 4px;
}

/* ------------------------------------------------------- */
/* Selected-cell override                                  */
/* ------------------------------------------------------- */
/* standardtime-gridengine.css's default selected-cell style (td.st-grid-cell.st-grid-cell-
   selected) is a solid opaque accent-color fill, which would completely hide the bars/viewport
   drawn underneath - swap to a thin outline instead so the mini-map stays visible while
   selected. Each selector below adds .ganttminimap-cell on top of the corresponding grid-engine
   selector specifically to out-specificity it (one extra class = always higher, regardless of
   stylesheet order) - group-row and hover both compound onto the base selected-cell rule there,
   and skipping either would silently fall back to the solid fill in exactly that state.
   Deliberately --st-gantt-today-color (orange), not --st-accent (the grid's normal selected-cell
   color, and also the mini-map's own viewport-rectangle color) - an accent outline here would
   read as a second little draggable window rather than "this cell is selected". */
td.st-grid-cell.st-grid-cell-selected.ganttminimap-cell,
tr.st-grid-row:hover > td.st-grid-cell.st-grid-cell-selected.ganttminimap-cell,
tr.st-grid-group-row > td.st-grid-cell.st-grid-cell-selected.ganttminimap-cell {
    background-color: transparent;
    color: inherit;
    outline: 2px solid var(--st-gantt-today-color, #c2580a);
    outline-offset: -2px;
}

/* Doubles as the "this cell is nudge-able with arrow keys" indicator (BuildGanttMiniMapCell's
   keydown.ganttminimap handler) - focus genuinely lands on this <td> on selection, unlike the
   grid's other cells where it's mostly incidental. Same orange as the non-focus rule above, not
   --st-focus-ring, for the same reason. */
td.st-grid-cell.st-grid-cell-selected.ganttminimap-cell:focus {
    outline: 2px solid var(--st-gantt-today-color, #c2580a);
    outline-offset: -2px;
}

/* ------------------------------------------------------- */
/* Row-level dark "shop-floor strip" theme, matching Mini WIP / Clocked-In-Out */
/* ------------------------------------------------------- */
/* Unlike Mini WIP/Clocked-In-Out (both a single .st-grid-frozenwide-cell colspan <td>), this row keeps
   its normal per-column <td>s - Name, the Gantt column, any others - so the compressed timeline stays
   under the exact same column the real Gantt bars render in below it.

   Set directly on the <tr>, NOT on td.st-grid-cell - a row can also contain td.st-grid-spacer and/or
   td.st-grid-insert-end filler cells (standardtime-gridengine.js's _buildRowHtml tail logic: a spacer
   when !fitCols100Perc && !_hasFillColumn, an insert-end cell whenever this.insertEndColumn is set -
   which ModelRecordsetGrid.cs sets unconditionally for every RecordsetGrid, Task/Gantt included, so at
   least one of these two filler cells is present on effectively every real render of this row). All
   three <td> kinds - st-grid-cell, st-grid-spacer, st-grid-insert-end - already declare their own
   `background-color: inherit` (standardtime-gridengine.css), so ONE rule here, on the row itself,
   reaches every cell kind automatically with no per-class list to keep in sync. `color` inherits by
   default (no `inherit` keyword needed) down to every descendant, including the resize grip's own
   `background-color: currentColor` (.st-grid-row-resize-handle) and .ganttcelldiv's own compressed-
   bar/viewport drawing - the same "set color on a real ancestor of both the content and the handle"
   shape the generic .st-grid-frozenwide-cell rule already uses for Mini WIP/Clocked-In-Out, just at
   row scope instead of cell scope since this row has more than one cell.
   Requires InsertGanttMiniMapRow to no longer set COL_ROWBKCOLOR (Part 1 above) - SetGridRowStyles
   (standardtime-grid.js) applies any COL_ROWBKCOLOR value as a literal inline background-color directly
   on the <tr>, which would always win over this class rule regardless of specificity; with it removed,
   BuildRowStylesJsonString (HomeController.cs) never builds a GridRowStyle entry for this row at all
   (bSummaryRow is also false here, since this row never sets COL_SUMMARY), so no inline style ever lands
   on the <tr> to fight this rule. */
tr.st-grid-ganttminimap-row {
    background-color: var(--st-frozenrow-bg, #343c4a);
    color: var(--st-frozenrow-text, #f4f6f8);
}

/* td.st-grid-cell specifically (NOT the spacer/insert-end fillers, which need no equivalent - see
   below) needs its own explicit override for the :hover state - without this, the grid's own
   `tr.st-grid-row:hover > td.st-grid-cell` (standardtime-gridengine.css) sets a LITERAL, opaque
   background directly on td.st-grid-cell that outranks the plain `tr.st-grid-ganttminimap-row` rule
   above ((0,0,3,2) vs (0,0,1,1), this file's own established 4-part specificity notation), so the row's
   normal light hover color would otherwise flash over the dark theme on every mouseover. This rule is
   ALSO (0,0,3,2) - a genuine tie with the base hover rule, resolved by source order:
   standardtime-frozenrowganttminimap.css loads after standardtime-gridengine.css in both the JS and CSS bundles
   (App_Start\BundleConfig.cs), so this rule wins. Deliberately NOT extended to the selected-cell state -
   ordinary accent-color selection feedback on this row's non-Gantt cells (Name, any blank columns) is
   left alone; only the incidental, constant hover flash is judged worth overriding here.
   td.st-grid-spacer/td.st-grid-insert-end need no :hover rule of their own: neither ever gets a literal
   hover-background rule anywhere in this codebase (both are pointer-events:none and non-interactive), so
   their own `background-color: inherit` keeps resolving to the <tr>'s plain-state rule above - which
   itself never changes on hover - through every mouseover with no extra CSS required. */
tr.st-grid-ganttminimap-row:hover > td.st-grid-cell {
    background-color: var(--st-frozenrow-bg, #343c4a);
    color: var(--st-frozenrow-text, #f4f6f8);
}

/* ------------------------------------------------------- */
/* Suppress vertical cell dividers outside the Gantt track  */
/* ------------------------------------------------------- */
/* Mini WIP/Clocked-In-Out get a seamless dark strip for free from being one colspan <td> - no internal
   vertical borders to begin with. This row can't be colspan (see the row-level theme comment above), so
   the same look is faked here: every non-Gantt td.st-grid-cell (Name, Start, Duration, Actual work, ...)
   loses its border-right, leaving only the two dividers that still mean something - going into the Gantt
   track and coming out of it. (0,0,3,2) beats the base td.st-grid-cell rule's (0,0,1,1)
   (standardtime-gridengine.css) - no !important needed. */
tr.st-grid-ganttminimap-row > td.st-grid-cell:not(.ganttminimap-cell) {
    border-right: none;
}

/* The "going in" divider (gantt-left) is drawn here, as the Gantt cell's OWN border-left, rather than
   left as the preceding cell's border-right (now suppressed above) - stays correct regardless of which
   column a user's own column order happens to put immediately before Gantt. border-left has shown no
   rendering problem in this row (confirmed live, and in every screenshot Ray has sent), so it's left as
   a plain border - only the RIGHT-side accents below needed the box-shadow workaround.

   "Gantt-right" (the row's own right-side accent, immediately after Gantt's real content) is drawn as
   an inset box-shadow, not border-right: this cell sits directly against the row's trailing auto-width
   td.st-grid-spacer filler in the common case (Gantt is this row's default last real column - stdata's
   ProjectTaskSet.GetDefaultGridColumns), and a real border-right there does not paint - confirmed live,
   the exact same failure diagnosed and fixed for the spacer's own former border-right below. The spacer's
   <col> is deliberately UNDEFINED width, so table-layout:fixed hands it whatever's left over after
   _syncTableWidth's explicit pixel sum of every OTHER column (standardtime-gridengine.js - the spacer is
   excluded from that sum on purpose, so it can stretch to fill the pane via the table's own `min-width:
   100%`); a real border on either side of that boundary adds to an already-resolved box's total width,
   pushing the painted line 1px past wherever the table's width/scroll math actually landed - invisible in
   practice even though computed style reports it correctly. box-shadow is pure paint, not layout, so it
   can't get pushed past the boundary that way. */
tr.st-grid-ganttminimap-row > td.st-grid-cell.ganttminimap-cell {
    border-left: 1px solid var(--st-grid-border, #dee2e6);
    border-right: none;    /* replaced by the box-shadow below - see this rule's own comment */
    box-shadow: inset -1px 0 0 var(--st-grid-border, #dee2e6);
}

/* "Grid-right": the row's default last real column is Gantt (handled above), but a custom column order -
   or another column dragged in after it, as Ray tested with "Client rate"/Duration - can put real
   content there instead. Each such trailing td.st-grid-cell gets the identical box-shadow accent on its
   own right edge (general-sibling match: every td.st-grid-cell that comes after .ganttminimap-cell),
   re-enabling exactly what the leading suppression rule above took away from it, for the same
   box-shadow-not-border-right reason - it too sits directly against the trailing spacer/insert-end
   filler. Confirmed live against a real trailing column (Duration placed after Gantt via a custom column
   order) after the plain-border-right version of this rule was confirmed NOT to paint there either. */
tr.st-grid-ganttminimap-row > td.st-grid-cell.ganttminimap-cell ~ td.st-grid-cell {
    box-shadow: inset -1px 0 0 var(--st-grid-border, #dee2e6);
}

/* ------------------------------------------------------- */
/* Close/Minimize/Restore controls (standardtime-frozenrowganttminimap.js's EnsureGanttMiniMapControls) */
/* ------------------------------------------------------- */
/* This row has no single colspan cell the way Mini WIP/Clocked-In-Out/Mini Resource Allocation do (see
   EnsureGanttMiniMapControls's own comment, standardtime-frozenrowganttminimap.js, for why the controls
   cluster is anchored into td.st-grid-row-resize-anchor - whichever column ends up LAST, not hardcoded
   to the Gantt column) - so the generic minimized-state rule in standardtime-gridengine.css (scoped to
   td.st-grid-frozenwide-cell) never reaches this row at all. Three separate rules below, each
   column-order-independent on purpose (Ray's own test moves Duration to render after Gantt):

   1. Name cell's own icon/text/date-range - always hidden regardless of where the anchor column is.
   2. Whatever the Gantt cell's own redraw loop drew (bars/viewport/today-marker/resize pill) - always
      hidden too, even on a render where the anchor (and therefore the controls cluster) is some OTHER
      column, not Gantt.
   3. Anything else in the anchor cell besides the controls cluster itself - covers both the resize grip
      (StGrid._buildRowResizeHandleHtml, always a sibling of whatever real content the anchor cell has)
      and, when the anchor happens to BE the Gantt column, rule 2 already got its content so this is a
      harmless no-op re-match there.

   .st-frozenrow-controls itself needs no positioning rule here - it inherits the same 16x16/gap/color/
   hover styling from standardtime-gridengine.css wholesale, and every cell in a frozen-top/bottom row
   already has `position: sticky` from the generic `.st-grid-frozen-top-row > td` rule there, which is
   all an absolutely-positioned child needs, regardless of which column it lands in. */
tr.st-grid-ganttminimap-row.st-frozenwide-minimized .st-grid-cell-content,
tr.st-grid-ganttminimap-row.st-frozenwide-minimized .ganttminimap-daterange,
tr.st-grid-ganttminimap-row.st-frozenwide-minimized .ganttminimap-nocolumn-message {
    display: none;
}
tr.st-grid-ganttminimap-row.st-frozenwide-minimized .ganttcelldiv > * {
    display: none;
}
tr.st-grid-ganttminimap-row.st-frozenwide-minimized td.st-grid-row-resize-anchor > *:not(.st-frozenrow-controls) {
    display: none;
}



.MiniHtmlTreeView {
    list-style-type: none;
    margin: 0;
    padding: 0;
}


.MiniHtmlTreeViewCaret {
    cursor: pointer;
    -webkit-user-select: none; /* Safari 3.1+ */
    -moz-user-select: none; /* Firefox 2+ */
    -ms-user-select: none; /* IE 10+ */
    user-select: none;
}

/* Caret glyph drawn as a CSS border-triangle rather than a Unicode glyph (was "\25B6") - Windows  */
/* substitutes a colored icon font for that character in some configurations, which ignores `color` */
/* entirely and always renders solid blue regardless of the CSS below. A border-triangle can't be    */
/* hijacked by font substitution since it isn't text. See standardtime-treeengine.css's              */
/* .st-tree-toggle::before for the same fix applied to StTree.                                       */
.MiniHtmlTreeViewCaret::before {
    content: "";
    display: inline-block;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 4px 0 4px 6px;
    border-color: transparent transparent transparent gray;
    margin-right: 6px;
    transition: transform 0.1s ease;
}

.MiniHtmlTreeViewCaretDown::before {
    -ms-transform: rotate(90deg); /* IE 9 */
    -webkit-transform: rotate(90deg); /* Safari */
    transform: rotate(90deg);
}

.MiniHtmlTreeViewNested {
    display: none;
    list-style-type: none;
}

.MiniHtmlTreeViewActive {
    display: block;
    list-style-type: none;
}

.MiniHtmlTreeViewChild {
    -webkit-user-select: none; /* Safari 3.1+ */
    -moz-user-select: none; /* Firefox 2+ */
    -ms-user-select: none; /* IE 10+ */
    user-select: none;
}

.MiniHtmlTreeViewNoCaret {
    cursor: pointer;
    -webkit-user-select: none; /* Safari 3.1+ */
    -moz-user-select: none; /* Firefox 2+ */
    -ms-user-select: none; /* IE 10+ */
    user-select: none;
}

/* Invisible placeholder matching the caret triangle's box (6px wide) so leaf-row text lines up */
/* with parent-row text, now that the caret is a sized border-triangle rather than a text glyph.  */
.MiniHtmlTreeViewNoCaret::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 8px;
    margin-right: 6px;
}

/*
 * standardtime-shottimer.css -- Barcode shot timer countdown (ring meter).
 * Spec: Feature enhancement md's\Barcoding shot time\ShotTimer.md (see SS5/SS7).
 * Visual design ported from ShotTimerPrototype.html in this same folder.
 *
 * DROP-IN FILE -- see standardtime-shottimer.js's header comment for the copy and
 * registration steps to run when implementation begins.
 */

/* Outer holder: zero width/opacity until a shot timer is active, so an idle screen is
   pixel-identical to today. Lives inline beside the barcode textarea -- as a sibling of
   the <textarea> inside .bc-textarea-wrapper in BarcodesPartialView.cshtml -- not in a
   separate row under the toolbar. See ShotTimer.md SS5 for the placement rationale and
   the flex-wrap fallback at narrow/small-app widths. */
.shottimer-ring-holder {
    flex: none;
    width: 0;
    height: 0;
    margin-left: 0;
    opacity: 0;
    overflow: hidden;
    transition: width 0.35s ease, height 0.35s ease, margin-left 0.35s ease, opacity 0.25s ease;
}

.shottimer-ring-holder.active {
    width: 148px;
    height: 148px;
    margin-left: 16px;
    opacity: 1;
}

.shottimer-widget {
    display: flex;
    align-items: center;
}

.shottimer-ring {
    position: relative;
    width: 148px;
    height: 148px;
    flex: none;
}

.shottimer-ring svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.shottimer-ring-track {
    fill: none;
    stroke: var(--st-border-color);
    stroke-width: 14;
}

.shottimer-ring-progress {
    fill: none;
    stroke: var(--st-success, #198754);
    stroke-width: 14;
    stroke-linecap: round;
    transition: stroke-dashoffset 0.9s linear, stroke 0.4s ease;
}

.shottimer-ring-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

.shottimer-digits {
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--st-text-body);
    transition: color 0.3s ease;
}

/* State coloring -- applied to both the ring stroke and the digits.
   --st-success / --st-warning / --st-danger are NOT defined as real custom properties
   anywhere in standardtime-skin-variables.css or any Content/skins/st-*.css file today
   (confirmed by grep against the live repo) -- this follows the same "aspirational token
   with a literal fallback" pattern already shipping in BarcodesPartialView.cshtml's own
   #BarcodeScanStateBadge rules, so every skin renders the same fixed green/amber/red
   regardless of skin choice. That is an existing, accepted pattern in this codebase, not
   a new gap introduced here -- but it is a real state of the world, not "confirmed to
   exist as skin variables" as an earlier draft of ShotTimer.md stated. */
.shottimer-widget[data-state="normal"] .shottimer-ring-progress { stroke: var(--st-success, #198754); }
.shottimer-widget[data-state="normal"] .shottimer-digits { color: var(--st-text-body); }

.shottimer-widget[data-state="yellow"] .shottimer-ring-progress { stroke: var(--st-warning, #ffc107); }
/* #a66a00, not the raw --st-warning amber (#ffc107) or a near-black amber -- #ffc107 on
   white is ~1.6:1 contrast (illegible) and a too-dark amber reads fine on white but fails
   on the dark/high-contrast skins' near-black body backgrounds. #a66a00 targets the same
   mid luminance the --st-danger/--st-success literals above already land at, giving it the
   same contrast profile they already have: ~4.5:1 on white, ~3.7:1 on st-dark.css's
   #1e1e2e body, ~4.7:1 on st-high-contrast.css's #000000 body -- legible across the full
   shipped skin range without adding a new skin-file token. */
.shottimer-widget[data-state="yellow"] .shottimer-digits { color: #a66a00; }

.shottimer-widget[data-state="red"] .shottimer-ring-progress { stroke: var(--st-danger, #dc3545); }
.shottimer-widget[data-state="red"] .shottimer-digits { color: var(--st-danger, #dc3545); }

.shottimer-widget[data-state="redflash"] .shottimer-ring-progress { stroke: var(--st-danger, #dc3545); }
.shottimer-widget[data-state="redflash"] .shottimer-digits { color: var(--st-danger, #dc3545); }
.shottimer-widget[data-state="redflash"] { animation: shottimer-flash-anim 0.6s steps(1, start) infinite; }

@keyframes shottimer-flash-anim {
    0%, 49%   { opacity: 1; }
    50%, 100% { opacity: 0.3; }
}

