/* ======================================================================
   Merged in from theme.css / theme-override.css.
   These loaded BEFORE this file did, so they sit at the top: everything
   below still overrides them, exactly as it did when they lived in the
   two old sheets.
   ====================================================================== */
/* ----- from theme.css ----- */


.form-control:focus {
    border-color: #3e93ff;
}
.form-control:not(textarea) {
  height: inherit !important;
}

.form-control:-moz-placeholder {
  color: inherit;
  opacity: 0.7; }

.form-control::-ms-input-placeholder {
  color: inherit;
  opacity: 0.7; }

.form-check [type="checkbox"]:not(:checked) + .form-check-sign {
  position: relative;
  padding-left: 2em;
  color: #2A2F5B;
  cursor: pointer; }
.form-check [type="checkbox"]:not(:checked) + .form-check-sign:before,
.form-check [type="checkbox"]:checked + .form-check-sign:before {
  content: '';
  position: absolute;
  left: 0;
  top: 1px;
  width: 16px;
  height: 16px;
  border: 1px solid #ccc;
  background: transparent;
  border-radius: 4px; }
.form-check [type="checkbox"]:not(:checked) + .form-check-sign:after {
  content: "\f00c";
  display: inline-block;
  position: absolute;
  top: -1px;
  left: 2px;
  width: 18px;
  height: 18px;
  text-align: center;
  font-size: 1.3em;
  line-height: 0.8;
  color: var(--color-blue);
  transition: all .2s;
  font-family: 'Font Awesome 6 Free'; }
.form-check [type="checkbox"]:not(:checked) + .form-check-sign:after {
  opacity: 0;
  transform: scale(0); }

.form-check [type="checkbox"]:disabled:not(:checked) + .form-check-sign:before {
  box-shadow: none;
  border-color: #bbb;
  background-color: #ddd; }
.form-check [type="checkbox"]:disabled:checked + .form-check-sign:before {
  box-shadow: none;
  border-color: #bbb;
  background-color: #ddd; }

.form-check [type="checkbox"]:checked:focus + .form-check-sign:before, .form-check [type="checkbox"]:not(:checked):focus + .form-check-sign:before {
  border: 1px solid #ccc; }

  

  
  .form-floating-label .form-control :-moz-placeholder {
    color: transparent; }

  
  .form-floating-label .form-control {
    padding: .2rem !important;
  }    body[data-background-color="dark"] .form-control,
body[data-background-color="dark"] .select2-container--default .select2-selection {
      background-color: var(--input-bg);
      color: #fff;
      border-color: var(--input-border); }
/* ----- from theme-override.css ----- */

/* Make read only text field font darker so it's easy to read. */
input.form-control[type="text"]:read-only {
    /*color: #040406 !important;*/
    /*font-weight: bold !important;*/
}
input.form-control[type="number"]:read-only {
    /*color: #040406 !important;*/
    /*font-weight: bold !important;*/
}
input.form-control[type="tel"]:read-only {
    /*color: #040406 !important;*/
    /*font-weight: bold !important;*/
}
input[type=checkbox], input[type=radio] {
    margin-left: .3rem;
    margin-top: 6px;
}
.form-check-inline {
    display: inline-flex !important;
    flex-direction: row !important;
}
.form-check-inline .form-check-input {
    margin-bottom: 8px;
}.custom-select.is-invalid:focus, .was-validated .custom-select:invalid:focus {
    background-color: var(--chrome-base);
}
.custom-select.is-invalid, .was-validated .custom-select:invalid{
    background-color: var(--chrome-base);
}

.form-floating-label select.form-control {
    padding: 0.26rem !important;
}

body[data-background-color="dark"] .form-control:focus:not([readonly]),
body[data-background-color="dark"] select.form-control:focus:not([readonly]) {
    background: var(--input-bg-focus) !important;
    border-color: var(--input-border-focus) !important;
    color: var(--text-primary) !important;
    box-shadow: var(--input-focus-ring) !important;
    outline: none !important;
}

body[data-background-color="dark"] select.form-control:open {
    background-color: var(--input-bg-focus) !important;
    border-color: var(--input-border-focus) !important;
    box-shadow: var(--input-focus-ring) !important;
}
.form-group-sm .toggle-field-slot {
    min-height: calc(1.5em + 0.5rem + 2px);
}

body[data-background-color="dark"] .input-group > .form-control:focus,
body[data-background-color="dark"] .input-group > .custom-select:focus {
    box-shadow: none !important;
}body[data-background-color="dark"] .form-control,
body[data-background-color="dark"] .select2-selection,
body[data-background-color="dark"] select.form-control {
    color: var(--text-primary) !important;
    background-color: var(--input-bg) !important;
    border-color: var(--input-border) !important;
}

.input-kbd-hint {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    font-size: 0.7rem;
    background: var(--kbd-bg);
    border: 1px solid var(--kbd-border);
    border-radius: 3px;
    padding: 1px 5px;
    color: var(--kbd-fg);
    opacity: var(--kbd-opacity);
}

/* Form actions row rendered by the `FormActions` layout object. Owned
   markup — class names belong to us, not crispy. Cancel link on the left,
   primary submit on the right, with a top divider that anchors the row to
   the form above. */
.form-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border-normal);
}

.form-actions-secondary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

/* Shared min-width so the three action buttons read as a matched set. */
.form-actions-btn {
    min-width: 140px;
}

/* Back button — uses surface tokens to feel like a real button instead
   of the default washed-out outline. */
.form-actions-cancel {
    background: var(--surface-2);
    border: 1px solid var(--border-normal);
    color: var(--text-primary);
}

.form-actions-cancel:hover {
    background: var(--surface-3);
    color: var(--text-primary);
}/* Inline-statement toggle: switch + sentence on a single row, no uppercase
   form-field label. The sentence reads as a setting, not a form input. */
.form-group.inline-statement-pill-switch .custom-control-label {
    cursor: pointer;
    padding-left: 0.4rem;
    font-size: 0.875rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-secondary);
    /* Sentence-length label: must wrap on narrow screens, unlike the
       nowrap eyebrow labels (.form-group label above). Otherwise it
       pokes past the viewport and gives the page horizontal overflow. */
    white-space: normal;
}
.form-group.inline-statement-pill-switch .custom-control-input {
    cursor: pointer;
}

