/* === Willrich brand color system ===
   Two-ramp brand: Navy (structure, identity) + Teal (action, signal).
   Same brand expressed two ways depending on light/dark theme.

   The semantic tokens below are the only colors views/components should use.
   When the customer rebrands, only the Light/Dark blocks change. */
:root {
  /* Light theme (default) */
  --bg-canvas: #F4F7FA;
  --bg-surface: #FFFFFF;
  --bg-elevated: #ECEEF1;
  --text-primary: #0E2542;
  --text-secondary: #5E6B7A;
  --text-tertiary: #8AA3BF;
  --brand-primary: #0E2542;
  --brand-primary-rgb: 14, 37, 66;
  --brand-action: #0F857C;
  --brand-action-rgb: 15, 133, 124;
  --brand-action-hover: #0A6058;
  --brand-accent: #6FE3D2;
  --brand-accent-rgb: 111, 227, 210;
  --border: #E1E7EE;
  --border-strong: #C4D3E3;

  --status-ok-bg: #E1F5F2;
  --status-ok-fg: #0A6058;
  --status-warn-bg: #FEF3D6;
  --status-warn-fg: #854F0B;
  --status-degraded-bg: #FFE9D6;
  --status-degraded-fg: #993C1D;
  --status-critical-bg: #FCEBEB;
  --status-critical-fg: #A32D2D;
  --status-info-bg: #E6F1FB;
  --status-info-fg: #0C447C;
}

[data-theme="dark"] {
  color-scheme: dark;
  --bg-canvas: #0A1B30;
  --bg-surface: #122847;
  --bg-elevated: #1E3A5F;
  --text-primary: #F1F5FA;
  --text-secondary: #94A3B8;
  --text-tertiary: #5E6B7A;
  --brand-primary: #6FE3D2;
  --brand-primary-rgb: 111, 227, 210;
  --brand-action: #2DD4BF;
  --brand-action-rgb: 45, 212, 191;
  --brand-action-hover: #6FE3D2;
  --brand-accent: #6FE3D2;
  --brand-accent-rgb: 111, 227, 210;
  --border: #1E3A5F;
  --border-strong: #3D5A7A;

  --status-ok-bg: #0A6058;
  --status-ok-fg: #A8E6DD;
  --status-warn-bg: #633806;
  --status-warn-fg: #FAC775;
  --status-degraded-bg: #712B13;
  --status-degraded-fg: #F0997B;
  --status-critical-bg: #791F1F;
  --status-critical-fg: #F09595;
  --status-info-bg: #0C447C;
  --status-info-fg: #B5D4F4;
}

/* Auto dark when the user hasn't picked a theme. data-theme="light" on <html>
   wins over the OS preference; same for data-theme="dark". */
[data-theme="light"] {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg-canvas: #0A1B30;
    --bg-surface: #122847;
    --bg-elevated: #1E3A5F;
    --text-primary: #F1F5FA;
    --text-secondary: #94A3B8;
    --text-tertiary: #5E6B7A;
    --brand-primary: #6FE3D2;
    --brand-primary-rgb: 111, 227, 210;
    --brand-action: #2DD4BF;
    --brand-action-rgb: 45, 212, 191;
    --brand-action-hover: #6FE3D2;
    --border: #1E3A5F;
    --border-strong: #3D5A7A;

    --status-ok-bg: #0A6058;
    --status-ok-fg: #A8E6DD;
    --status-warn-bg: #633806;
    --status-warn-fg: #FAC775;
    --status-degraded-bg: #712B13;
    --status-degraded-fg: #F0997B;
    --status-critical-bg: #791F1F;
    --status-critical-fg: #F09595;
    --status-info-bg: #0C447C;
    --status-info-fg: #B5D4F4;
  }
}

/* === Bootstrap variable bridge ===
   Wire Bootstrap's CSS custom properties to the brand tokens so existing
   utility classes (text-bg-success, alert-warning, etc.) automatically pick
   up the brand palette.

   Several Bootstrap components compose colors via rgba(var(--bs-*-rgb), N) —
   form-floating labels, focus rings, muted text, etc. We must supply the
   matching -rgb triples whenever we override the named color, otherwise
   those rules silently fall back to Bootstrap's light-theme defaults and
   become unreadable in dark mode. */
