/*
	standard-UI-display engine styles. Bootstrap 5.3 base; only the few rules the
	generated markup needs beyond the framework defaults.
*/

.sud-table th.sud-sort   { cursor: pointer; white-space: nowrap; user-select: none; }
.sud-table th.sud-sort i { opacity: .5; }

.sud-json-editor         { height: 18rem; }

.sud-help td             { background: rgba(0,0,0,.03); }
.sud-help-toggle         { font-size: .8rem; }

/* Stacked modals: each level the manager opens sits above the one beneath. The
   manager assigns z-index inline per level; these are only the base bumps so a
   nested dialog never renders behind its backdrop. */
.sud-modal-stacked       { z-index: 1056; }
.sud-modal-stacked + .modal-backdrop { z-index: 1055; }

/* The Character Lab wizard is an extra-large modal ( Bootstrap ships only up to modal-xl ). */
@media ( min-width: 1400px ) { .modal-xxl { max-width: 1560px; } }

/* Character Lab: the list progress badge, the animation-row door button, and the matrix cells. */
.sud-clab-badge          { display: inline-flex; }
.sud-clab-door           { display: inline-block; }
.clab-cell               { transition: box-shadow .12s ease; }
.clab-cell:hover         { box-shadow: 0 0 0 2px rgba( 13, 110, 253, .25 ); }

/* A board card's badge line: one non-wrapping row that scrolls sideways on the wheel or a
   left-button drag, with no bar of its own so the card keeps its height. The hide is scoped to
   this class alone, so the site-wide slim rails further down stand everywhere else. */
.clab-tagrow             { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.clab-tagrow::-webkit-scrollbar { display: none; }
.clab-tagrow.clab-pannable { cursor: grab; }
.clab-tagrow.grabbing    { cursor: grabbing; }

/* b2uPanel pagination ships negative margins ( b2upanel-mt-n30 / -mb-n50 ) tuned
   for another container; in the sud list they make the "Page size" row overlap
   the pager. Reset them so pager / page-input / page-size stack with a gap. */
.sud-section .b2upanel-mb-n50 { margin-bottom: 0; }
.sud-section .b2upanel-mt-n30 { margin-top: .5rem; }

/* The pager renders the "Page size" ( and mobile "Page" ) rows as a plain <ul><li>,
   not a Bootstrap .pagination list, so the <li> shows a default disc bullet. Strip
   the marker + its indent. */
.sud-section ul.b2upanel-mb-40 { list-style: none; padding-left: 0; }

/* Page-number input = the trailing member of the pager's input-group: match the
   .page-link height ( drop the plugin's fixed 34px ), butt it against the Last
   button ( shared border + flat left corners ), keep the right corners rounded. */
.sud-section .pagination .page-link[aria-label="Last"] { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.sud-section .pagination .b2upanel-page-input { height: auto !important; margin-left: -1px; border-top-left-radius: 0; border-bottom-left-radius: 0; position: relative; }
.sud-section .pagination .b2upanel-page-input:focus { z-index: 3; }

/* Tile list layout ( the toolbar's Tiles button ): a fixed portrait media box on the rows
   that carry a picture ( which covers it ), over a one-line title, the badges and one
   compact line per listed column. */
.sud-cards .sud-card-media       { aspect-ratio: 4 / 5; overflow: hidden; background: var(--bs-tertiary-bg); display: flex; align-items: center; justify-content: center; }
.sud-cards .sud-card-media img   { width: 100%; height: 100%; object-fit: cover; display: block; }
.sud-cards .sud-card-title       { font-weight: 600; }
.sud-cards .sud-card-cols        { margin-top: .25rem; }
.sud-cards .sud-card-cols > div  { line-height: 1.3; }

/* b2uPanel's loading overlay hardcodes a white fill + a fixed spinner, so in the
   portal's dark theme it flashes a white box with a near-invisible icon. Follow the
   active Bootstrap theme instead ( --bs-body-bg matches #fff in light ), and invert
   the spinner in dark so it reads on the dark fill. The [data-bs-theme] prefix out-
   specifies the plugin rule, so this wins regardless of stylesheet load order, and
   covers both the plugin's own overlay and AMMSApp.overlay()'s. */
[data-bs-theme] .b2upanel-loading-overlay      { background: var(--bs-body-bg); }
[data-bs-theme="dark"] .b2upanel-loading-image { filter: invert(1) hue-rotate(180deg); }

/* jquery-confirm ( $.confirm ) ships a light theme - near-invisible text on a
   white box in the portal's dark theme. Follow the active Bootstrap theme so the
   dialog reads in both modes ( dialogs mount at <body>, outside #sud-page, so
   this stays global ). */
.jconfirm .jconfirm-box                   { background: var(--bs-body-bg) !important; color: var(--bs-body-color) !important; }
.jconfirm .jconfirm-box .jconfirm-title   { color: var(--bs-emphasis-color) !important; }
.jconfirm .jconfirm-box .jconfirm-content { color: var(--bs-body-color) !important; }

/* Bootstrap drops the .collapsing height transition under prefers-reduced-motion,
   so every collapse ( sud search panels, help rows, the localized accordion and the
   side-menu groups ) snaps open / shut. Keep the gentle height / width ease anyway -
   it is a non-vestibular slide the portal leans on - so panels animate, not pop. */
@media (prefers-reduced-motion: reduce) {
    .collapsing                     { transition: height .35s ease; }
    .collapsing.collapse-horizontal { transition: width  .35s ease; }
}

/* Keyed / localized JSON fields: a flag icon sits inline with the language label,
   keyed rows stack tightly, and the collapse toggle reads as a link. */
.sud-flag                          { width: 1.25rem; height: auto; vertical-align: -2px; margin-right: .35rem; }
.sud-json-fields .input-group-text { min-width: 4rem; justify-content: center; }
.sud-collapse-toggle               { cursor: pointer; }
.sud-localized .sud-localized-lang  { width: auto; flex-grow: 0; }
.sud-localized .sud-localized-input { border-top-right-radius: var(--bs-border-radius) !important; border-bottom-right-radius: var(--bs-border-radius) !important; }

/* Validation: error text under the label + a red outline on the field's row. */
.sud-err-msg                       { color: var(--bs-danger); font-size: .8rem; margin-top: .15rem; }
tr.sud-row-error > td              { border-top: 1px solid var(--bs-danger); border-bottom: 1px solid var(--bs-danger); }
tr.sud-row-error > td:first-child  { border-left: 1px solid var(--bs-danger); }
tr.sud-row-error > td:last-child   { border-right: 1px solid var(--bs-danger); }

/* select2 ( 4.0.13, vendored ) skinned to the Bootstrap 5.3 theme. The stock theme
   is light-only, so without this the control + dropdown are near-invisible in dark
   mode ( same reason the jconfirm block above follows the bs vars ). The single
   control is sized like .form-select-sm; the dropdown mounts inside the modal via
   dropdownParent, so it rides above the dialog body. */
.select2-container                                                          { width: 100% !important; }
.select2-container--default .select2-selection--single                      { height: calc(1.5em + .5rem + 2px); background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); border-radius: var(--bs-border-radius-sm); }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: calc(1.5em + .5rem); padding-left: .5rem; color: var(--bs-body-color); }
.select2-container--default .select2-selection--single .select2-selection__arrow    { height: calc(1.5em + .5rem); }
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--open  .select2-selection--single    { border-color: var(--bs-primary); }
/* Multi-select control ( the Generate piece / layer picker ): the stock 4.0.13 theme leaves the
   box + chips white, so it is near-invisible in dark mode. Mirror the single control's bs-var skin
   so both themes track - box + chips + inline search all follow the Bootstrap variables. */