/* PillSwitch: standard form-group with a Bootstrap custom-switch placed
   inline with the label text. Help text drops below. The `<label>` is a
   direct child of `.form-group` so the global label styling applies.
   Flex on the form-group lets `align-items: center` vertically center the
   label text with the (taller) switch. Help text wraps to its own row. */
.form-group.pill-switch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 0.6rem;
}
.form-group.pill-switch > label {
    margin-bottom: 0 !important;
}
.form-group.pill-switch > .pill-switch-switch {
    flex: 0 0 auto;
}
.form-group.pill-switch > .pill-switch-help {
    flex-basis: 100%;
    margin-top: 0.05rem;
}
.form-group.pill-switch > .pill-switch-switch.custom-switch .custom-control-input,
.form-group.pill-switch > .pill-switch-switch.custom-switch .custom-control-label {
    cursor: pointer;
}
/* Both lines stay on one line each — the column is narrow in wide tables and
   a wrapped date reads as two separate values. */
.stacked-datetime .time,
.stacked-datetime .date {
    white-space: nowrap;
}
.stacked-datetime .time {
    font-weight: 600;
    color: var(--text-secondary);
}
/* When the stamp is itself the row link, the time reads as a link. */
a.cell-link .stacked-datetime .time {
    color: var(--color-blue);
}
a.cell-link:hover .stacked-datetime .time {
    color: var(--color-blue-hover);
}
.stacked-datetime .date {
    font-size: .75rem;
    color: var(--text-tertiary);
}
/* Every type listed here must stay in sync: any control left out keeps the
   UA drawing its chrome for the other scheme. */
input[type="time"], input[type="date"], input[type="datetime-local"],
input[type="number"] {
    color-scheme: var(--control-scheme);
}

/* Number spinner: dark-scheme so Chrome draws it in theme colors, and
   hidden until hover/focus so resting inputs stay clean. */
input[type="number"]::-webkit-inner-spin-button {
    opacity: 0;
    transition: opacity 0.15s ease;
}

input[type="number"]:hover::-webkit-inner-spin-button,
input[type="number"]:focus::-webkit-inner-spin-button {
    opacity: 1;
}

/* ==========================================================================
   Forms — the single owner of form-control chrome.

   Consolidated from theme.css (vendor) and theme-override.css (app layer);
   every value here is the one that already resolved after that cascade.

   Load order: bootstrap.min.css → theme.css → THIS FILE.
   Bootstrap is earlier, so plain declarations beat it at equal specificity;
   the !important that remain are called out individually — each one is
   there to beat a Bootstrap rule that is itself !important or lands at a
   higher specificity (chiefly the `.is-invalid` / `.was-validated`
   validation family), or a vendor rule outside this file's scope.

   Everything is driven by the --input-* token ladder in tokens.css, which
   flips it for the light theme:

     --input-bg            fields have NO fill of their own; the border
                           alone defines them, so a field sits on whatever
                           surface it lands on (card, modal, zebra row)
     --input-bg-focus      same as resting — the border change alone
                           signals focus
     --input-bg-disabled   the one field state that carries a fill, so an
                           inert control reads as filled-in
     --input-border        single source of truth for every input edge
     --input-border-focus  focus pushes the edge well past hover, so the
                           two states differ by how solid the line is,
                           not by hue
     --input-border-disabled  the same white at half strength
     --input-inset         a no-op shadow: a field is an outline, not a
                           recess
     --input-focus-ring    a faint halo just outside the border
     --select-*            the dropdown is the field continued

   Nothing here may hardcode a value those tokens own.

   Not owned by this file: .btn (buttons), select2 (select2.css), the
   crispy IconFieldset family (fieldset/legend/.pill-switch/.gated-*),
   bootstrap-toggle (.toggle-*), .selectgroup-*, swal2 inputs.
   ========================================================================== */


/* --- Labels and help text ---------------------------------------------- */

/* !important on color and font-size: theme.css keeps non-form label rules
   that out-specify this one and would otherwise take over —
   `.card-dark label { color: #fff }` and
   `body[data-background-color="dark"] .main-panel label { color: #fff }`.
   Both are dead today because of this !important; keep them dead. */
