* {
    border-radius: 0 !important;
}

.wide {
    @media screen and (min-width: 730px) {
        display: block;
    }

    @media screen and (max-width: 729px) {
        display: none;
    }
}

.slim {
    @media screen and (min-width: 730px) {
        display: none;
    }

    @media screen and (max-width: 729px) {
        display: block;
    }
}

.datepicker {
    font-size: 12px;
}

/* Unify neutral/uncolored borders (inputs, toolbars, panels, multi-select boxes) to the
   same grey panels already use (bootstrap.css: .panel-default { border-color: #949494; }),
   instead of the mix of #ebebeb/#ccc/#bbbbbb/#f5f5f5 that were scattered around. */
.form-control,
.ms-container .ms-list,
.select2-container .select2-choice,
.select2-container .select2-choices,
.select2-drop,
.has-switch,
div.datepicker.dropdown-menu,
.bootstrap-timepicker-widget.dropdown-menu,
table.table-bordered,
table.table-bordered th,
table.table-bordered td,
table.table-bordered thead th,
table.table-bordered thead td,
table.table-bordered tfoot th,
table.table-bordered tfoot td {
    border-color: var(--border-grey) !important;
}

/* DataTables' own bundled CSS sets a specific dark border-bottom on thead cells and
   border-top on tfoot cells (the header/footer divider lines), which beats the generic
   border-color rule above for those two sub-properties specifically. Borders aren't
   collapsing here, so only set this on one side of each divider (not tbody's matching
   edge too), or it doubles up to 2px. */
table.table-bordered thead th,
table.table-bordered thead td {
    border-bottom: 1px solid var(--border-grey) !important;
}

table.table-bordered tfoot th,
table.table-bordered tfoot td {
    border-top: 1px solid var(--border-grey) !important;
}

/* DataTables' auto column-width layout (used by the .table-responsive horizontal scroll wrap -
   see the DataTable() init scripts in render_datatable(), neon_html_select.php) sizes each column
   from its widest cell content. Plain text already resists that fine (.nw's white-space:nowrap
   keeps it from wrapping, giving it a real minimum width to push back with) - but a width:100%
   .form-control has no minimum size of its own, so an editable/input-type table column just keeps
   shrinking the input down to nothing instead of the table recognizing it doesn't fit and
   actually overflowing (which is what triggers .table-responsive's scrollbar). This gives inputs
   something to push back with, so scrolling kicks in at a usable point instead of past it. */
table.dataTable td .form-control,
table.dataTable td select {
    min-width: 100px;
}

/* select2 hides the underlying <select> and draws its own arrow instead, so this only ever reaches
   a batch-mode cell's plain 'input' => 'select' control (render_table(), neon_html_select.php) -
   'drop' cells stay select2-enhanced. Bootstrap's base .form-control padding-right (12px) sits the
   native dropdown arrow closer to the border than the rest of this app's controls read as
   comfortable. */
table.dataTable td select {
    padding-right: 14px;
}

/* DataTables 2's type detection tags a column whose data-order values are all empty/numeric with
   td.dt-type-numeric (text-align: right), which beats our own dt-left (same specificity, later in
   its stylesheet) - so a page where no row has a value yet right-aligned the select2 placeholder
   in 'searchable_select'/'drop' cells. */
table.dataTable td .select2-container {
    text-align: left;
}
/* DataTables' own base CSS puts 'clear: both' directly on table.dataTable - that's what makes it
   drop below the floated .dataTables_length (float:left) / .dataTables_filter (float:right)
   controls above it. Wrapping the table in .table-responsive (render_datatable()'s DataTable()
   init scripts, neon_html_select.php) moves the table one level deeper, so it's no longer the
   actual sibling of those floats - the wrapping div is, and it has no clear of its own, so it
   was rendering in the open space beside them instead of below. Bootstrap's own .table-responsive
   never needs this outside a floated-siblings context like this one, so it's safe as a permanent
   default here rather than something scoped only to DataTables. */
.table-responsive {
    clear: both;
}

/* The outer .panel wrapper carries no border of its own; .panel-heading is fully bordered
   on its own (so a collapsed panel, with its body hidden, still reads as a complete box
   instead of showing both the panel's and the heading's border-bottom stacked together),
   and .panel-body picks up the sides/bottom without a top border, so it fuses seamlessly
   under the heading instead of doubling that line when expanded. */
.panel-default {
    border: none !important;
}

.panel-default>.panel-heading {
    border: 1px solid var(--border-grey) !important;
}

.panel-default>.panel-body {
    border: 1px solid var(--border-grey) !important;
    border-top: none !important;
}

/* The mini add-form's own box (neon_html_select.php's render_select()) - standalone, not a
   .panel/.panel-body, so it doesn't compete with the panel border rules above. */
.mini-box {
    position: relative;
    background-color: #fff !important;
    border: 1px solid var(--border-grey) !important;
    padding: 15px !important;
    margin-bottom: 17px !important;
}

/* Floating label sitting on the box's top border, like a fieldset legend - left-offset to
   line up with the box's own left padding, background matching the box to mask the border
   line underneath it. */