.select2-container--default .select2-selection--multiple                    { min-height: calc(1.5em + .5rem + 2px); background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); border-radius: var(--bs-border-radius-sm); }
.select2-container--default.select2-container--focus .select2-selection--multiple  { border-color: var(--bs-primary); }
.select2-container--default .select2-selection--multiple .select2-selection__choice { background: var(--bs-secondary-bg); border: 1px solid var(--bs-border-color); color: var(--bs-body-color); border-radius: var(--bs-border-radius-sm); }
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove { color: var(--bs-secondary-color); }
.select2-container--default .select2-selection--multiple .select2-search__field     { color: var(--bs-body-color); }
.select2-dropdown                                                           { background: var(--bs-body-bg); border-color: var(--bs-border-color); color: var(--bs-body-color); }
.select2-container--default .select2-search--dropdown .select2-search__field { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); color: var(--bs-body-color); }
.select2-container--default .select2-results__option                        { color: var(--bs-body-color); }
.select2-container--default .select2-results__option[aria-selected=true]    { background: var(--bs-secondary-bg); }
.select2-container--default .select2-results__option--highlighted[aria-selected] { background: var(--bs-primary); color: #fff; }
/* The dropdown is parented into the stacked modal ( z-index 1056+ ); keep it on top. */
.select2-container--open                                                    { z-index: 1061; }

/* select2 as a flexible member of a Bootstrap input-group ( the sud asset / icon pickers
   put the select2 alongside the index / preview / Preview controls in one row ). Its base
   rule is width:100% !important, which would break the row, so flex it instead and round
   only its leading ( left ) corners since a control always follows it. */
.input-group > .select2-container                                           { flex: 1 1 auto; width: 1% !important; }
.input-group > .select2-container .select2-selection--single                { height: 100%; display: flex; align-items: center; border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group > .select2-container .select2-selection--single .select2-selection__rendered { line-height: normal; }
.input-group > .select2-container .select2-selection--single .select2-selection__arrow     { height: 100%; }

/* IMAGE_INDEX cropped preview: a bordered, rounded chip at the end of the picker row.
   inline-block so the width / height sud.js paints on it apply ( a bare inline span
   ignores them ); the min size keeps a tidy placeholder before a cell is picked. */
.sud-ii-prevcell                                                            { padding: 2px; }
.sud-ii-preview                                                             { display: inline-block; min-width: 32px; min-height: 32px; border: 1px solid var(--bs-border-color); border-radius: 5px; }

/* Read-only form fields: tint the control and show a blocked cursor so a non-editable
   field reads as such at a glance. Read-only widgets render either with the native
   readonly attribute ( text / number / mask inputs ) or disabled ( selects, the BOOL
   checkbox, and the icon / asset / multiselect pickers ), so cover both. opacity:1
   keeps the tint legible ( bs dims disabled controls ). */
#sud-form .form-control[readonly],
#sud-form .form-control:disabled,
#sud-form .form-select:disabled,
#sud-form .form-check-input:disabled,
#sud-form input[readonly],
#sud-form input[disabled],
#sud-form select[disabled]                                                  { background-color: var(--bs-secondary-bg); cursor: not-allowed; opacity: 1; }
/* A disabled checkbox keeps pointer-events off in bs; re-enable so the cursor shows. */
#sud-form .form-check-input:disabled                                        { pointer-events: auto; }

/* fastselect ( dujardin, bundled in core ) skinned to the Bootstrap 5.3 theme + sized to the
   form controls. The stock theme is light-only AND scales every part in COMPOUNDING em
   ( .fstElement 1.1em; result items / query / titles 1.4em; chips 1.2em ) over a 20em-wide
   control, so against the modal it renders an oversized white box with huge options + dark
   ( invisible ) text. These rules theme it with bs vars ( both modes ) and reset the sizes at
   the base's OWN selector specificity ( a bare .fstResultItem can't beat .fstMultipleMode
   .fstControls ), bringing it to a standard control. Used by MULTISELECT ( Permissions > Modes ). */
.fstElement                              { display: block; width: 100%; margin: 0; font-size: 1rem; color: var(--bs-body-color); background-color: var(--bs-body-bg); border-color: var(--bs-border-color); border-radius: var(--bs-border-radius); }
.fstElement:focus-within                 { border-color: var(--bs-primary); }
.fstMultipleMode .fstControls            { width: auto; min-height: calc(1.5em + .75rem + 2px); padding: .25rem .4rem 0 .4rem; }
.fstMultipleMode .fstQueryInput          { font-size: 1rem; color: var(--bs-body-color); padding: .2rem 0; }
.fstMultipleMode .fstFakeInput           { font-size: 1rem; }   /* hidden width-measurer; keep it in step with the input */
.fstQueryInput::placeholder              { color: var(--bs-secondary-color); }
/* Selected chips ( multiple mode ) as compact bs-primary pills. */
.fstChoiceItem                           { font-size: .8125rem; color: #fff; background-color: var(--bs-primary); border-color: var(--bs-primary); border-radius: var(--bs-border-radius-sm); }
.fstChoiceRemove                         { color: #fff; opacity: .8; }
.fstChoiceRemove:hover                   { color: #fff; opacity: 1; }
/* Dropdown: theme it, cap the height ( base is 30em ), keep it above the form rows. */
.fstResults                              { color: var(--bs-body-color); background-color: var(--bs-body-bg); border-color: var(--bs-border-color); max-height: 14rem; box-shadow: var(--bs-box-shadow); z-index: 1061; }
.fstResultItem                           { font-size: 1rem; padding: .375rem .75rem; color: var(--bs-body-color); border-top: 0; }
.fstResultItem.fstFocused                { color: #fff; background-color: var(--bs-primary); border-color: var(--bs-primary); }
.fstResultItem.fstSelected               { color: var(--bs-body-color); background-color: var(--bs-secondary-bg); border-color: var(--bs-border-color); }
.fstResultItem.fstSelected.fstFocused    { color: #fff; background-color: var(--bs-primary); }
.fstGroupTitle,
.fstNoResults                            { font-size: 1rem; color: var(--bs-secondary-color); padding: .375rem .75rem; }

/* JSONEditor ( josdejong ) — follow the active Bootstrap theme. The stock theme is
   light-only ( base text #1a1a1a on #fff ), so in dark mode it renders dark text on a
   white box inside the dark portal. bs vars auto-switch, so this themes the editor
   area in BOTH light and dark with one block. The navy menu bar ( #00205b, white
   sprite icons ) is left as its own accent in both modes. Code mode uses Ace, which
   keeps its own theme ( not CSS-skinnable here ). */
.jsoneditor                                   { background-color: var(--bs-body-bg); color: var(--bs-body-color); border-color: var(--bs-border-color); }
.jsoneditor-outer,
div.jsoneditor-tree,
.jsoneditor-text,
.jsoneditor-frame                             { background-color: var(--bs-body-bg); }
/* Match jsoneditor's OWN selectors ( it colors content with div.jsoneditor-field /
   div.jsoneditor td / div.jsoneditor-value at #1a1a1a - specificity 0,1,1, which
   out-specifies a bare .class ). Same selectors here + sud.css loading after = these
   win. Type-colored values ( string / number / etc ) keep their own higher-specificity
   colors, so only the field / base text flips to the theme color. */
div.jsoneditor td,
div.jsoneditor th,
div.jsoneditor textarea,
div.jsoneditor-field,
div.jsoneditor-value,
pre.jsoneditor-preview,
.jsoneditor-search input,
.jsoneditor-value.jsoneditor-color-value,
.jsoneditor-value.jsoneditor-invalid          { color: var(--bs-body-color); }
/* The {N} / [N] / (empty ...) node size count is a div.jsoneditor-readonly { color: grey }
   ( jsoneditor builds it with that class ) - too dim on dark. A descendant selector ( not
   td, which never matched the div ) beats jsoneditor's bare .jsoneditor-readonly. Keys are
   .jsoneditor-field, handled by the rule above. */
.jsoneditor .jsoneditor-readonly              { color: var(--bs-body-color); }
.jsoneditor-navigation-bar                    { background-color: var(--bs-tertiary-bg); border-bottom-color: var(--bs-border-color); color: var(--bs-secondary-color); }
/* Value-type accents too low-contrast on a dark background ( number/boolean stay
   bright enough ); retoned only in dark, light keeps the defaults. */
[data-bs-theme="dark"] .jsoneditor-value.jsoneditor-string,
[data-bs-theme="dark"] .jsoneditor-value.jsoneditor-url    { color: #5fbf6a; }
[data-bs-theme="dark"] .jsoneditor-value.jsoneditor-null   { color: #5b9bff; }
[data-bs-theme="dark"] .jsoneditor-selected                { background-color: var(--bs-secondary-bg); }

/* JSONEditor context menu ( the Append / change-type popup ) — its own overlay with a
   white bg + dark text + light hover. bs vars theme it for both modes; the type-list
   lives in a submenu ( li ul li button ), so its hover is covered too. */
.jsoneditor-contextmenu .jsoneditor-menu                              { background: var(--bs-body-bg); border-color: var(--bs-border-color); }
.jsoneditor-contextmenu .jsoneditor-menu button                       { color: var(--bs-body-color); }
.jsoneditor-contextmenu .jsoneditor-menu button.jsoneditor-expand     { border-left-color: var(--bs-border-color); }
.jsoneditor-contextmenu .jsoneditor-separator                         { border-top-color: var(--bs-border-color); }
.jsoneditor-contextmenu .jsoneditor-menu button:focus,
.jsoneditor-contextmenu .jsoneditor-menu button:hover,
.jsoneditor-contextmenu .jsoneditor-menu li ul li button:focus,
.jsoneditor-contextmenu .jsoneditor-menu li ul li button:hover        { color: var(--bs-body-color); background-color: var(--bs-secondary-bg); }
/* The current-type highlight is jsoneditor's hardcoded red ( #ee422e ); retheme to a READABLE
   themed highlight ( solid primary + white text was only ~3.7:1, below AA - hard to read ).
   Emphasis text on the secondary surface + bold reads in both modes and still marks selection. */
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected,
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:focus,
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:hover { color: var(--bs-emphasis-color); background-color: var(--bs-secondary-bg); font-weight: 600; }
/* the popup's sprite glyphs are dark ( #4c4c4c ); invert in dark so the glyphs read
   light while their opaque backing inverts to near-black and blends into the popup
   ( plain invert, NOT brightness(0)+invert which would flatten each cell to a solid
   white block ). Light mode keeps the dark glyphs, which read on the light popup. */
[data-bs-theme="dark"] .jsoneditor-contextmenu .jsoneditor-icon,
[data-bs-theme="dark"] .jsoneditor-contextmenu .jsoneditor-menu button .jsoneditor-expand { filter: invert(1); }

/* JSONEditor's toolbar + search icons use the sprite's WHITE glyphs, built for jsoneditor's
   fixed navy menu bar ( #00205b ). Against the modal that bar does not read as a dark accent
   in light mode, so the white glyphs vanish on the light surface. Theme the toolbar bar to
   the active surface and flip its ( and the search widget's ) sprite glyphs to MATCH the
   theme: dark glyphs on the light bar, white glyphs on the dark bar - so every toolbar / mode
   / search button reads in BOTH modes. The tree node-toggle glyphs are the sprite's dark
   #4c4c4c set and read on the light body already, so they are left untouched. */
.jsoneditor-menu                                   { background-color: var(--bs-tertiary-bg); border-bottom-color: var(--bs-border-color); }
.jsoneditor-menu > button,
.jsoneditor-menu > .jsoneditor-modes > button,
.jsoneditor-search button                          { filter: invert(1); }
[data-bs-theme="dark"] .jsoneditor-menu > button,
[data-bs-theme="dark"] .jsoneditor-menu > .jsoneditor-modes > button,
[data-bs-theme="dark"] .jsoneditor-search button   { filter: none; }

/* JSONEditor code mode ( Ace, theme "ace-jsoneditor" ). Ace injects its light theme at
   runtime, so these dark overrides are scoped under [data-bs-theme="dark"] ( the
   ancestor out-specifies Ace's runtime rules ); light mode keeps Ace's own theme. */
[data-bs-theme="dark"] .ace-jsoneditor.ace_editor,
[data-bs-theme="dark"] .ace-jsoneditor .ace_scroller                  { background-color: var(--bs-body-bg); color: var(--bs-body-color); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_gutter                    { background-color: var(--bs-tertiary-bg); color: var(--bs-secondary-color); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_gutter-active-line        { background-color: var(--bs-secondary-bg); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_cursor                    { color: var(--bs-body-color); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_marker-layer .ace_selection   { background: rgba(255,255,255,.16); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_marker-layer .ace_active-line { background: rgba(255,255,255,.06); }
[data-bs-theme="dark"] .ace-jsoneditor .ace_indent-guide              { opacity: .25; }
[data-bs-theme="dark"] .ace-jsoneditor .ace_variable                  { color: var(--bs-body-color); }   /* JSON keys */
[data-bs-theme="dark"] .ace-jsoneditor .ace_string                    { color: #5fbf6a; }
[data-bs-theme="dark"] .ace-jsoneditor .ace_constant.ace_numeric      { color: #d19a66; }
[data-bs-theme="dark"] .ace-jsoneditor .ace_constant.ace_language     { color: #ff8c00; }   /* true / false / null */
[data-bs-theme="dark"] .ace-jsoneditor .ace_invalid                   { color: #fff; background-color: var(--bs-danger); }

/* ---- Full JSONEditor theming: the remaining hardcoded light-theme colors ( "Everything" ).
   Chrome bars -> the tertiary surface; frames / text / autocomplete -> the body surface; inline
   node chrome + the Transform wizard modal -> themed text / accents. Error-yellow and the dark
   popover tooltip read in both modes already and are left as-is; value-type accents are themed
   above. All use bs vars present in the bundle ( the *-bg-subtle / *-text-emphasis vars are not ). */
.jsoneditor-statusbar,
.jsoneditor-treepath.show-all,
.jsoneditor-treepath .jsoneditor-treepath-show-all-btn  { color: var(--bs-secondary-color); background-color: var(--bs-tertiary-bg); border-color: var(--bs-border-color); }
.jsoneditor-menu a,
.jsoneditor-results                                     { color: var(--bs-secondary-color); }
.jsoneditor-text                                        { color: var(--bs-body-color); }
.jsoneditor .autocomplete.dropdown                      { color: var(--bs-body-color); background-color: var(--bs-body-bg); border-color: var(--bs-border-color); }
.jsoneditor .autocomplete.dropdown .item                { color: var(--bs-body-color); }
.jsoneditor .autocomplete.dropdown .item.hover          { background-color: var(--bs-secondary-bg); }
.jsoneditor .autocomplete.hint                          { color: var(--bs-secondary-color); }
.jsoneditor-tree div.jsoneditor-show-more,
.jsoneditor-tree div.jsoneditor-date,
.jsoneditor .jsoneditor-additional-errors               { color: var(--bs-secondary-color); background-color: var(--bs-secondary-bg); }
.jsoneditor-tree div.jsoneditor-show-more a:hover,
.jsoneditor-value.jsoneditor-url:hover                  { color: var(--bs-primary); }
.jsoneditor-tree button.jsoneditor-button:focus         { background-color: var(--bs-secondary-bg); outline-color: var(--bs-border-color); }
.jsoneditor-empty,
.jsoneditor-value.jsoneditor-empty::after               { border-color: var(--bs-border-color); color: var(--bs-secondary-color); }
/* Transform / sort wizard ( pico-modal ): body surface, primary header + accents, danger error,
   themed inputs. Advanced - rarely opened from config JSON, so themed but not visually smoked. */
.jsoneditor-modal                                       { color: var(--bs-body-color); background-color: var(--bs-body-bg); }
.jsoneditor-modal .pico-modal-header                    { background: var(--bs-primary); color: #fff; }
.jsoneditor-modal a,
.jsoneditor-modal .jsoneditor-jmespath-label            { color: var(--bs-primary); }
.jsoneditor-modal .jsoneditor-transform-preview         { color: var(--bs-body-color); background: var(--bs-secondary-bg); }
.jsoneditor-modal .jsoneditor-transform-preview.jsoneditor-error { color: var(--bs-danger); }
.jsoneditor-modal table th                              { color: var(--bs-body-color); }
.jsoneditor-modal textarea                              { color: var(--bs-body-color); background: var(--bs-body-bg); border-color: var(--bs-border-color); }
.jsoneditor-modal .selectr-selected .selectr-tag,
.jsoneditor-modal .jsoneditor-button-group.jsoneditor-button-group-value-desc input.jsoneditor-button-desc { background: var(--bs-primary); border-color: var(--bs-primary); color: #fff; }
/* selectr "Field" dropdown + the modal's text inputs are hardcoded white ( #fff ) - white
   islands inside the dark modal box. Theme to the body surface ( light keeps the same values,
   dark goes dark ). The blue header / Asc-Desc toggle accents are left as-is. */
.jsoneditor-modal input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]),
.jsoneditor-modal .selectr-selected,
.jsoneditor-modal .selectr-options-container,
.jsoneditor-modal .selectr-input,
.jsoneditor-modal .selectr-notice                       { color: var(--bs-body-color); background-color: var(--bs-body-bg); border-color: var(--bs-border-color); }
.jsoneditor-modal .selectr-placeholder                  { color: var(--bs-secondary-color); }
.jsoneditor-modal .selectr-option                       { color: var(--bs-body-color); }
.jsoneditor-modal .selectr-option.active,
.jsoneditor-modal .selectr-option.selected              { color: var(--bs-emphasis-color); background-color: var(--bs-secondary-bg); }

/* ASSETBUNDLE Preview: the embedded WebGL viewer iframe ( /sud/viewer ). Fills the
   modal-xl body at a 16:9-ish height; the viewer page scales its canvas to fit. */
.sud-viewer-host                                                      { width: 100%; }
.sud-viewer-frame                                                     { display: block; width: 100%; height: 72vh; border: 0; background: #000; }

/* In-portal model reference ( /sud/docref ): one model-library doc page rendered into a modal
   body, carrying the library's own doc-site look. The lead facts read as a two-column definition
   grid with the state facts as pills, each section heading sits over a hairline rule, a wide
   settings table scrolls inside its own wrapper, and the Examples block is a responsive grid
   whose media all streams same-origin, each cell a fixed square so the grid does not reflow as
   the lazily-started clips arrive. Every colour is a Bootstrap variable, so the modal follows
   the portal's light / dark switch. */
.sud-docref-back                                                      { position: sticky; top: 0; z-index: 2; background-color: var(--bs-body-bg); }
.sud-docref-body                                                      { line-height: 1.6; }
.sud-docref-body > :first-child                                       { margin-top: 0; }
.sud-docref-body h4,
.sud-docref-body h5,
.sud-docref-body h6                                                   { margin-top: 1.75rem; margin-bottom: .75rem; }
.sud-docref-body h5                                                   { padding-bottom: .35rem; border-bottom: 1px solid var(--bs-border-color); }
.sud-docref-body p,
.sud-docref-body ul                                                   { max-width: 90ch; margin-bottom: .75rem; }
.sud-docref-body ul                                                   { padding-left: 1.25rem; }
.sud-docref-body code                                                 { color: var(--bs-code-color); background-color: var(--bs-secondary-bg); border-radius: .25rem; padding: .1rem .3rem; overflow-wrap: anywhere; }
.sud-docref-body a code                                               { color: inherit; background-color: transparent; padding: 0; }
.sud-docref-body .table-responsive                                    { margin-bottom: 1rem; }
.sud-docref-code                                                      { padding: .5rem .75rem; border-radius: .25rem; background: var(--bs-secondary-bg); overflow-x: auto; }
.sud-docref-code code                                                 { color: var(--bs-body-color); background-color: transparent; padding: 0; }
.sud-docref-facts                                                     { display: grid; grid-template-columns: auto 1fr; gap: .3rem 1.25rem; align-items: baseline; margin-bottom: 1.25rem; padding-bottom: 1rem; border-bottom: 1px solid var(--bs-border-color); }
.sud-docref-facts dt                                                  { color: var(--bs-secondary-color); font-weight: 600; white-space: nowrap; }
.sud-docref-facts dd                                                  { margin: 0; overflow-wrap: anywhere; }
.sud-docref-chips                                                     { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .75rem; }
.sud-docref-chip                                                      { padding: .25rem .5rem; border: 1px solid var(--bs-border-color); }
.sud-docref-table                                                     { width: auto; max-width: 100%; margin-bottom: 0; }
.sud-docref-gallery                                                   { display: grid; gap: .5rem; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); margin-bottom: 1rem; }
.sud-docref-cell                                                      { aspect-ratio: 1 / 1; overflow: hidden; border: 1px solid var(--bs-border-color); border-radius: .375rem; background: var(--bs-secondary-bg); }
.sud-docref-cell:hover                                                { border-color: var(--bs-link-color); }
.sud-docref-cell img,
.sud-docref-cell video                                                { width: 100%; height: 100%; object-fit: cover; display: block; }

/*
    Portal side menu - the sole navigation surface on logged-in pages, injected
    into the chrome by siteTemplate as {var:SIDE_MENU}. Expanded shows icon +
    label; the desktop collapsed rail shows icons only; below lg it becomes an
    off-canvas drawer over a backdrop. Themed via Bootstrap 5.3 CSS variables so
    it tracks the light / dark color mode automatically.
*/

#layout-body { align-items: stretch; }

/* Let the content column flex-shrink ( e.g. wide tables scroll ) instead of
   forcing the sidebar to overflow. */
#main-content { min-width: 0; }

/* Desktop app-shell: pin the chrome to the viewport so the side menu and the
   content column each scroll on their own ( scrolling the long menu no longer
   drags the whole page ). The header / footer stay put; layout-body fills the
   space between them and hands its height to the two scroll columns. Mobile
   keeps the document-scroll + off-canvas drawer behavior below. */
@media (min-width: 992px) {

    html, body { height: 100%; }

    #main-body {
        display: flex;
        flex-direction: column;
        height: 100vh;
        height: 100dvh;
    }

    #layout-body { flex: 1 1 auto; min-height: 0; overflow: hidden; }

    #main-content { overflow-y: auto; }

}

.sud-sidebar {
    flex: 0 0 240px;
    width: 240px;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--bs-border-color);
    background: var(--bs-body-bg);
    overflow-y: auto;
    transition: flex-basis .15s ease, width .15s ease, transform .15s ease;
}

.sud-sidebar-head {
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.sud-handle { font-weight: 600; }

.sud-group { padding: .35rem 0; }
.sud-group + .sud-group { border-top: 1px solid var(--bs-border-color); }

.sud-group-title {
    padding: .35rem 1rem .15rem;
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bs-secondary-color);
}

.sud-nav-link {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .5rem 1rem;
    color: var(--bs-body-color);
    text-decoration: none;
    white-space: nowrap;
    border-left: 3px solid transparent;
}

.sud-nav-link:hover { background: var(--bs-tertiary-bg); }

.sud-nav-link.active {
    background: var(--bs-tertiary-bg);
    border-left-color: var(--bs-primary);
    font-weight: 600;
}

.sud-nav-link > i { width: 1.25rem; flex: 0 0 auto; text-align: center; }

.sud-nav-link.disabled {
    color: var(--bs-secondary-color);
    opacity: .55;
    cursor: default;
}

/* Expandable parent group: the parent nav-link and its chevron toggle sit on one
   row ( the link flexes to fill, the caret pins to the right ). The caret rotates
   180deg when its toggle is expanded ( a short transition so it eases, not pops ).
   Child nav-links carry a slight left indent so the nesting reads at a glance. */
.sud-nav-parent { display: flex; align-items: stretch; }
.sud-nav-parent > .sud-nav-link { flex: 1 1 auto; min-width: 0; }

.sud-nav-caret {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--bs-secondary-color);
    cursor: pointer;
}

.sud-nav-caret:hover { background: var(--bs-tertiary-bg); }

.sud-nav-caret > i { transition: transform .15s ease; }

.sud-nav-caret[aria-expanded="true"] > i { transform: rotate(180deg); }

.sud-nav-child .sud-nav-link { padding-left: 2.4rem; }

.sud-nav-footer { margin-top: auto; border-top: 1px solid var(--bs-border-color); }

/* Desktop ( lg+ ): the collapse toggle shrinks the menu to an icon rail. */
@media (min-width: 992px) {

    .sud-sidebar.sud-collapsed { flex-basis: 56px; width: 56px; }

    .sud-sidebar.sud-collapsed .sud-nav-label,
    .sud-sidebar.sud-collapsed .sud-group-title,
    .sud-sidebar.sud-collapsed .sud-nav-caret,
    .sud-sidebar.sud-collapsed .sud-sidebar-head { display: none; }

    .sud-sidebar.sud-collapsed .sud-nav-link {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
        border-left-width: 0;
    }

    /* In the icon rail children show as plain icon rows ( no indent, no nesting ),
       and the collapse stays open so every section icon stays reachable. */
    .sud-sidebar.sud-collapsed .sud-nav-child .sud-nav-link { padding-left: 0; }
    .sud-sidebar.sud-collapsed .sud-nav-group-body { display: block !important; }

}

/* Below lg: off-canvas drawer. Hidden by default, slid in by the navbar toggle
   ( .sud-open ) over a click-to-dismiss backdrop. Desktop collapse does not apply. */
@media (max-width: 991.98px) {

    .sud-sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 1045;
        transform: translateX(-100%);
    }

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

    .sud-backdrop {
        position: fixed;
        inset: 0;
        z-index: 1044;
        background: rgba(0, 0, 0, .5);
    }

}

/* fengyuanchen datepicker ( bundled in core, opened on the DATETIME .sud-dt-date inputs )
   ships a light-only theme: a #fff panel with dark cells and a pale-blue ( #e5f2ff ) hover.
   In the portal's dark theme the panel stayed white while the inherited font went light, so
   the cells - and especially the hover - were unreadable. Theme the panel + cells with bs
   vars so it follows BOTH modes ( dark panel + light text in dark, the stock look in light );
   hover / today use the secondary surface with body text, and the selected day keeps a
   primary accent. */
.datepicker-container                            { background-color: var(--bs-body-bg); color: var(--bs-body-color); }
.datepicker-dropdown                             { border-color: var(--bs-border-color); box-shadow: 0 3px 6px rgba(0,0,0,.35); }
.datepicker-container::after                      { border-top-color: var(--bs-body-bg); border-bottom-color: var(--bs-body-bg); }
/* Core gives EVERY cell its own #fff background, so darkening only the container left a
   white grid under the light text. Clear each cell to the panel surface, then theme the
   states: hover / today on the secondary surface ( a subtle lighter highlight in dark ),
   the selected day on a primary accent, muted / week-headers / disabled dimmed. */
.datepicker-panel > ul > li,
.datepicker-panel > ul > li.muted,
.datepicker-panel > ul > li.disabled,
.datepicker-panel > ul > li.disabled:hover,
.datepicker-panel > ul[data-view="week"] > li,
.datepicker-panel > ul[data-view="week"] > li:hover { background-color: transparent; }
.datepicker-panel > ul > li                       { color: var(--bs-body-color); }
.datepicker-panel > ul > li.muted,
.datepicker-panel > ul > li.disabled,
.datepicker-panel > ul > li.disabled:hover,
.datepicker-panel > ul[data-view="week"] > li     { color: var(--bs-secondary-color); }
.datepicker-panel > ul > li:hover,
.datepicker-panel > ul > li.highlighted,
.datepicker-panel > ul > li.highlighted:hover     { background-color: var(--bs-secondary-bg); color: var(--bs-body-color); }
.datepicker-panel > ul > li.picked,
.datepicker-panel > ul > li.picked:hover          { background-color: var(--bs-primary); color: #fff; }

/* DATETIME widget ( date + h + m in one input-group ): BS makes every input-group
   form-select flex-grow + width:1%, so the 2-digit hour / minute selects stretched huge.
   Shrink them to their content so the date input takes the slack and the group sizes to
   its column ( like a normal field ). The ancestor + element selector out-specifies BS. */
.input-group > select.sud-dt-time                 { flex: 0 0 auto; width: auto; }

/* Process-queue View modal: the read-only error box. The stock .bg-light forced a light
   surface that the dark theme's light body text became invisible on, so the message went
   unreadable in dark mode. Follow the theme ( tertiary surface + body text ) and wrap long
   errors. */
.sud-pq-error                                    { white-space: pre-wrap; background-color: var(--bs-tertiary-bg); color: var(--bs-body-color); }

/* A render's prompt pair in the queue's View modal: the same readable block the error uses,
   capped so a long prompt scrolls inside its own box instead of pushing the modal down. */
.sud-pq-prompt                                   { white-space: pre-wrap; background-color: var(--bs-tertiary-bg); color: var(--bs-body-color); max-height: 9rem; overflow-y: auto; }

/* Progress-bar percentage label: centered over the WHOLE track rather than riding inside
   the coloured fill, so a low percent still shows its number in the middle of the bar. The
   fill carries no text; this overlay sits above both fill and track. The body-colour text
   with a body-background halo stays readable over the fill AND the empty track, in either
   theme, and pointer-events:none lets the bar's own hover tooltip through. */
.progress                                        { position: relative; }
.sud-progress-num                                { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
                                                   font-size: .75rem; line-height: 1; font-weight: 600; pointer-events: none;
                                                   color: var(--bs-body-color); text-shadow: 0 0 2px var(--bs-body-bg), 0 0 2px var(--bs-body-bg); }

/* Core-Asset upload cropper, shared by the DEVELOPER /admin/authoring screen and the
   DESIGNER /design Icons screen ( the AMMSApp.assetForm form ). Dark-mode checkerboard so
   the preview reads in the dark theme AND shows PNG transparency ( the alpha the chrome /
   icons rely on ). */
.asset-cropper-wrap {
	background-color: #2a2e33;
	background-image:
		linear-gradient( 45deg, #3a3f44 25%, transparent 25% ),
		linear-gradient( -45deg, #3a3f44 25%, transparent 25% ),
		linear-gradient( 45deg, transparent 75%, #3a3f44 75% ),
		linear-gradient( -45deg, transparent 75%, #3a3f44 75% );
	background-size: 20px 20px;
	background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}
/* The preview is shown at true pixel size ( zoom-controlled ); the wrap scrolls in both
   axes and pans on drag. */
.asset-cropper-wrap                              { min-height: 16rem; max-height: 420px; overflow: auto; cursor: grab; }
.asset-cropper-wrap.grabbing                     { cursor: grabbing; }
.asset-cropper                                   { image-rendering: pixelated; }
.asset-help-toggle                               { cursor: pointer; }
/* Tooltip-carrying text ( a SystemParam name in help text, a coverage table header ):
   dotted underline + help cursor flag that hover reveals more. */
.sysparam-ref, .tip-ref                          { text-decoration: underline dotted; text-underline-offset: 2px; cursor: help; }
.sysparam-set                                    { text-decoration-color: var(--bs-success); }
.sysparam-unset                                  { text-decoration-color: var(--bs-secondary-color); }
.sysparam-state                                  { display: inline-block; margin-left: .25rem; padding: .05rem .35rem; border-radius: .375rem; font-size: .7rem; font-weight: 600; line-height: 1.4; text-transform: uppercase; letter-spacing: .02em; vertical-align: baseline; }
.sysparam-state-set                              { color: var(--bs-success-text-emphasis); background-color: var(--bs-success-bg-subtle); }
.sysparam-state-unset                            { color: var(--bs-secondary-color); background-color: var(--bs-secondary-bg); }
.tooltip.sysparam-tip .tooltip-inner             { max-width: 32rem; text-align: left; }

/* IMAGE_CROP form field ( Field::IMAGE_CROP -> the b2uCrop stage + the harvested-crop
   thumbnail ). The stage reserves its boundary height so the form does not jump as the
   cropper mounts; the thumb is the pending cropped image shown beside the Crop button. */
.sud-ic-stage                                    { min-height: 320px; }

/* ASSETBUNDLE art-tile authoring control ( Shop item tile / offer image ): a centered
   checkered preview box ( showing PNG transparency + the dark theme ) of the entity's
   current authored image, with the Edit / Preview buttons centered below. The frame keeps
   the image at true aspect within a bounded box; the empty state shows a muted icon. */
.sud-art-tile                                    { text-align: center; }
.sud-art-frame {
	display: inline-flex; align-items: center; justify-content: center;
	max-width: 100%; min-height: 8rem; padding: .5rem; border-radius: .375rem;
	border: 1px solid var(--bs-border-color);
	background-color: #2a2e33;
	background-image:
		linear-gradient( 45deg, #3a3f44 25%, transparent 25% ),
		linear-gradient( -45deg, #3a3f44 25%, transparent 25% ),
		linear-gradient( 45deg, transparent 75%, #3a3f44 75% ),
		linear-gradient( -45deg, transparent 75%, #3a3f44 75% );
	background-size: 20px 20px;
	background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}
.sud-art-img                                     { max-width: 100%; max-height: 16rem; object-fit: contain; border-radius: .25rem; }
.sud-art-frame.empty                             { min-height: 8rem; width: 12rem; }
.sud-art-empty                                   { font-size: 2rem; opacity: .6; }

/* Slim scrollbars site-wide. The native bars render chunky; slim them to a thin,
   theme-tinted rail that brightens on hover.

   Chromium / WebKit are driven ONLY by the ::-webkit-scrollbar block below: it gives a
   pixel-exact 6px rail with no arrow buttons and a transparent track. We deliberately do
   NOT set scrollbar-width / scrollbar-color at the root, because Chromium 121+ treats those
   standard properties as authoritative and, once present, falls back to the OS-drawn
   scrollbar ( full width + arrow buttons ) and ignores ::-webkit-scrollbar entirely.

   Firefox is the reverse: it ignores ::-webkit-scrollbar and only understands the standard
   properties. So we hand those to Firefox alone, gated on @supports not selector(::-webkit-
   scrollbar) — true only where the webkit pseudo-element is unrecognized ( i.e. Firefox ),
   so Chromium never sees them and its webkit rules stay in force. */
::-webkit-scrollbar                              { width: 6px; height: 6px; }
::-webkit-scrollbar-button                       { display: none; }
::-webkit-scrollbar-track                        { background: transparent; }
::-webkit-scrollbar-thumb                        { background-color: var(--bs-secondary-bg); border-radius: 6px; border: 1px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover                  { background-color: var(--bs-secondary-color); }
::-webkit-scrollbar-corner                       { background: transparent; }
@supports not selector(::-webkit-scrollbar) {
	:root                                        { scrollbar-width: thin; scrollbar-color: var(--bs-secondary-bg) transparent; }
}
.sud-ic-thumb                                    { max-width: 120px; max-height: 120px; border-radius: .25rem; border: 1px solid var(--bs-border-color); }

/*  Character-animation first-frame thumbnails ( Characters icon column + Animations
    "Animation" column ): a small square thumb that opens full-size in Fancybox, with a
    256px hover tooltip. Keep the Fancybox lightbox above the stacked SUD modals.  */
.sud-anim-thumb                                  { width: 2rem; height: 2rem; object-fit: contain; border-radius: .2rem; vertical-align: middle; }
.sud-anim-thumb-link                             { line-height: 0; display: inline-block; }
.sud-anim-thumb-tip                              { max-width: 256px; height: auto; display: block; }
/*  The preview tooltip's bs-5.3 default background is the EMPHASIS color ( white in dark
    mode ), which read as a white slab behind a transparent frame. Surface + border theme
    it for both modes, full opacity so the art reads true, no arrow ( it would float
    detached beside the repositioned image ). */
.tooltip.sud-anim-tip                            { --bs-tooltip-opacity: 1; }
.tooltip.sud-anim-tip .tooltip-inner             { background-color: var(--bs-body-bg); border: 1px solid var(--bs-border-color); padding: .25rem; max-width: none; }
.tooltip.sud-anim-tip .tooltip-arrow             { display: none; }
.fancybox__container                             { z-index: 20000; }

/* The house switch ( b2uswitcher over Switchery ) at two thirds of the library's stock size - the
   library's own small metrics - so it sits on a form line, a card corner or a table cell without
   dominating the label beside it. Switchery places the knob from the rendered widths, so the size
   lives here alone. */
.switchery.switchery-default         { height: 20px; width: 33px; border-radius: 20px; }
.switchery.switchery-default > small { height: 20px; width: 20px; }

/* The house switch's OFF state takes the theme's own control colours - the fill of the chips and
   read-only fields above, under the controls' border - in place of the white track, #dfdfdf border
   and #dfdfdf empty ring Switchery writes inline on the span it puts right after the checkbox, so
   an OFF switch reads as one on both themes and follows a theme change at once, and the green ring
   of a switch turned ON grows out of the track's own colour; !important is what outranks the
   inline colours. Switched ON, the plugin ticks the checkbox and reads the rendered width before
   it paints the green, and that read alone would drop the fill to the inline white: a ticked
   switch therefore carries the plugin's own ON transition ( 0.1s, the fill 0.3s ) from that read
   on, so the fill fades from the colour on screen. The knob and the ON colours stay the library's
   own. */
input:not(:checked) + .switchery     { background-color: var(--bs-secondary-bg) !important; border-color: var(--bs-border-color) !important; box-shadow: inset 0 0 0 0 var(--bs-secondary-bg) !important; }
input:checked + .switchery           { transition: border 0.1s, box-shadow 0.1s, background-color 0.3s !important; }

/* The public door ( every shell page ). The age gate covers the whole window above everything -
   header, side menu, dialogs, the cookie bar - on a page that declared it; the page sends no
   content behind it, and the window cannot scroll while it is up. The footer's link rows each
   sit on one line, split by middle dots, and its Cookie Settings button reads as one link. */
.age-gate                                        { position: fixed; inset: 0; z-index: 2000; overflow-y: auto; background-color: var(--bs-body-bg); }
html[data-age-gate] body                         { overflow: hidden; }
#footer-links .list-inline-item + .list-inline-item::before,
#footer-legal .list-inline-item + .list-inline-item::before { content: "\00B7"; margin-right: .5rem; }
#footer-legal .btn-link                          { font-size: inherit; padding: 0; border: 0; vertical-align: baseline; }

/* While the cookie bar is up ( fixed to the window's bottom ), the page keeps room beneath it as
   tall as the bar ( amms.js AMMSConsent measures it into --consent-bar-h and follows it as the bar
   wraps ), so the footer can always be brought above it: below lg the document gains the room
   after the footer; on the desktop shell, whose footer is pinned to the window, the room sits
   inside the shell's fixed height, so the shell shrinks by it. */
html[data-consent-bar] #main-body                { padding-bottom: var(--consent-bar-h, 0px); }

/* The landing page ( "/" for a signed-out visitor ). The hero lays the game's name, pitch and
   buttons over its video ( over the poster while no video is set ), darkened so the text reads in
   either theme; the closing strip repeats the buttons on the same dark ground. */
.landing-hero                                    { position: relative; display: flex; align-items: center; min-height: 34rem; overflow: hidden; background-color: #212529; }
.landing-hero-video                              { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.landing-hero::after                             { content: ""; position: absolute; inset: 0; background: linear-gradient( 90deg, rgba( 0, 0, 0, .78 ), rgba( 0, 0, 0, .3 ) ); }
.landing-hero-body                               { position: relative; z-index: 1; }
.landing-closing                                 { background-color: #212529; }