.form-label,
label {
    color: var(--text-label) !important;
    font-size: 14px !important;
    font-weight: 500;
    margin-bottom: 0.5rem;
}

/* Legacy jquery-validate error label (vendor theme JS still emits it). */
label.error {
    color: var(--color-red) !important;
    font-size: 80% !important;
    margin-top: 0.5rem;
}

.form-text {
    color: var(--text-muted);
    font-size: 0.8rem;
}

/* Labels inside a field wrapper. `white-space: nowrap` is inherited by the
   uppercase eyebrow rule below and is load-bearing there. */
.form-group label,
.form-check label {
    margin-bottom: 0.5rem;
    font-weight: 600;
    white-space: nowrap;
}

/* The field eyebrow: small uppercase tracked label above every control.
   Excludes inline check/radio labels and .col-form-label (horizontal
   layouts) so those keep their original sizing.
   !important on color/font-size beats the app-wide `label` rule above,
   which is itself !important. */
.form-group > label:not(.col-form-label):not(.custom-control-label):not(.form-check-label),
.form-group > .control-label:not(.col-form-label) {
    display: block;
    margin-bottom: 0.2rem;
    font-size: 0.72rem !important;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary) !important;
    line-height: 1.3;
}

/* Required-field asterisk that crispy injects. */
.form-group > label .asteriskField {
    color: var(--color-red);
    margin-left: 0.2rem;
    font-weight: 700;
    text-decoration: none;
}

/* Push the LabelHelpModalField icon after the required asterisk via flex
   order. The asterisk is appended after the icon in the DOM, so without
   this it would render before the asterisk. */
.form-group > label:has(.label-help-icon) {
    display: inline-flex;
    align-items: baseline;
    flex-wrap: wrap;
}
.form-group > label .label-help-icon {
    order: 2;
}

/* !important: the eyebrow rule above is (0,4,1) and this is (0,1,1). */
.form-inline label {
    margin-bottom: 0 !important;
}

.col-form-label {
    line-height: 1.8;
}

/* !important: beats `.table tr td, .table tr th { padding: .5rem !important }`
   in theme-override.css. */
.table th.col-form-label {
    padding-left: 15px !important;
}

.login .custom-control-label {
    white-space: nowrap;
}


/* --- Field wrappers ----------------------------------------------------- */

.form-group {
    margin-bottom: 0.85rem;
    padding: 3px;
}

.form-check {
    margin-bottom: 0;
    padding: 3px;
}

/* Help text below an input. */
.form-group .form-text,
.form-group small.form-text,
.form-group .help-block {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--text-muted);
}

/* Tighten the gap between the label and the input so they read as a
   single unit. */
.form-group > label + .form-control,
.form-group > label + .select2,
.form-group > label + .input-group,
.form-group > label + textarea {
    margin-top: 0;
}

/* Last form-group inside a card/modal body shouldn't add bottom margin
   since the container already has padding. */
.modal-body > form > .form-group:last-child,
.card-body > form > .form-group:last-child {
    margin-bottom: 0;
}


/* --- Text inputs -------------------------------------------------------- */

/* !important on background/border/color: Bootstrap's validation family
   (`.form-control.is-invalid`, `.was-validated .form-control:invalid`)
   lands at (0,2,0)/(0,2,1) and would repaint the edge red and inject the
   warning-icon background. Errors are shown by .invalid-feedback instead. */
.form-control,
select.form-control {
    background: var(--input-bg) !important;
    border: 1px solid var(--input-border) !important;
    color: var(--text-primary) !important;
    border-radius: 6px;
    /* The metrics block below restates this as 14px for every control it
       covers; this is what textareas and .custom-file land on. */
    font-size: 0.875rem;
    box-shadow: var(--input-inset);
    transition: all 0.2s ease;
}

/* :not([readonly]) matters — a readonly field still takes focus, so
   without it clicking one repaints it with the active-field fill and it
   stops reading as inert.
   !important: `.was-validated .form-control:invalid:focus` is (0,3,1) in
   Bootstrap and carries its own border-color and box-shadow. */
.form-control:focus:not([readonly]),
select.form-control:focus:not([readonly]) {
    background: var(--input-bg-focus) !important;
    border-color: var(--input-border-focus) !important;
    color: var(--text-primary) !important;
    box-shadow: var(--input-focus-ring) !important;
    outline: none !important;
}

/* Chrome autofill forces its own background/text color with UA !important
   rules that author styles can't override. Both are animatable, so an
   effectively-infinite transition delay keeps the input's own colors on
   screen indefinitely instead. Autofilled fields deliberately look
   identical to normally-filled ones — Chrome's key icon is the only hint.
   !important: beats the UA rule. */
.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus {
    transition: background-color 600000s 0s, color 600000s 0s !important;
    -webkit-text-fill-color: var(--text-primary) !important;
    caret-color: var(--text-primary);
}

.form-control::placeholder {
    color: var(--text-muted);
}

/* The prefixed aliases are separate rules on purpose: an unrecognised
   pseudo-element invalidates the whole selector list it appears in.
   Bootstrap sets opacity 1 on each of these; the vendor theme dims them. */
.form-control::-webkit-input-placeholder {
    opacity: 0.7;
}
.form-control::-moz-placeholder {
    opacity: 0.7;
}
.form-control:-ms-input-placeholder {
    opacity: 0.7;
}