:root {
  --bs-body-bg: var(--bg-canvas);
  --bs-body-bg-rgb: 244, 247, 250;
  --bs-body-color: var(--text-primary);
  --bs-body-color-rgb: 14, 37, 66;
  --bs-secondary-color: var(--text-secondary);
  --bs-secondary-color-rgb: 94, 107, 122;
  --bs-secondary-bg: var(--bg-elevated);
  --bs-tertiary-bg: var(--bg-elevated);
  --bs-tertiary-color: var(--text-tertiary);
  --bs-border-color: var(--border);
  --bs-border-color-translucent: var(--border);
  --bs-primary: var(--brand-action);
  --bs-primary-rgb: var(--brand-action-rgb);
  --bs-link-color: var(--brand-action);
  --bs-link-color-rgb: var(--brand-action-rgb);
  --bs-link-hover-color: var(--brand-action-hover);
  --bs-emphasis-color: var(--text-primary);
  --bs-heading-color: var(--text-primary);
}

[data-theme="dark"] {
  --bs-body-bg-rgb: 10, 27, 48;
  --bs-body-color-rgb: 241, 245, 250;
  --bs-secondary-color-rgb: 148, 163, 184;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bs-body-bg-rgb: 10, 27, 48;
    --bs-body-color-rgb: 241, 245, 250;
    --bs-secondary-color-rgb: 148, 163, 184;
  }
}

/* Status-tinted Bootstrap utilities. Bootstrap's default text-bg-* uses
   solid saturated colors; the brand system prefers tinted backgrounds with
   bolder foreground text — calmer at scale (lots of badges in tables). */
.text-bg-success { background-color: var(--status-ok-bg) !important; color: var(--status-ok-fg) !important; }
.text-bg-warning { background-color: var(--status-warn-bg) !important; color: var(--status-warn-fg) !important; }
.text-bg-danger  { background-color: var(--status-critical-bg) !important; color: var(--status-critical-fg) !important; }
.text-bg-info    { background-color: var(--status-info-bg) !important; color: var(--status-info-fg) !important; }
.text-bg-primary { background-color: var(--brand-action) !important; color: #fff !important; }
.text-bg-secondary { background-color: var(--bg-elevated) !important; color: var(--text-secondary) !important; }
.text-bg-dark    { background-color: var(--brand-primary) !important; color: var(--bg-surface) !important; }

.alert-success { --bs-alert-bg: var(--status-ok-bg); --bs-alert-color: var(--status-ok-fg); --bs-alert-border-color: var(--status-ok-fg); }
.alert-warning { --bs-alert-bg: var(--status-warn-bg); --bs-alert-color: var(--status-warn-fg); --bs-alert-border-color: var(--status-warn-fg); }
.alert-danger  { --bs-alert-bg: var(--status-critical-bg); --bs-alert-color: var(--status-critical-fg); --bs-alert-border-color: var(--status-critical-fg); }
.alert-info    { --bs-alert-bg: var(--status-info-bg); --bs-alert-color: var(--status-info-fg); --bs-alert-border-color: var(--status-info-fg); }

/* Surfaces: cards, modals, dropdowns, the navbar bar all use --bg-surface so
   dark mode flips them in one go. */
.card,
.dropdown-menu,
.modal-content,
.offcanvas,
.list-group-item,
.toast {
  --bs-card-bg: var(--bg-surface);
  --bs-dropdown-bg: var(--bg-surface);
  --bs-modal-bg: var(--bg-surface);
  --bs-offcanvas-bg: var(--bg-surface);
  --bs-list-group-bg: var(--bg-surface);
  background-color: var(--bg-surface);
  color: var(--text-primary);
}

.dropdown-item {
  --bs-dropdown-link-color: var(--text-primary);
  --bs-dropdown-link-hover-bg: var(--bg-elevated);
  --bs-dropdown-link-hover-color: var(--text-primary);
  --bs-dropdown-link-active-bg: var(--brand-action);
  --bs-dropdown-link-active-color: #fff;
}

/* The navbar markup uses bg-white directly — bridge it to the surface token
   so dark mode flips the bar too. Same for the explicit text-dark nav links. */
.navbar.bg-white { background-color: var(--bg-surface) !important; }
.navbar .nav-link.text-dark,
.navbar .navbar-brand { color: var(--text-primary) !important; }
.navbar .nav-link.text-dark:hover { color: var(--brand-action) !important; }

/* Bootstrap's navbar-light renders the toggler icon as a dark SVG and the
   border as rgba(0,0,0,.1) — both invisible against the dark surface in
   dark mode. Repaint with the light text token so the hamburger stays
   readable, and strengthen the border for the same reason. */
[data-theme="dark"] .navbar .navbar-toggler {
  border-color: var(--border-strong);
}
[data-theme="dark"] .navbar .navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23F1F5FA' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .navbar .navbar-toggler {
    border-color: var(--border-strong);
  }
  :root:not([data-theme="light"]) .navbar .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23F1F5FA' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
  }
}