.mini-box-label {
    position: absolute;
    top: -3px;
    left: 15px;
    transform: translateY(-50%);
    margin: 0;
    padding: 0 6px;
    background-color: #fff;
}

/* Universal vertical spacing for stacked form controls/boxes (render_edit_fields() wraps its
   field loop in this, and it's reused anywhere else a sequence of controls/panels needs the same
   treatment - the mini-box above, for one). `gap` puts a real 15px between every adjacent pair of
   direct children regardless of order or type, immune to margin-collapsing - so whatever margin a
   child normally carries on its own (.form-group's margin-bottom, .panel's margin-bottom, etc.)
   is zeroed here to stop it from stacking on top of the gap and doubling the space. */
.control-stack {
    display: flex;
    flex-direction: column;
    gap: 15px;
}

.control-stack>* {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

/* A handful of disabled/readonly field renderers (switch, radio, spinner, access-switch,
   wysiwyg - see render_edit_text() call sites in neon_html_edit.php) nest render_edit_text()'s
   own labeled .form-group.row INSIDE their outer row instead of replacing it, so it ends up a
   grandchild of .control-stack, not a direct child - the rule above doesn't reach it. Catch
   .form-group/.panel at any depth instead, so a disabled field's gap to its neighbor matches
   every other field's, not just its enabled rendering. */
.control-stack .form-group,
.control-stack .panel {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

/* render_button() (neon_html_common.php) sets margin-bottom via an inline style attribute -
   10px normally, 0 for 'cell' buttons - which none of the class-based rules above can reach
   (a class selector, even with !important, never wins against a matching inline style unless
   the inline style itself lacks !important, which is the case here). Left alone, that inline
   10px sits inside the button's own .form-group.row (a floated column doesn't clip its child's
   margin), quietly adding on top of the 15px gap. Reset it here instead. */
.control-stack .btn {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

/* .switch-group (render_filter_radio() and every render_edit_input_radio()-style radio-as-switches
   control, both files) holds one floated .col-* per option, each wrapping a .make-switch that - in
   some call sites - carries its own inline margin-bottom (5px or 15px, inconsistently) meant to
   space wrapped options apart on a narrow screen. Applied to every option including the last, that
   margin is contained inside the group's own box (floats don't collapse it out) and just adds on
   top of .control-stack's gap to whatever comes next. Flex + row-gap replaces it uniformly: a real
   15px between wrapped options, matching every other gap in the app, and - unlike margin - never
   any trailing space after the last one. */
.switch-group {
    display: flex;
    flex-wrap: wrap;
    row-gap: 15px;
}

.switch-group .make-switch {
    margin-bottom: 0 !important;
}

/* 'input' => 'radio' column in a datatable (neon_html_select.php): tight 3px spacing between the
   option switches, centered in the cell, and always kept on one row - the column widens to fit
   instead of the options wrapping (DataTables sizes the column from this unwrapped content). */
.switch-group-cell {
    gap: 3px;
    justify-content: center;
    flex-wrap: nowrap;
}

.switch-group-cell > .make-switch {
    flex-shrink: 0;
}

/* A compact radio (render_edit_input_radio() with 'compact' => true) sizes its option columns
   against the full row next to the label (col-sm-3 + n × col-sm-1), not against the switch-group's
   own leftover width - so the group steps out of the box tree and the .wrap-gap-row row itself
   does the flex wrapping/row-gap. .has-switch's own min-width: 100px (neon-forms.css) would
   otherwise overflow a col-sm-1 column and eat the column padding that makes the gap. */
.wrap-gap-row > .switch-group {
    display: contents;
}

.switch-compact .has-switch {
    min-width: 0;
}

/* Any Bootstrap row whose .col-* children are floated (not flex) and can end up stacked on top of
   each other on a narrow screen (all col-xs-12, so nothing fits side by side) - floated columns
   carry no margin between them by default, so they'd otherwise touch with zero gap once stacked.
   render_buttons() (neon_html_common.php) is the original case: it puts every button of one group
   into a single .form-group.row - when there are more buttons than fit on one line, Bootstrap
   wraps them onto a second line within that same row, same problem as the narrow-screen stack.
   render_qr_field()'s label/input/button row is the other user of this class. Flex + row-gap
   gives a real 15px between wrapped/stacked items either way, and - unlike margin - never adds
   trailing space after the last one, so it can't double up with .control-stack's own gap. */
.button-row,
.wrap-gap-row {
    display: flex;
    flex-wrap: wrap;
    row-gap: 15px;
}

/* Bootstrap gives every heading its own default top margin (h3: 17px, h4/h5/h6: 8.5px - see
   bootstrap.css) that none of the rules above touch, since they only target .form-group/.panel/
   .btn. A heading sitting first inside a row (render_edit_box()'s <h3 class="panel-title">, the
   related-table <h4>, etc.) is contained by that row's own box (floated/padded parents don't let
   a child's margin collapse out), so it just adds silently on top of the 15px gap before it - the
   row's OWN margin is already 0, but its visible content still starts further down than the gap
   alone would suggest. Only margin-top is reset here, never margin-bottom - several of these
   headings already carry a deliberate inline margin-bottom (5px for the page title, 15px for the
   related-table header) that must survive untouched. */
.control-stack h1,
.control-stack h2,
.control-stack h3,
.control-stack h4,
.control-stack h5,
.control-stack h6 {
    margin-top: 0 !important;
}

/* ...except inside a table cell: render_datatable() wraps plain cell text in <h5>, and a cascade
   sub-table on an edit page (render_edit_related_table()) sits inside .control-stack - losing only
   the top margin (bottom stays 8.5px) pushed that text visibly above the cell's middle. Restores
   Bootstrap's own symmetric 8.5px, same as a full select-page table. */
.control-stack td h4,
.control-stack td h5,
.control-stack td h6 {
    margin-top: 8.5px !important;
}

/* Bootstrap 3 top-aligns table cells - with the margins above symmetric again, this centers
   sub-table text against the taller input/select2 cells beside it. Sub-tables only (select pages
   have no .control-stack). */
.control-stack table.dataTable > tbody > tr > td {
    vertical-align: middle;
}

.custom-image-container {
    position: absolute;
    top: 10px;
    bottom: 10px;
    left: 10px;
    right: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.custom-image-upload-area {
    position: relative;
    width: 100%;
    padding-top: 75%;
    border: 1px solid var(--border-grey);
    background-color: var(--background-white);
    cursor: pointer;
    overflow: hidden;
    box-sizing: border-box;
    text-align: center;
    min-height: 220px;

    img {
        max-width: 100%;
        max-height: 100%;
        height: auto;
        width: auto;
        display: none;
    }

    input[type="file"] {
        display: none;
    }
}

.custom-image-right-corner-icon {
    position: absolute !important;
    top: 8px !important;
    right: 8px !important;
    padding: 5px;
    cursor: pointer;
    z-index: 9999;
}

#crop_image {
    /* Jcrop resizes this to boxWidth/boxHeight via inline width/height once it initializes,
       but that happens after the modal is already visible - without a cap here the raw
       full-resolution <img> flashes at natural size for a frame first. */
    max-width: 600px;
    max-height: 450px;
}

.custom-image-left-corner-icon {
    position: absolute !important;
    top: 8px !important;
    left: 8px !important;
    padding: 5px;
    cursor: pointer;
    z-index: 9999;
}

.custom-image-upload-area-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: var(--border-grey);
    display: block;
}

.has-switch>div {
    width: 240% !important;

    &.switch-off {
        left: -140% !important;
    }
}

.time-counter {
    padding-left: 15px;
    height: 30px;
    line-height: 30px;
    font-weight: bold !important;
}

pre {
    white-space: pre-wrap;
    overflow-x: auto;
    max-width: 100%;
    word-break: normal;
    overflow-wrap: normal;
    font-family: helvetica-neue, sans-serif;
    font-size: 12px;
}

.swiper {
    margin-bottom: 0px;
    min-height: 220px;
    background-color: var(--background-white);
    border: 1px solid var(--border-grey);
}

.swiper-button-prev,
.swiper-button-next {
    position: absolute;
    transform: translateY(-50%);
    z-index: 15;
    width: 28px;
    height: 28px;
    background: none;
    border: none;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    font-size: 16px;

    /* Swiper draws the actual chevron via its own ::after (the "swiper-icons" glyph font), not
       this element's own text - a plain color on .swiper-button-prev/-next only tints the glyph,
       it can't stroke it, so the black outline has to be applied to ::after itself. Bright
       secondary-cyan fill + black stroke so the arrow itself reads clearly against any photo,
       rather than a colored box sitting around a plain dark arrow. */
    &::after {
        color: var(--bright-secondary);
        -webkit-text-stroke: 1px #000;
    }

    &:hover::after {
        color: #ffffff;
    }
}

.swiper-button-next {
    right: 10px;
}

.swiper-button-prev {
    left: 10px;
}

#swiper-button-trash {
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 5px;
}

.swiper-slide {
    display: flex;
    justify-content: center;
    /* Centers horizontally */
    align-items: center;
    /* Centers vertically */
    padding: 10px;
    height: 100%;
    /* Ensure the slide takes full height */
    background-color: var(--background-white);
    position: relative;

    img {
        justify-content: center;
        max-width: 100%;
        /* Scale image to fit width */
        max-height: 100%;
        /* Scale image to fit height */
        object-fit: contain;
        /* Keeps the image's aspect ratio */
        display: block;
        /* .swiper-slide's own 10px padding always keeps a gap between the image and the swiper's
           outer border, so this never sits flush against it. */
        border: 1px solid var(--border-grey);
        box-sizing: border-box;
        /* Removes any inline spacing */
    }
}

/* make-switch: data-on/data-off are set to "primary-checked" / "primary-unchecked" (or the
   secondary equivalents), which bootstrap-switch turns into a single "switch-X" class on
   the generated span. The -unchecked variant reuses the plain button look, the -checked
   variant reuses the button's hover/active look, so only the checked state reads as "active". */
.btn-primary,
.tile-primary,
.alert-primary,
.has-switch span.switch-primary-unchecked {
    background-color: var(--bright-primary) !important;
    border: 1px solid var(--primary-border) !important;
    color: var(--primary-dark-text) !important;
}
.btn-primary:hover,
.tile-primary:hover,
.has-switch span.switch-primary-checked {
    background-color: var(--very-dark-primary) !important;
    border: 1px solid var(--primary-border) !important;
    color: var(--primary-bright-text) !important;
}

.btn-secondary,
.tile-secondary,
.alert-secondary,
.has-switch span.switch-secondary-unchecked,
.dt-paging .page-link {
    background-color: var(--bright-secondary) !important;
    border: 1px solid var(--secondary-border) !important;
    color: var(--secondary-dark-text) !important;
}

.dt-paging .page-link:hover {
    background-color: var(--very-dark-secondary) !important;
    border: 1px solid var(--secondary-border) !important;
    color: var(--secondary-bright-text) !important;
}

/* Bootstrap's .page-link (and the navbar links below) draw a rounded native focus ring on
   click/:active, which sticks out against this theme's "everything square, no rounded corners"
   look (see the border-radius reset at the top of this file). Same fix as .form-control's own
   outline: 0 above - just extended to the elements that still showed it. */
.dt-paging .page-link:focus,
.dt-paging .page-link:active {
    outline: 0 !important;
    box-shadow: none !important;
}

header.navbar a:focus,
header.navbar a:active {
    outline: 0 !important;
    box-shadow: none !important;
}

.btn-secondary:hover,
.tile-secondary:hover,
.has-switch span.switch-secondary-checked {
    background-color: var(--very-dark-secondary) !important;
    border: 1px solid var(--secondary-border) !important;
    color: var(--secondary-bright-text) !important;
}

.select2-container.select-primary .select2-choice {
    border-width: 0;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

.select2-container.select-primary-value .select2-choice {
    border-width: 1px !important;
    border-style: solid !important;
    background-color: var(--very-dark-primary) !important;
    color: var(--primary-bright-text) !important;
    border-color: var(--primary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

.select2-drop.select-primary {
    border-width: 1px !important;
    border-style: solid !important;
    border-color: var(--primary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

/* Marks a select2 control as "navigational" - it doesn't write any data itself (the search
   box, filter dropdowns), unlike the secondary/primary button colors above which mark actions.
   Applied via select2's containerCssClass option, since select2 doesn't copy the source
   <select>'s own classes onto the container it generates. */
.select2-container.select-secondary .select2-choice {
    border-width: 0;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--secondary-shadow) !important;
}

/* -value variants: same control, but currently holding a value - not just "you can filter/find
   things here" but "this is actively narrowing what you see right now". Mirrors the
   -unchecked/-checked contrast switches already use above (light face at rest, inverted dark
   face once active) rather than just a brighter glow, so it reads at a glance. */
.select2-container.select-secondary-value .select2-choice {
    border-width: 1px;
    border-style: solid;
    background-color: var(--very-dark-secondary);
    color: var(--secondary-bright-text);
    border-color: var(--secondary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--secondary-shadow) !important;
}



/* select2's open results dropdown is a separate floating element (.select2-drop), not nested
   inside .select2-container - containerCssClass never reaches it, so it was still showing the
   plain grey unify-borders color even when the closed box above it was colored. Applied via
   select2's dropdownCssClass option, matching only the color family (no -value split - the
   open list isn't itself "holding a value" the way the closed box is). */
.select2-drop.select-secondary {
    border-color: var(--secondary-border) !important;
}

/* select2 v3's own dropdown arrow (.select2-arrow b) and clear "x" (.select2-choice abbr) are a
   sprite background-image (select2.png) - color can't touch a background-image, so against the
   dark -value fills above they were nearly invisible (barely-there grey-on-magenta/cyan). Redrawn
   as plain CSS shapes instead (a border-triangle, two crossed bars) with no color of their own, so
   they inherit .select2-choice's own color - already set per family/-value state above - and always
   read at the same brightness as the chosen text next to them. */
.select2-container .select2-choice .select2-arrow b {
    background: none;
    position: relative;
}

.select2-container .select2-choice .select2-arrow b:after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-top: 4px solid currentColor;
    border-right: 4px solid transparent;
    border-left: 4px solid transparent;
}

.select2-dropdown-open .select2-choice .select2-arrow b:after {
    transform: translate(-50%, -50%) rotate(180deg);
}

.select2-container .select2-choice abbr {
    background: none;
}

.select2-container .select2-choice abbr:before,
.select2-container .select2-choice abbr:after {
    content: "";
    position: absolute;
    top: 5px;
    left: 1px;
    width: 10px;
    height: 2px;
    background-color: currentColor;
}

.select2-container .select2-choice abbr:before {
    transform: rotate(45deg);
}

.select2-container .select2-choice abbr:after {
    transform: rotate(-45deg);
}

/* 'multiselect' field/filter control: select2 v3's native multi-select mode embeds its search
   input inline among the tag chips (inside .select2-choices) with no built-in way to relocate it
   into the results dropdown instead - confirmed genuinely unreadable there against both the light
   default and dark "has a value" skins, and there's no clean CSS-only fix since it's baked into
   how the widget positions/paints that input. So 'multiselect' doesn't use select2's multi mode at
   all: it's a plain removable-tag list (.multiselect-tags/.multiselect-tag below) paired with an
   ordinary SINGLE-value select2 "add one more" picker underneath - the exact same click-box/
   dropdown-with-search-at-top experience every other select2 field in the app already has, reused
   as-is (see render_edit_input_multiselect() / render_filter_multiselect()). */
.multiselect-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-height: 20px;
    padding: 6px;
    margin-bottom: 6px;
    border-radius: 3px;
}

/* Only ever rendered/shown once at least one tag exists (see render_edit_input_multiselect() /
   render_filter_multiselect()), so there's no separate "empty" state to theme - it's always the
   "has a value" dark look, matching the tag pills sitting inside it rather than leaving a plain
   white gap behind them. */
.multiselect-tags.select-primary-value {
    border: 1px solid var(--primary-border);
    background-color: var(--very-dark-primary);
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

.multiselect-tags.select-secondary-value {
    border: 1px solid var(--secondary-border);
    background-color: var(--very-dark-secondary);
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--secondary-shadow) !important;
}

.multiselect-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 3px;
    font-size: 13px;
    white-space: nowrap;
}

.multiselect-tag-primary {
    background-color: var(--dark-primary);
    color: var(--primary-bright-text);
    border: 1px solid var(--primary-border);
}

.multiselect-tag-secondary {
    background-color: var(--dark-secondary);
    color: var(--secondary-bright-text);
    border: 1px solid var(--secondary-border);
}

.multiselect-tag-remove {
    color: inherit;
    text-decoration: none;
    font-weight: bold;
    line-height: 1;
    opacity: 0.8;
}

.multiselect-tag-remove:hover {
    opacity: 1;
    text-decoration: none;
    color: inherit;
}



/* Same secondary/primary/-value language as the select2 classes above, for plain inputs/textareas
   and non-form-control write controls alike (image/gallery/swiper upload areas) - no shared
   container to target here, so these apply straight to whatever element carries the class.
   Deliberately NOT scoped to .form-control so the image-upload area (a <label>, not an input)
   can use them too; declaration order alone (after the .form-control unify-borders rule above)
   is enough to win against that rule's !important border-color at equal specificity. */
.input-secondary {
    border-width: 1px;
    border-style: solid;
    border-color: var(--secondary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--secondary-shadow) !important;
}

.input-secondary-value {
    border-width: 1px;
    border-style: solid;
    background-color: var(--very-dark-secondary);
    color: var(--secondary-bright-text);
    border-color: var(--secondary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--secondary-shadow) !important;
}

.input-primary {
    border-width: 1px;
    border-style: solid;
    border-color: var(--primary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

.input-primary-value {
    border-width: 1px;
    border-style: solid;
    background-color: var(--very-dark-primary);
    color: var(--primary-bright-text);
    border-color: var(--primary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

/* 'slider' edit field (render_edit_input_slider()) - neon-forms.css's .slider look (10px track,
   20px round handle, value label under the handle) under its own class, since that field can't
   carry .slider itself (see the function's comment). jQuery UI's own base CSS supplies the
   positioning. Colors follow the same edit-control language as .input-primary-value above: dark
   track, filled up to the handle, bright handle and value label. margin-top lines the track up with
   the control-label beside it; margin-bottom leaves room for the value label under it. */
.edit-slider {
    width: 100%;
    height: 10px;
    margin-top: 12px;
    margin-bottom: 30px;
    border-radius: 3px;
}

.edit-slider .ui-slider-handle {
    top: 0;
    width: 20px;
    height: 20px;
    margin-top: -6px;
    margin-left: -10px;
    border-radius: 50%;
    outline: none;
    cursor: pointer;
}

.edit-slider .ui-slider-handle .ui-label {
    position: absolute;
    top: 22px;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
}

.edit-slider .ui-slider-range {
    border-radius: 3px;
}

.edit-slider.slider-primary {
    background: var(--dark-primary);
    border: 1px solid var(--primary-border);
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow);
}

.edit-slider.slider-primary .ui-slider-range {
    background: var(--muted-primary);
}

.edit-slider.slider-primary .ui-slider-handle {
    background: var(--bright-primary);
    border: 2px solid var(--primary-border);
}

.edit-slider.slider-primary .ui-slider-handle .ui-label {
    color: var(--primary-bright-text);
}

/* Batch mode's 'input' => 'select' cell (render_table(), neon_html_select.php) - a native <select>'s
   open dropdown is an OS-native popup, so Chrome/Edge give CSS no way at all to color its :hover
   state (only Firefox honors that). This is an ordinary DOM list instead (Bootstrap 3's own
   .dropdown/.dropdown-menu, not select2 - a real <li>/<a> hover is normal CSS everywhere), styled
   to match this app's own primary edit-control language rather than Bootstrap's default grey.
   .table-select-toggle carries .input-primary/.input-primary-value (same classes/shadow as every
   other batch cell input) so it still visibly reads as a value that writes back on save, not a
   plain button. */
.table-select {
    width: 100%;
}

/* Flex, not the old float-right caret alone - once a clear "x" sits at this same right edge
   (.table-select-clear below), a long label needs to stop (ellipsis) before reaching either one
   rather than run under them, which text-overflow on the button itself can't target selectively.
   .table-select-label carries the ellipsis instead, as the one flexible-width item. */
.table-select-toggle {
    display: flex;
    align-items: center;
    width: 100%;
    text-align: left;
    cursor: pointer;
}

.table-select-label {
    flex: 1 1 auto;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.table-select-toggle:after {
    content: "";
    flex: 0 0 auto;
    display: inline-block;
    margin-left: 8px;
    border-top: 4px solid;
    border-right: 4px solid transparent;
    border-left: 4px solid transparent;
}

/* Same "x" this control's own :after-drawn caret above uses currentColor for - see the select2
   arrow/clear rules further below for why: color can't be aimed at a background-image, but this is
   plain text, so it already inherits .table-select-toggle's own input-primary/-primary-value color
   with no extra rule needed. Only ever rendered for a clearable, currently-valued cell (PHP side),
   so there's no "hide when empty" state to handle here. */
.table-select-clear {
    flex: 0 0 auto;
    margin-left: 8px;
    font-size: 16px;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
}

.table-select-clear:hover {
    opacity: 0.7;
}

.table-select-menu {
    width: 100%;
    max-height: 260px;
    overflow-y: auto;
}

.table-select-menu>li>a:hover,
.table-select-menu>li>a:focus {
    background-color: var(--very-dark-primary);
    color: var(--bright-primary);
}

.table-select-menu>li.active>a,
.table-select-menu>li.active>a:hover,
.table-select-menu>li.active>a:focus {
    background-color: var(--bright-primary);
    color: var(--very-dark-primary);
}

/* .table-responsive's overflow-x: auto (bootstrap.css) forces overflow-y to 'auto' too per the CSS
   overflow spec (an element can't have one axis clipping and the other genuinely visible), so it
   was clipping a table-select dropdown-menu the instant it grew taller than the scroll container -
   including at the table's own outer border, not just the viewport edge. Neutralized only while a
   menu is actually open (class toggled in the show/hidden.bs.dropdown handlers, neon_html_select.php)
   so a wide table keeps its horizontal scrollbar the rest of the time. */
.table-responsive.table-select-menu-open {
    overflow: visible;
}

/* A currency field's "SEK" suffix (render_edit_input_text() in neon_html_edit.php) is an overlaid
   label inside the same <input> box, not a separate .input-group-addon segment - that would sit
   outside the field entirely, with its own plain border, so .input-primary/-value's glow (above)
   would only ever wrap the input half, leaving the addon looking like a disconnected second box. */
.currency-input-wrapper {
    position: relative;
}

.currency-input-wrapper .currency-input {
    padding-right: 48px;
}

.currency-input-wrapper .currency-suffix {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(calc(-50% + 1px));
    opacity: 0.65;
    pointer-events: none;
}

.btn-danger,
.tile-danger {
    background-color: #ffbbbb !important;
    border: 1px solid #bb7777 !important;
    color: #440000 !important;
}

.btn-danger:hover,
.switch-danger,
.tile-danger:hover {
    background-color: #330000 !important;
    border: 1px solid #bb7777 !important;
    color: #ffbbbb !important;
}

.btn-info,
.tile-info {
    background-color: #bbbbff !important;
    border: 1px solid #7777bb !important;
    color: #000044 !important;
}

.btn-info:hover,
.switch-info,
.tile-info:hover {
    background-color: #000033 !important;
    border: 1px solid #7777bb !important;
    color: #bbbbff !important;
}

.btn-success,
.tile-success {
    background-color: #bbffbb !important;
    border: 1px solid #77bb77 !important;
    color: #004400 !important;
}

.btn-success:hover,
.switch-success,
.tile-success:hover {
    background-color: #003300 !important;
    border: 1px solid #77bb77 !important;
    color: #bbffbb !important;
}

.btn-warning,
.tile-warning {
    background-color: #ffffbb !important;
    border: 1px solid #bbbb77 !important;
    color: #444400 !important;
}

.btn-warning:hover,
.switch-warning,
.tile-warning:hover {
    background-color: #333300 !important;
    border: 1px solid #bbbb77 !important;
    color: #ffffbb !important;
}

/* Both the table-cell status coloring below and render_alert()'s boxed alerts (neon_html_common.php -
   error/warning banners above forms and on top of individual fields, plus the couple of literal
   alert-primary/alert-success boxes in my_information/my_artwork/login's own views) used to share
   Bootstrap's own blue/green/yellow/red alert hues. Both are recolored here onto the same
   primary(magenta)/secondary(cyan) families the rest of the app already uses: info/success reuse
   each family's light resting look, warning/danger reuse its dark/inverted hover look, so all four
   read as clearly distinct while staying inside the app's two-color language. */
.alert-info {
    background-color: var(--bright-secondary) !important;
    border: 1px solid var(--secondary-border) !important;
    color: var(--secondary-dark-text) !important;
}

.alert-success {
    background-color: var(--bright-primary) !important;
    border: 1px solid var(--primary-border) !important;
    color: var(--primary-dark-text) !important;
}

.alert-warning {
    background-color: var(--very-dark-secondary) !important;
    border: 1px solid var(--bright-secondary) !important;
    color: var(--bright-secondary) !important;
}

.alert-danger {
    background-color: var(--very-dark-primary) !important;
    border: 1px solid var(--bright-primary) !important;
    color: var(--bright-primary) !important;
}

/* The table-cell version (render_table()'s 'alert' => 'status_color' column type,
   neon_html_select.php) - same 4 colors as the boxed alerts above, but applied straight to the
   whole cell (background + text, no border) instead of a nested alert box, per-request. Separate
   classes from .alert-* above so the two call sites can be recolored independently. */
.status-info {
    background-color: var(--bright-secondary) !important;
}

.status-info h5 {
    color: var(--secondary-dark-text) !important;
}

.status-success {
    background-color: var(--bright-primary) !important;
}

.status-success h5 {
    color: var(--primary-dark-text) !important;
}

.status-warning {
    background-color: var(--very-dark-secondary) !important;
}

.status-warning h5 {
    color: var(--bright-secondary) !important;
}

.status-danger {
    background-color: var(--very-dark-primary) !important;
}

.status-danger h5 {
    color: var(--bright-primary) !important;
}

/* bootstrap-wysihtml5 (vendored) hardcoded its bold/italic/underline buttons as
   btn-danger/-warning/-success - a leftover template choice from the library, not a semantic
   "danger/warning/success" meaning, which used to need a CSS reset here to keep them from
   standing out from the rest of the toolbar's plain btn-white buttons. Now overridden at the
   source instead via the 'emphasis' customTemplates option (initWysihtml5(), custom.js), which
   the library reads before building the toolbar - so those 3 buttons carry btn-white themselves,
   same as their neighbors, and need no separate CSS rule at all. */

/* .btn-white's own native border (#ebebeb, neon-core.css) is much paler than the app's one
   unified control border (#949494 - see the very first rule in this file) that the toolbar's own
   frame around these buttons already uses, so every button in the toolbar read as a near-invisible
   outline floating inside a sharply-bordered box. Sharpen all of them - not just the former
   emphasis trio - to the same grey as every other bordered control/button in the app. */
.wysihtml5-toolbar .btn,
.wysihtml5-toolbar .btn:hover,
.wysihtml5-toolbar .btn:focus {
    border-color: var(--border-grey) !important;
}

/* wysihtml5 swaps the source <textarea> for this hardcoded iframe (className set directly in
   the library, nothing from the textarea carries over) - no per-field "has a value" hook
   available here the way plain inputs have, so this is a flat input-primary look, not -value. */
iframe.wysihtml5-sandbox {
    border-width: 1px;
    border-style: solid;
    border-color: var(--primary-border) !important;
    box-shadow: 0px 1px 1px var(--black-shadow) inset, 0px 0px 8px var(--primary-shadow) !important;
}

.main-content {
    padding-right: 15px;
    overflow-y: auto;
}

.se-pre-con {
    position: fixed;
    left: 0px;
    top: 80px;
    width: 100%;
    height: 80%;
    z-index: 9999;
    background: url(../../img/loading_icon.gif) center no-repeat #fff;
}

.gradient-primary {
    background: linear-gradient(to bottom right, #ffffff 0% var(--bright-primary) 140%) !important;
}

.gradient-secondary {
    background: linear-gradient(to bottom right, #ffffff 0% var(--bright-secondary) 140%) !important;
}

.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(max(200px, calc((100% - 30px) / 4)), 1fr));
    grid-gap: 10px;
}

.tile-stats {
    transition: transform 0.5s;

    &:hover {
        transform: scale(1.1);
    }
}

ul {
    z-index: 2;
}

.panel-heading {
    cursor: pointer !important;
}

.ms-selection .ms-list,
.ms-selectable .ms-list {
    height: auto;
    max-height: calc(2.7rem * 5);
    overflow-y: auto;
    margin-bottom: 10px;
    width: 100%;
}

.ms-container {
    display: flex;
    justify-content: space-between;
    width: 100% !important;
    padding: 0 !important;
    margin-right: 0 !important;
    margin-left: 0 !important;
    margin-bottom: 10px !important;
    box-sizing: border-box;
}

.ms-container::before,
.ms-container::after,
.ms-selectable::before,
.ms-selectable::after,
.ms-selection::before,
.ms-selection::after,
.ms-selectable .ms-arrow {
    display: none !important;
    content: none !important;
}

.ms-selectable,
.ms-selection {
    min-width: 48% !important;
    max-width: 48% !important;
    margin: 0px !important;
    padding: 0px !important;
    box-sizing: border-box;
}

.btn-group-toggle {
    display: flex;

    label {
        flex: 1 1 auto;
        width: 100%;
        white-space: normal;
    }
}

.dt-button-collection {
    .dt-button {
        display: block;
        width: 100%;
        padding: 8px 16px;
        text-align: left;

        span {
            display: block;
        }
    }
}

.table,
.dt-paging,
.dt-info,
.dt-search,
.dt-length {
    margin-top: 0px !important;
    margin-bottom: 15px !important;
}

.dt-button,
.dt-paging,
.dt-info,
.dt-length,
.dt-search,
.dt-buttons {
    float: left !important;
    margin-right: 15px !important;
}

.navbar {
    background-color: var(--navbar-grey);
}

.navbar-inner {
    background-color: var(--navbar-grey);
}

.navbar-nav {
    background-color: var(--navbar-grey);
}

.navbar-brand {
    color: #fff;
    font-size: 26px;
    font-family: "NeuePlakText-Regular", sans-serif;
}

header {
    li {
        background-color: var(--navbar-grey);
    }

    ul {
        background-color: var(--navbar-grey);
    }
}

.nw {
    white-space: nowrap !important;
}

/* Allow wrap and full width on xs screens */
.nw-wrap {
    @media (max-width: 575.98px) {
        white-space: normal !important;
        width: 100% !important;
    }
}

/* Hide other columns */
.nw-hide {
    @media (max-width: 575.98px) {
        display: none !important;
    }
}

.edit {
    cursor: pointer !important;

    tr {
        cursor: pointer;
    }
}

td {
    .input-spinner {
        display: inline-flex;
        align-items: center;
    }

    input,
    .btn,
    select td option {
        margin-bottom: 0;
    }

    .btn {
        font-size: 12px;
    }
}

div .alert {
    padding: 10px;
}

.input-spinner {
    display: flex;

    button {
        flex: 1 1 auto;
    }
}

.alert-cell {
    margin: 0px !important;
    padding: 5px !important;
    width: 100% !important;
}

.wysihtml5-toolbar {
    /* neon-forms.css gives .wysihtml5-toolbar a clearfix using content: " " (a literal
       space) on :before, which renders as a small table-level box before the first
       button and shows up as stray blank space; :after with clear:both is the part
       that's actually needed, so just drop the :before box */
    &:before {
        content: none;
        display: none;
    }

    /* give the toolbar its own form-control-like frame (matching the textarea below)
       so it reads as one control instead of buttons floating on the page background */
    background-color: var(--background-white);
    border: 1px solid var(--border-grey);
    border-bottom: none;
    border-radius: 3px 3px 0 0;
    padding: 6px 8px;
    margin-bottom: 0 !important;

    /* keep toolbar items on one line, with a little spacing between groups */
    >li {
        display: inline-block;
        vertical-align: top;
        margin-right: 4px;
    }

    /* if something forces full width */
    white-space: nowrap;
}

/* flatten the textarea's top corners so it fuses seamlessly with the toolbar above */
textarea.wysihtml5 {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

.dashboard-row-eq-height {
    display: flex !important;
    flex-wrap: wrap !important;

    >[class*="col-"] {
        display: flex !important;
        margin-bottom: 10px !important;
    }

    a {
        display: flex !important;
        width: 100% !important;
    }

    .dashboard-tile-stats {
        flex: 1 !important;
        width: 100% !important;
    }
}

/* render_image_tile() (neon_html_simple.php): an invisible square cell (unless a taller text
   tile in the same .row-eq-height row stretches it) with the uncropped thumbnail centred in it;
   the grey border sits on the image itself. */
.dashboard-image-tile {
    width: 100%;
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.5s;

    &:hover {
        transform: scale(1.1);
    }

    img {
        max-width: 100%;
        max-height: 100%;
        object-fit: contain;
        display: block;
        box-sizing: border-box;
        border: 1px solid var(--border-grey);
    }
}

.dashboard-tile-stats h4 {
    word-break: normal !important;
    overflow-wrap: anywhere !important;
    hyphens: none !important;
}

.btn-shine {
    position: relative;
    overflow: hidden;

    &::after {
        content: "";
        position: absolute;
        top: 0;
        left: -75%;
        width: 50%;
        height: 100%;
        background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.4), transparent);
    }

    &:hover::after {
        animation: shine .5s;
    }
}

@keyframes shine {
    100% {
        left: 150%;
    }
}

/* Read-only 'html' field type (render_edit_html) - rendered HTML inside the standard input outline.
   .form-control's fixed height is lifted so the box grows with its content. */
.form-control.html-field {
    height: auto;
    min-height: 34px;
    overflow-x: auto;
    overflow-wrap: anywhere;
}

.html-field > :last-child {
    margin-bottom: 0;
}

.html-field img,
.html-field table {
    max-width: 100%;
}

.html-field img {
    height: auto;
}

/* neon-core.css hides a top menu's caption after its icon on tablets (767-992px, "i + span
   { display: none }") - keep the captions visible at every width. */
@media (min-width: 767px) and (max-width: 992px) {
    .page-container.horizontal-menu header.navbar .navbar-nav > li > a i + span {
        display: inline;
    }
}

/* Rensa/skriv ut buttons show only an icon below lg; drop side padding and the entypo glyph's
   own .2em margins so the icon fits and stays centered in a narrow col-sm-1 button. */
@media (max-width: 1199px) {
    .btn.btn-compact {
        padding-left: 0;
        padding-right: 0;
    }

    .btn.btn-compact [class^="entypo-"]:before,
    .btn.btn-compact [class*=" entypo-"]:before {
        margin-left: 0;
        margin-right: 0;
    }
}