.form-control[readonly] {
    margin: 2px 0;
}


/* --- Standardised control metrics --------------------------------------
   Single source of truth so text inputs, native selects, Select2 pickers
   and the polymorphic destination widget all line up in the same row.

     Default size:  38px tall  (line-height 36px + 2px border)
     Small size:    32px tall  (line-height 30px + 2px border)

   Zero vertical padding + an explicit line-height sized to fill the box.
   That centers content automatically and is the only way to get Select2's
   nested __rendered span to land at the same height as everything else.
   The select2 selectors here own only the OUTER box; select2.css owns the
   inner span and must change with them.

   !important on padding / padding-right ONLY: Bootstrap's
   `.form-control.is-valid { padding-right: 3rem !important }` and
   `.form-control.is-invalid { padding-right: calc(1.5em + .75rem) !important }`
   reserve room for a validation icon this theme never shows. -------------- */

.form-control:not(.form-control-sm):not(textarea):not(.custom-file),
select.form-control:not(.form-control-sm),
.select2-container .select2-selection--single,
.upoly-trigger.form-control:not(.form-control-sm) {
    height: 38px;
    min-height: 38px;
    padding: 0 0.75rem !important;
    /* !important: the vendor size variants below are !important at lower
       specificity and would otherwise reinstate their own type size. */
    font-size: 14px !important;
    line-height: 36px;
    box-sizing: border-box;
}

/* Native select needs extra right padding so the OS chevron doesn't
   collide with the value. */
select.form-control:not(.form-control-sm) {
    padding-right: 1.75rem !important;
}

.form-control-sm:not(textarea):not(.custom-file),
select.form-control-sm,
.input-group-sm > .form-control:not(textarea):not(.custom-file),
.input-group-sm > .input-group-prepend > .btn,
.input-group-sm > .input-group-append > .btn,
.upoly-trigger.form-control.form-control-sm,
.form-control-sm + .select2-container .select2-selection--single,
.input-group-sm > .select2-container .select2-selection--single,
.select2-container--sm .select2-selection--single {
    height: 32px;
    min-height: 32px;
    padding: 0 0.5rem !important;
    font-size: 0.8125rem !important;
    line-height: 30px;
    box-sizing: border-box;
}

select.form-control-sm {
    padding-right: 1.5rem !important;
}

/* Large select2. Bootstrap sizes .form-control-lg with vertical padding and
   never has to reach a nested span, so its 48px box is restated here in this
   file's zero-padding + line-height form — the only shape select2's
   __rendered span can be centered in. Its inner span is in select2.css. */
.form-control-lg + .select2-container .select2-selection--single,
.input-group-lg > .select2-container .select2-selection--single {
    height: 48px;
    min-height: 48px;
    padding: 0 1rem !important;
    font-size: 1.25rem !important;
    line-height: 46px;
    box-sizing: border-box;
}

/* Vendor size variants the metrics block above deliberately does not
   cover: the addon text of a sized input-group. Kept !important because
   that is how they win today over the base .input-group-text type size. */
.input-group-lg > .form-control,
.input-group-lg > .input-group-prepend > .btn,
.input-group-lg > .input-group-prepend > .input-group-text,
.input-group-lg > .input-group-append > .btn,
.input-group-lg > .input-group-append > .input-group-text,
.form-control-lg {
    padding: 0.5rem 1rem !important;
    font-size: 1.25rem !important;
}

.input-group-sm > .input-group-prepend > .input-group-text,
.input-group-sm > .input-group-append > .input-group-text {
    padding: 0.25rem 0.5rem !important;
    font-size: 0.875rem !important;
    line-height: 1.5;
}

/* Bootstrap shrinks every -sm control to a .2rem radius, leaving small
   controls less rounded than the base 6px ones. Use 6px across all sizes.
   Standalone controls and a group's .form-control take the full shorthand
   safely (Bootstrap zeros their inner corners at higher specificity). */
.form-control-sm,
.custom-select-sm,
.input-group-sm > .form-control,
.input-group-sm > .custom-select {
    border-radius: 6px;
}


/* --- Textareas ---------------------------------------------------------- */

/* Textareas opt out of the line-height trick — they need their own
   line-height for multi-line. !important on padding for the same
   validation-icon reason as above. */
textarea.form-control {
    line-height: 1.5;
    padding: 0.43rem !important;
}

textarea.form-control-sm {
    line-height: 1.5;
    padding: 0.25rem 0.5rem !important;
}

textarea.form-control::-webkit-resizer {
    background: linear-gradient(
        -45deg,
        transparent 0px,
        transparent 1px,
        rgba(255, 255, 255, 0.3) 1px,
        rgba(255, 255, 255, 0.3) 2px,
        transparent 2px,
        transparent 5px,
        rgba(255, 255, 255, 0.3) 5px,
        rgba(255, 255, 255, 0.3) 6px,
        transparent 6px,
        transparent 9px,
        rgba(255, 255, 255, 0.3) 9px,
        rgba(255, 255, 255, 0.3) 10px,
        transparent 10px
    ) var(--input-bg);
}


/* --- Native selects ----------------------------------------------------- */

/* .custom-select keeps Bootstrap's inline chevron svg: only background-color
   is set here, never the `background` shorthand, so the arrow survives.
   !important for the same validation-family reason as .form-control. */