/* Form controls: dark-theme inputs need surface bg + readable text.
   The textarea selector is repeated explicitly because some browsers (Safari
   especially) overlay native dark-mode form rendering on top of declared CSS
   when the page hasn't opted in via color-scheme. The combination of
   color-scheme on the theme selectors above plus the higher-specificity
   textarea.form-control rule below makes the surface color stick. */
.form-control, .form-select {
  background-color: var(--bg-surface);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
textarea.form-control {
  background-color: var(--bg-surface);
  color: var(--text-primary);
}
.form-control:focus, .form-select:focus {
  background-color: var(--bg-surface);
  color: var(--text-primary);
  border-color: var(--brand-action);
  box-shadow: 0 0 0 0.2rem rgba(var(--brand-action-rgb), 0.25);
}
.form-control::placeholder { color: var(--text-tertiary); }

/* Tables: header tone + zebra stripes pick up the surface tokens. */
.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--text-primary);
  --bs-table-border-color: var(--border);
  --bs-table-hover-bg: var(--bg-elevated);
  --bs-table-striped-bg: var(--bg-elevated);
}
.table > thead { color: var(--text-secondary); }

/* Brand-action buttons (primary CTAs). */
.btn-primary {
  --bs-btn-bg: var(--brand-action);
  --bs-btn-border-color: var(--brand-action);
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: var(--brand-action-hover);
  --bs-btn-hover-border-color: var(--brand-action-hover);
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--brand-action-hover);
  --bs-btn-active-border-color: var(--brand-action-hover);
  --bs-btn-active-color: #fff;
  --bs-btn-disabled-bg: var(--brand-action);
  --bs-btn-disabled-border-color: var(--brand-action);
}

.btn-outline-primary {
  --bs-btn-color: var(--brand-action);
  --bs-btn-border-color: var(--brand-action);
  --bs-btn-hover-bg: var(--brand-action);
  --bs-btn-hover-border-color: var(--brand-action);
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--brand-action-hover);
  --bs-btn-active-border-color: var(--brand-action-hover);
  --bs-btn-active-color: #fff;
}

.btn-outline-secondary {
  --bs-btn-color: var(--text-secondary);
  --bs-btn-border-color: var(--border-strong);
  --bs-btn-hover-bg: var(--bg-elevated);
  --bs-btn-hover-border-color: var(--border-strong);
  --bs-btn-hover-color: var(--text-primary);
}

.text-muted { color: var(--text-secondary) !important; }
hr { border-top-color: var(--border); }

html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

body > .container {
  flex: 1 0 auto;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--text-tertiary);
  text-align: start;
}

/* Keep the floating label permanently small at the top instead of animating
   from placeholder position. Mirrors Bootstrap's "floated" rule and applies
   it unconditionally. The ::after carve-out gives the label a solid background
   so it sits over the input border cleanly.

   We set color explicitly (instead of relying on Bootstrap's
   rgba(--bs-body-color-rgb, .65) rule) because that variable's RGB triple
   isn't part of our brand bridge — without this the label inherits the
   default dark RGB and is unreadable on the dark canvas. */
.form-floating > label {
  color: var(--text-secondary);
  opacity: 1;
  transform: scale(.85) translateY(-0.5rem) translateX(0.15rem);
}

.form-floating > label::after {
  position: absolute;
  inset: 1rem 0.375rem;
  z-index: -1;
  height: 1.5em;
  content: "";
  background-color: var(--bg-surface);
  border-radius: var(--bs-border-radius);
}

/* With the label always floated, the input's text area must always reserve
   space at the top, otherwise the placeholder/value sits under the label. */
.form-floating > .form-control,
.form-floating > .form-control-plaintext {
  padding-top: 1.625rem;
  padding-bottom: 0.625rem;
}

/* Sticky form action bar: pins Save/Cancel to the viewport bottom on long forms.
   Wrap your buttons in <div class="form-actions-sticky">…</div>. */