.custom-select {
    background-color: var(--input-bg) !important;
    border-color: var(--input-border) !important;
    color: var(--text-primary) !important;
    box-shadow: var(--input-inset) !important;
}

.custom-select:focus {
    background-color: var(--input-bg-focus) !important;
    border-color: var(--input-border-focus) !important;
    color: var(--text-primary) !important;
    box-shadow: var(--input-focus-ring) !important;
}

/* While the popup is open, focus lives inside the picker, so :focus no
   longer matches the select — keep the focus look via :open. */
select.form-control:open,
.custom-select:open {
    background-color: var(--input-bg-focus) !important;
    border-color: var(--input-border-focus) !important;
    box-shadow: var(--input-focus-ring) !important;
}

select.form-control option,
.custom-select option {
    background-color: var(--select-option-bg);
    color: var(--text-primary);
}

select.form-control option:checked,
select.form-control option:focus,
.custom-select option:checked,
.custom-select option:focus {
    background-color: var(--select-option-bg-active);
    color: var(--text-primary);
}

/* !important: the UA paints its own hover highlight on native listbox
   options and ignores an author declaration without it. */
select.form-control option:hover,
.custom-select option:hover {
    background-color: var(--select-option-bg-hover) !important;
    color: var(--text-primary);
}

/* Chromium's customizable <select>: opting in makes the popup a
   page-styled popover we control, replacing the OS listbox with its
   bright UA border and offset. Single-selects only — multiple/size
   selects keep native rendering. Non-supporting browsers ignore the
   whole block. */
@supports (appearance: base-select) {
    select.form-control:not([multiple]):not([size]),
    .custom-select:not([multiple]):not([size]) {
        appearance: base-select;
        /* Bootstrap's inline-block display breaks base-select's flex
           layout and wraps the ▾ under the box — restore it. */
        display: flex !important;
        align-items: center;
        /* The picker-icon replaces Bootstrap's baked-in ⇕ svg, so the
           1.75rem right padding reserved for it can go too.
           !important on both: they beat Bootstrap's `.custom-select`
           background shorthand and the metrics rule above. */
        background-image: none !important;
        padding-right: 0.75rem !important;
    }
    select.form-control::picker(select),
    .custom-select::picker(select) {
        appearance: base-select;
        background: var(--select-option-bg);
        border: 1px solid var(--input-border-focus);
        /* Flush with the select, overlapping 1px so the two borders
           collapse into a single seam line and the focus halos merge
           into one ring around the open unit. */
        margin: -1px 0;
        /* The fallback for the moment before select_seam.js resolves the
           direction, and for any select it never sees. */
        border-radius: 6px;
        padding: 0.25rem 0;
        box-shadow: var(--input-focus-ring), 0 8px 24px rgba(0, 0, 0, 0.45);
        scrollbar-width: thin;
        scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
    }
    /* The seam. select_seam.js sets data-drop to the direction the picker
       actually opened, and the two edges that meet square off so the field
       and its list read as one control rather than two stacked boxes. The
       outer corners keep their 6px. */
    select.form-control[data-drop="down"]:open,
    .custom-select[data-drop="down"]:open {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }
    select.form-control[data-drop="down"]::picker(select),
    .custom-select[data-drop="down"]::picker(select) {
        border-top-left-radius: 0;
        border-top-right-radius: 0;
    }
    select.form-control[data-drop="up"]:open,
    .custom-select[data-drop="up"]:open {
        border-top-left-radius: 0;
        border-top-right-radius: 0;
    }
    select.form-control[data-drop="up"]::picker(select),
    .custom-select[data-drop="up"]::picker(select) {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }
    select.form-control option,
    .custom-select option {
        display: flex;
        align-items: center;
        padding: 0.375rem 0.75rem;
        font-size: 0.875rem;
        cursor: pointer;
    }
    /* The UA puts the checkmark before the label; select2 trails it, and
       leading it here would indent every label to leave room for a mark
       only one option ever shows. Ordered last and pushed to the far edge
       so the labels all start on the same line. */
    select.form-control option::checkmark,
    .custom-select option::checkmark {
        order: 1;
        margin-left: auto;
        color: var(--text-muted);
    }
    /* Swap the UA's solid ▾ for a thin chevron like select2's. */
    select.form-control::picker-icon,
    .custom-select::picker-icon {
        margin-left: auto;
        content: "";
        width: 0.4em;
        height: 0.4em;
        border-right: 1.5px solid var(--text-muted);
        border-bottom: 1.5px solid var(--text-muted);
        transform: translateY(-25%) rotate(45deg);
        color: var(--text-muted);
    }
}


/* --- File inputs -------------------------------------------------------- */

/* The control is a flex line so the UA button sits vertically centred as a
   compact pill; without it the button inherits the input's full content
   height and overflows the rounded border box. */
input[type="file"] {
    display: flex;
    align-items: center;
    line-height: 1.2;
    cursor: pointer;
}

input[type="file"]::file-selector-button {
    flex: none;
    height: auto;
    padding: 0.2rem 0.7rem;
    margin: 0 0.75rem 0 0;
    line-height: 1.4;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid var(--input-border);
    color: var(--text-primary);
    border-radius: 4px;
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 0.875rem;
}

input[type="file"]::file-selector-button:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: var(--input-border-hover);
}

input[type="file"]::file-selector-button:active {
    background: rgba(255, 255, 255, 0.15);
}

.custom-file {
    padding: 0.25rem;
}

.custom-file label {
    margin-bottom: 0;
}


/* --- Checkboxes, radios, switches --------------------------------------- */

input[type="checkbox"],
input[type="radio"] {
    margin-left: 0.3rem;
    margin-top: 6px;
}

.form-check-input {
    position: relative;
    margin-top: 0.3rem;
}

.form-check-label {
    margin-right: 15px;
}

.custom-control {
    position: relative;
}

/* !important on margin-bottom: `.form-group label` above is (0,1,1) and
   this is (0,1,0). */
.custom-control-label {
    color: var(--text-secondary);
    margin-bottom: 0 !important;
}

/* !important: `.form-group small.form-text` above is (0,2,1) and this is
   (0,2,0), so plain source order can't win. */
.custom-control .form-text {
    margin-top: 0 !important;
}

.custom-control.custom-radio,
.custom-control.custom-checkbox {
    margin-bottom: 0;
    padding-left: 1.5rem;
    cursor: pointer;
    line-height: 24px;
    margin-right: 25px;
    display: inline-block;
}

/* Remove padding from checkbox & radio input for table formsets. */
td .custom-control.custom-radio,
td .custom-control.custom-checkbox {
    padding-left: 0;
}

.custom-control.custom-radio label.error,
.custom-control.custom-radio label.success,
.custom-control.custom-checkbox label.error,
.custom-control.custom-checkbox label.success {
    position: absolute;
    width: 100vh;
    top: 23px;
    left: 0;
}

/* Unchecked track. Bootstrap paints it white with a grey edge, which is
   invisible against a light card. */
.custom-control-label::before {
    background-color: var(--switch-track-bg);
    border-color: var(--switch-track-border);
}

/* Checked fill. Radios and switches take the theme blue; checkboxes keep
   the vendor's older, deeper blue at higher specificity — that split is
   what renders today and is preserved deliberately. */
.custom-control-input:checked ~ .custom-control-label::before {
    background-color: var(--color-blue);
    border-color: var(--color-blue);
}

.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before {
    background-color: var(--color-blue);
}

/* Vendor Font Awesome checkbox: `.form-check > input[type=checkbox]`
   hidden offscreen with a `.form-check-sign` sibling drawing the box and
   the ✓ glyph. The sibling is what gates the hide — crispy renders a bare
   `.form-check-input` with no sign, and that box has to stay on screen. */
.form-check [type="checkbox"]:has(+ .form-check-sign) {
    position: absolute;
    left: -9999px;
}

.form-check [type="checkbox"] + .form-check-sign {
    position: relative;
    padding-left: 2em;
    color: #2A2F5B;
    cursor: pointer;
}

.form-check [type="checkbox"] + .form-check-sign:before {
    content: '';
    position: absolute;
    left: 0;
    top: 1px;
    width: 16px;
    height: 16px;
    border: 1px solid #ccc;
    background: transparent;
    border-radius: 4px;
}

.form-check [type="checkbox"] + .form-check-sign:after {
    content: "\f00c";
    display: inline-block;
    position: absolute;
    top: -1px;
    left: 2px;
    width: 18px;
    height: 18px;
    text-align: center;
    font-size: 1.3em;
    line-height: 0.8;
    color: var(--color-blue);
    transition: all 0.2s;
    font-family: 'Font Awesome 6 Free';
    opacity: 0;
    transform: scale(0);
}

.form-check [type="checkbox"]:checked + .form-check-sign {
    font-weight: 400;
}

.form-check [type="checkbox"]:checked + .form-check-sign:after {
    opacity: 1;
    transform: scale(1);
}

.form-check [type="checkbox"]:disabled + .form-check-sign {
    color: #aaa;
}

.form-check [type="checkbox"]:disabled + .form-check-sign:before {
    box-shadow: none;
    border-color: #bbb;
    background-color: #ddd;
}

.form-check [type="checkbox"]:disabled:checked + .form-check-sign:after {
    color: #999;
}

.form-check [type="checkbox"]:focus + .form-check-sign:before {
    border: 1px solid #ccc;
}

/* !important: beats the :focus rule above at lower specificity. */
.form-check-sign:hover:before {
    border: 1px solid #ccc !important;
}


/* --- Input groups ------------------------------------------------------- */

/* !important: theme.css keeps a dark-theme block that paints
   .input-group-text at (0,2,1) — `body[data-background-color="dark"]
   .input-group-text { border-color: … !important; background-color: …;
   color: #fff }`. That block must be deleted along with the rest; the
   !important here keeps this file correct either way. */
.input-group-text {
    background: var(--input-bg) !important;
    border: 1px solid var(--input-border) !important;
    color: var(--text-secondary) !important;
    box-shadow: var(--input-inset);
    transition: all 0.2s ease;
    font-size: 14px;
}

.input-group-text i.la {
    font-size: 21px;
}

.input-group-text i[class*="flaticon"] {
    font-size: 17px;
}