.form-actions-sticky {
  position: sticky;
  bottom: 0;
  z-index: 1020;
  background-color: var(--bs-body-bg);
  border-top: 1px solid var(--bs-border-color);
  padding: 0.75rem 0;
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Row-click affordance: any tr[data-href] gets a pointer in JS, but we also
   add a subtle hover lift on hover so the row reads as interactive. */
.table-hover > tbody > tr[data-href]:hover {
  background-color: var(--bs-tertiary-bg);
}

/* Mobile table cards: on small viewports, transform a regular Bootstrap table
   into stacked cards. Apply class="table-stack-sm" to the table and add
   data-label="Header text" to each <td> so cells get a visible label. */
@media (max-width: 575.98px) {
  .table-stack-sm thead {
    display: none;
  }
  .table-stack-sm tbody tr {
    display: block;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    background-color: var(--bs-body-bg);
  }
  .table-stack-sm tbody td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    border: none;
    padding: 0.35rem 0;
    text-align: right;
  }
  .table-stack-sm tbody td::before {
    content: attr(data-label);
    font-weight: 600;
    text-align: left;
    color: var(--bs-secondary-color);
    flex: 0 0 auto;
  }
  .table-stack-sm tbody td:empty,
  .table-stack-sm tbody td:not([data-label]) {
    justify-content: flex-end;
  }
  .table-stack-sm tbody td:not([data-label])::before {
    content: none;
  }
}

/* Live-search loading affordance: subtle dim on the swap target, plus a
   spinner cursor on the form's input while a fetch is in flight. */
form.is-loading input[type="search"],
form.is-loading input[type="text"] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><circle cx='8' cy='8' r='6' fill='none' stroke='%236c757d' stroke-width='2' stroke-dasharray='9.42 9.42' transform='rotate(-90 8 8)'><animateTransform attributeName='transform' type='rotate' from='0 8 8' to='360 8 8' dur='0.8s' repeatCount='indefinite'/></circle></svg>");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  background-size: 1rem 1rem;
  padding-right: 2rem;
}

/* Bulk-actions toolbar: appears above the table when ≥1 row is selected.
   ux.js toggles the .is-active class. */
.bulk-actions-bar {
  display: none;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
  background-color: var(--bs-tertiary-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
}
.bulk-actions-bar.is-active {
  display: flex;
}

/* === Touch-friendly sizing ===
   On coarse-pointer devices (touchscreens) every interactive control should
   meet the 44x44 px minimum so it can be tapped reliably. We don't enforce
   this on mouse devices — denser UIs there are fine. */
@media (pointer: coarse) {
  .btn-sm,
  .pagination-sm .page-link {
    min-height: 44px;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
  }
  .btn:not(.btn-sm):not(.btn-link) {
    min-height: 48px;
  }
  .form-control,
  .form-select {
    min-height: 44px;
  }
  /* Sortable headers: link wraps the label+icon. Pad it out so the whole
     header cell area is tappable. */
  thead th a {
    display: inline-flex;
    padding: 0.25rem 0.5rem;
    margin: -0.25rem -0.5rem;
  }
  /* Row checkboxes get a generous tap area. */
  .form-check-input {
    min-width: 1.25rem;
    min-height: 1.25rem;
  }
}

/* === Mobile bottom action bar ===
   On phones the sticky-bottom action bar inside the document area becomes a
   true viewport-fixed bar so Save/Cancel are always reachable above the
   thumb / above the on-screen keyboard's safe area. The form gets bottom
   padding so its tail content isn't hidden behind the bar. */
@media (max-width: 767.98px) {
  .form-actions-sticky {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    margin-top: 0;
    padding: 0.75rem 1rem;
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0));
    box-shadow: 0 -0.25rem 0.75rem rgba(0, 0, 0, 0.1);
    z-index: 1030;
  }
  form:has(.form-actions-sticky) {
    padding-bottom: 6rem;
  }
}

/* === Mobile accordion forms ===
   ux.js sets [data-mobile-accordion-active] on a form below md. Card bodies
   collapse via aria-expanded on the heading button. Above md the rule is
   inert and the cards render normally. */
[data-mobile-accordion-active] .card-body[data-collapsible-section] h2[role="button"] {
  cursor: pointer;
  position: relative;
  padding-right: 1.75rem;
  user-select: none;
}
[data-mobile-accordion-active] .card-body[data-collapsible-section] h2[role="button"]::after {
  content: "";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  width: 0.6rem;
  height: 0.6rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-75%) rotate(45deg);
  transition: transform 0.15s ease;
}
[data-mobile-accordion-active] .card-body[data-collapsible-section][data-collapsed] h2[role="button"]::after {
  transform: translateY(-25%) rotate(-45deg);
}
[data-mobile-accordion-active] .card-body[data-collapsible-section][data-collapsed] > :not([data-collapsible-header]) {
  display: none;
}

/* asp-validation-summary always renders the wrapper div; hide it when there
   are no errors so the empty alert-danger box doesn't show on first load. */
.alert.validation-summary-valid {
  display: none;
}