/* Append/prepend buttons share the input's border color so the group reads
   as one bordered control instead of a heavier btn-* seam. Height comes from
   stretching to the group rather than a fixed value, so the button tracks
   whatever the neighbouring control actually measures — a size variant the
   metrics blocks above don't cover (-lg), or a native date/time input whose
   shadow-DOM content is a couple of pixels taller than its declared height. */
.input-group > .input-group-append > .btn,
.input-group > .input-group-prepend > .btn {
    border-color: var(--input-border) !important;
    padding: 0 1rem;
    display: inline-flex;
    align-items: center;
    align-self: stretch;
    height: auto;
}

/* Floor for a group holding no input to stretch against. The -sm metrics block
   above already floors those buttons at 32px, so scoping this out of
   .input-group-sm keeps it from overriding them on source order. */
.input-group:not(.input-group-sm) > .input-group-append > .btn,
.input-group:not(.input-group-sm) > .input-group-prepend > .btn {
    min-height: 38px;
    height: auto;
}

/* Attached buttons must not run the .btn:hover translate, which makes them
   jump out of the group. */
.input-group > .input-group-prepend > .btn:hover,
.input-group > .input-group-append > .btn:hover {
    transform: none;
    box-shadow: none;
}

/* A group's prepend/append button/text ties Bootstrap's inner-corner
   zeroing in specificity, so only round the group's OUTER corners here and
   leave the inner seam corners to Bootstrap. */
.input-group-sm > .input-group-prepend:first-child > .btn:first-child,
.input-group-sm > .input-group-prepend:first-child > .input-group-text:first-child {
    border-top-left-radius: 6px;
    border-bottom-left-radius: 6px;
}
.input-group-sm > .input-group-append:last-child > .btn:last-child,
.input-group-sm > .input-group-append:last-child > .input-group-text:last-child {
    border-top-right-radius: 6px;
    border-bottom-right-radius: 6px;
}

/* The ring is drawn on the group box so it wraps the input and any
   append/prepend as one control; inner elements draw none (below). */
.input-group:focus-within {
    border-radius: 6px;
    box-shadow: var(--input-focus-ring);
}

/* Treat the whole input-group as one focus unit: a single ring on the
   group, every inner border recolored to the focus color, and no inner
   element drawing its own ring. This keeps the focus state consistent
   whether the input or an append/prepend button holds focus.
   !important: beats the .form-control / .input-group>.btn border rules
   above, which are themselves !important. */
.input-group:focus-within .form-control,
.input-group:focus-within .input-group-text,
.input-group:focus-within .input-group-append > .btn,
.input-group:focus-within .input-group-prepend > .btn {
    border-color: var(--input-border-focus) !important;
}

/* !important: beats .form-control:focus's own halo, which is !important. */
.input-group > .form-control:focus,
.input-group > .custom-select:focus,
.input-group:focus-within .input-group-append > .btn:focus,
.input-group:focus-within .input-group-prepend > .btn:focus {
    box-shadow: none !important;
}

/* Bootstrap lifts the focused .form-control to z-index 3, which reorders
   the -1px overlap seams and shifts the visible border by a pixel. Keep
   the stacking order constant so only border colors change on focus. */
.input-group > .form-control:focus {
    z-index: auto;
}

/* Legacy jquery-validate hooks. */
.input-group.has-error {
    border: 1px solid var(--color-red) !important;
    color: var(--color-red);
}

.input-group label.error,
.input-group label.success {
    width: 100%;
    order: 100;
}


/* --- Border utilities on form controls ----------------------------------
   The themed input rules set their own border-color with !important at
   higher specificity, so a bare .border-* never reaches an input; these
   re-apply it at input specificity. Put the class on the control for a
   standalone input, or on the .input-group to color the whole group
   (control + prepend/append). The color lands at the same 0.4 alpha the
   .btn-outline-* borders use, so a colored control sits at the same weight
   as an outline button next to it. An explicit color also holds through
   focus — only the halo changes, which is why the `body[data-*]` prefix
   stays: it puts these above the (0,3,0) focus-within recolor. -------- */

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-primary,
body[data-background-color] .input-group.border-primary > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-primary > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-primary-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-secondary,
body[data-background-color] .input-group.border-secondary > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-secondary > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-secondary-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-success,
body[data-background-color] .input-group.border-success > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-success > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-success-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-danger,
body[data-background-color] .input-group.border-danger > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-danger > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-danger-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-warning,
body[data-background-color] .input-group.border-warning > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-warning > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-warning-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-info,
body[data-background-color] .input-group.border-info > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-info > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-info-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-light,
body[data-background-color] .input-group.border-light > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-light > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-light-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-dark,
body[data-background-color] .input-group.border-dark > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-dark > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: rgba(var(--bs-dark-rgb), 0.4) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-subtle,
body[data-background-color] .input-group.border-subtle > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-subtle > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: var(--border-subtle) !important;
}

body[data-background-color] :is(.form-control, .custom-select, .input-group-text).border-emphasis,
body[data-background-color] .input-group.border-emphasis > :is(.form-control, .custom-select),
body[data-background-color] .input-group.border-emphasis > :is(.input-group-prepend, .input-group-append) > :is(.btn, .input-group-text) {
    border-color: var(--border-emphasis) !important;
}


/* --- Input-group seams --------------------------------------------------
   The group is one control: a single 1px border on the outer edge and a
   single 1px border on each internal seam. The -1px margins overlap the
   prepend/append border with the input's, so two semi-transparent borders
   would composite darker at the seam; drop the prepend/append's
   inward-facing color and let the input's own border draw the seam.

   Every selector below must out-rank both the focus-within recolor and the
   .border-* utilities, so each is restated at those specificities and the
   block is placed last. ------------------------------------------------- */

.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-prepend > .btn,
.input-group:focus-within > .input-group-prepend > .input-group-text,
.input-group:focus-within > .input-group-prepend > .btn,
body[data-background-color] .input-group[class*="border-"] > .input-group-prepend > :is(.btn, .input-group-text) {
    border-right-color: transparent !important;
}

.input-group > .input-group-append > .input-group-text,
.input-group > .input-group-append > .btn,
.input-group:focus-within > .input-group-append > .input-group-text,
.input-group:focus-within > .input-group-append > .btn,
body[data-background-color] .input-group[class*="border-"] > .input-group-append > :is(.btn, .input-group-text) {
    border-left-color: transparent !important;
}


/* --- Validation --------------------------------------------------------- */

/* Bootstrap only reveals feedback under .was-validated / .is-invalid; this
   app renders server-side errors, so the block is always shown. */
.invalid-feedback {
    display: block;
}

.form-group .invalid-feedback {
    font-size: 0.78rem;
    margin-top: 0.35rem;
}

/* Legacy vendor error wrapper, still driven by the theme's main.js. */
.has-error label {
    color: var(--color-red) !important;
}
.has-error .form-control {
    border-color: var(--color-red) !important;
    color: var(--color-red) !important;
}
.has-error .input-group-text {
    border-color: var(--color-red) !important;
    background: var(--color-red) !important;
    color: #ffffff !important;
}


/* --- Field variants ----------------------------------------------------- */

/* !important: beats the size-variant border-radius rules above, which land
   at higher specificity inside an .input-group-sm. */
.input-pill {
    border-radius: 1.3rem !important;
}

/* !important: beats the .form-control / .custom-select base fills, which
   are themselves !important. The dark variant is body-scoped because the
   two fills are literal greys, not tokens — there is no token for them. */
.input-solid {
    background: #e8e8e8 !important;
    border-color: #e8e8e8 !important;
}
body[data-background-color="dark"] .input-solid {
    background: #363b4c !important;
    border-color: #363b4c !important;
}

.form-control-white {
    background-color: #fff !important;
    color: black !important;
}

/* Vendor theme's bordered field wrapper (theme main.js toggles it).
   Body-scoped because that is how it resolves today: the light layer never
   themed it, and un-scoping would newly paint it in light mode. */
body[data-background-color="dark"] .form-group-default {
    background-color: var(--input-bg);
    color: var(--text-primary);
    border-color: var(--input-border);
}


/* --- Floating-label fields (crispy floating_label_field.html) ----------- */

.form-floating-label {
    position: relative;
}

.form-floating-label .placeholder {
    position: absolute;
    transition: all 0.2s;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    padding-left: 4px;
    opacity: 0.8;
    margin-bottom: 0 !important;
    font-size: 14px !important;
    font-weight: 400;
    top: 7px;
}

.form-floating-label .form-control:focus + .placeholder,
.form-floating-label .form-control:valid + .placeholder,
.form-floating-label .form-control.filled + .placeholder {
    font-size: 85% !important;
    transform: translate3d(0, -10px, 0);
    top: 0;
    opacity: 1;
    padding: 0.375rem 0 0.75rem;
    font-weight: 600;
}

.form-floating-label .form-control.filled + .placeholder {
    color: var(--color-blue) !important;
}

.form-floating-label .input-border-bottom + .placeholder {
    padding: 0.375rem 0 0.75rem;
}

.form-floating-label .form-control ::-webkit-input-placeholder {
    color: transparent;
}
.form-floating-label .form-control ::-moz-placeholder {
    color: transparent;
}
.form-floating-label .form-control :-ms-input-placeholder {
    color: transparent;
}


/* --- INERT FIELDS — disabled + readonly --------------------------------
   One rule for every inert field, in both themes. Readonly and disabled
   look identical on purpose: to a reader they're the same thing, a field
   you can't type in.

   The `body` prefix and the position at the end of the file are both
   load-bearing — every declaration here has to out-rank the base
   .form-control / .custom-select rules, which are !important. ---------- */

body .form-control:disabled,
body .form-control[readonly],
body select.form-control:disabled,
body .custom-select:disabled,
body textarea.form-control[readonly] {
    background-color: var(--input-bg-disabled) !important;
    /* Shorthand, not border-color: the vendor theme zeroed these fields'
       border with `border: none`, and a color alone can't restore a
       border whose style is none. */
    border: 1px solid var(--input-border-disabled) !important;
    /* Tertiary, not muted: an inert field's value is still content someone
       has to read, and muted lands under 4.5:1 on the inert fill. The
       backed-off border and fill say "inert" without the text paying. */
    color: var(--text-tertiary) !important;
    /* Flat: the inset sells "type here", which is the wrong invitation. */
    box-shadow: none !important;
    /* No blanket opacity — it fades the border along with the contents,
       and the border is what tells you where the field is. The muted fill
       and text carry "inert" on their own. */
    opacity: 1 !important;
    cursor: not-allowed;
}