/* Fluent-inspired component styles (tokens in fluent-tokens.css) */

body {
    font-family: var(--font-body);
    background-color: var(--color-bg-canvas);
    color: var(--color-text-primary);
    margin: 0;
    padding: 0;
}

/* Cards */
.card {
    --card-padding-x: 16px;
    --card-padding-y: 16px;
    width: 100%;
    background-color: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    box-shadow: none;
    margin-bottom: 1rem;
    color: var(--color-text-primary);
}

.card-header {
    background: transparent;
    color: var(--color-text-primary);
    /* Condensed sets smaller at a given size, so this is a size bump, not a size change. */
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: 13px var(--card-padding-x);
    border-bottom: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 46px;
}

.card-header i {
    font-size: 1.05rem;
    margin-right: 5px;
    color: var(--color-text-muted);
}

/* The display face is for the header's own label. Controls parked in the header
   (filter buttons, counts, a search box) are chrome and stay on the body face —
   they would otherwise inherit the condensed face just by sitting there. */
.card-header :is(.btn, .badge, .table-tag, input, select, textarea, .form-control, .form-select) {
    font-family: var(--font-body);
    letter-spacing: normal;
}

.card-body {
    padding: var(--card-padding-y) var(--card-padding-x);
    color: var(--color-text-primary);
    background-color: transparent;
}

/* Keep form fields, buttons, and grids aligned with the card header edges. */
.card-body > form,
.card-body form {
    width: 100%;
}

.card-body .form-control,
.card-body .form-select,
.card-body textarea.form-control,
.card-body .input-group,
.card-body .d-grid,
.card-body > .alert,
.card-body form > .alert {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

/* Bootstrap row negative margins bleed past card-body padding otherwise. */
.card-body .row {
    --bs-gutter-x: 1rem;
    margin-left: 0;
    margin-right: 0;
}

.card-body .row > [class*="col"] {
    padding-left: calc(var(--bs-gutter-x) * 0.5);
    padding-right: calc(var(--bs-gutter-x) * 0.5);
}

.card-body .row > [class*="col"]:first-child {
    padding-left: 0;
}

.card-body .row > [class*="col"]:last-child {
    padding-right: 0;
}

.card-body .row > [class*="col"]:only-child {
    padding-left: 0;
    padding-right: 0;
}

.card-body dt {
    color: var(--color-text-secondary);
    font-weight: 600;
    font-size: 0.875rem;
}

.card-body dd {
    color: var(--color-text-primary);
}

.card-body .table-responsive,
.card-body .table {
    background-color: transparent;
}

/* ---- Page sections ----
   On an index page the table IS the page, so it is not put in a card. A region is
   announced by a condensed label over a rule and then sits flat on the canvas.
   Elevation is reserved for things that genuinely float above it — modals,
   dropdowns, toasts, the dialer.

   Controls stay boxed and data does not: .search-row and the filter cards are
   objects you operate, the table is the content itself. */
.page-section {
    margin-bottom: 1rem;
}

/* Padded to the table's own cell padding, so the label sits directly over the
   first column and the meta over the last, while the rule spans the full region. */
.page-section-head {
    position: relative;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 16px;
    padding: 0 12px 7px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--color-stroke-strong);
}

/* Signal tick — a short amber segment riding the left end of the rule, marking
   where the region starts. The one piece of brand in an otherwise silent device. */
.page-section-head::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 40px;
    height: 2px;
    background: var(--color-brand);
}

.page-section-label {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin: 0;
    /* 700 and 600 are the only Barlow Condensed weights hosted; the heavier one
       here keeps the region label above the column headers below it. */
    font-family: var(--font-display);
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--color-text-secondary);
}

/* A row count is a machine number, so it takes the data face rather than the label's. */
.page-section-count {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}

.page-section-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

/* Controls parked in the head are chrome and keep the body face — same reason as
   the card header above. */
.page-section-head :is(.btn, .badge, .table-tag, input, select, textarea, .form-control, .form-select, label) {
    font-family: var(--font-body);
    letter-spacing: normal;
}

/* A filled header band would just be the card coming back as a stripe on the
   canvas, so inside a section the column headers are type on a rule. */
.page-section .table thead th {
    background-color: transparent;
}

.page-section .table {
    margin-bottom: 0;
}

/* Tables */
.table {
    color: var(--color-text-primary);
    background-color: transparent;
    font-size: 0.9rem;
    /* Inter's tabular figures — counts, durations and dates stacked down a column
       line up digit-for-digit instead of drifting. */
    font-variant-numeric: tabular-nums;
}

.table thead th {
    background-color: var(--color-bg-subtle);
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-stroke-default);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 10px 12px;
}

.table tbody tr {
    background-color: transparent;
    border-bottom: 1px solid var(--color-stroke-default);
    transition: background-color 0.1s ease;
}

.table tbody tr:hover {
    background-color: var(--color-bg-hover);
}

.table td {
    vertical-align: middle;
    padding: 10px 12px;
    color: var(--color-text-primary);
    background-color: transparent;
}

.table td:last-child {
    white-space: nowrap;
}

/* Right-align the Actions (last) column on every table */
.table thead th:last-child {
    text-align: right;
}
.table tbody td:last-child {
    text-align: right;
}

/* No extra bottom margin on tables inside cards — card-body padding is enough */
.card-body .table,
.card-body .table-responsive .table {
    margin-bottom: 0;
}

.table a:not(.btn) {
    color: var(--color-brand);
    text-decoration: none;
}

.table a:not(.btn):hover {
    text-decoration: underline;
}

.table > :not(caption) > * > * {
    background-color: transparent;
    border-bottom-color: var(--color-stroke-default);
}

.table-responsive {
    background-color: transparent;
}

/* Buttons */
.btn {
    font-weight: 500;
    padding: 8px 15px;
    min-height: 36px;
    border-radius: var(--radius-sm);
    transition: background 0.1s ease, border-color 0.1s ease, box-shadow 0.1s ease;
    font-size: 0.9rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    line-height: 1.2;
}

.btn i,
.btn .bi {
    color: inherit;
    font-size: 1.1rem;
    line-height: 1;
}

.btn-sm {
    padding: 6px 12px;
    min-height: 32px;
    font-size: 0.875rem;
}

.btn-sm i,
.btn-sm .bi {
    font-size: 1.05rem;
}

.btn-lg {
    padding: 10px 20px;
    min-height: 40px;
    font-size: 1rem;
}

.btn-primary {
    --bs-btn-color: var(--btn-primary-fg);
    --bs-btn-bg: var(--btn-primary-bg);
    --bs-btn-border-color: var(--btn-primary-bg);
    --bs-btn-hover-color: var(--btn-primary-fg);
    --bs-btn-hover-bg: var(--btn-primary-hover);
    --bs-btn-hover-border-color: var(--btn-primary-hover);
    --bs-btn-active-color: var(--btn-primary-fg);
    --bs-btn-active-bg: var(--btn-primary-hover);
    --bs-btn-active-border-color: var(--btn-primary-hover);
    --bs-btn-disabled-color: var(--btn-primary-fg);
    --bs-btn-disabled-bg: var(--btn-primary-bg);
    --bs-btn-disabled-border-color: var(--btn-primary-bg);
    --bs-btn-focus-shadow-rgb: var(--btn-focus-shadow-rgb);
    background: var(--btn-primary-bg);
    border: 1px solid var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    box-shadow: var(--shadow-2);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.btn-primary.show,
.btn-check:checked + .btn-primary {
    background: var(--btn-primary-hover);
    border-color: var(--btn-primary-hover);
    color: var(--btn-primary-fg);
    box-shadow: var(--shadow-4);
    transform: none;
}

.btn-success {
    --bs-btn-color: var(--btn-success-fg);
    --bs-btn-bg: var(--btn-success-bg);
    --bs-btn-border-color: var(--btn-success-bg);
    --bs-btn-hover-color: var(--btn-success-fg);
    --bs-btn-hover-bg: var(--btn-success-bg);
    --bs-btn-hover-border-color: var(--btn-success-bg);
    --bs-btn-active-color: var(--btn-success-fg);
    --bs-btn-active-bg: var(--btn-success-bg);
    --bs-btn-active-border-color: var(--btn-success-bg);
    background: var(--btn-success-bg);
    border: 1px solid var(--btn-success-bg);
    color: var(--btn-success-fg);
}

.btn-success:hover,
.btn-success:focus,
.btn-success:active,
.btn-success.active {
    background: var(--btn-success-bg);
    border-color: var(--btn-success-bg);
    color: var(--btn-success-fg);
    filter: brightness(1.1);
    box-shadow: var(--shadow-4);
}

/* Warning — a real variant rather than a relabelled secondary. It marks a consequential but
   reversible action (reset a password, regenerate an activation code, take ownership). Deep gold
   carries white text; the primary CTA is bright amber carrying near-black, so the two never read
   as the same button even when they sit side by side. */
.btn-warning {
    --bs-btn-color: var(--btn-warning-fg);
    --bs-btn-bg: var(--btn-warning-bg);
    --bs-btn-border-color: var(--btn-warning-bg);
    --bs-btn-hover-color: var(--btn-warning-fg);
    --bs-btn-hover-bg: var(--btn-warning-bg);
    --bs-btn-hover-border-color: var(--btn-warning-bg);
    --bs-btn-active-color: var(--btn-warning-fg);
    --bs-btn-active-bg: var(--btn-warning-bg);
    --bs-btn-active-border-color: var(--btn-warning-bg);
    --bs-btn-disabled-color: var(--btn-warning-fg);
    --bs-btn-disabled-bg: var(--btn-warning-bg);
    --bs-btn-disabled-border-color: var(--btn-warning-bg);
    background: var(--btn-warning-bg);
    border: 1px solid var(--btn-warning-bg);
    color: var(--btn-warning-fg);
}

.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active,
.btn-warning.active {
    background: var(--btn-warning-hover);
    border-color: var(--btn-warning-hover);
    color: var(--btn-warning-fg);
    box-shadow: var(--shadow-4);
}

/* Danger — solid destructive, everywhere. It used to be transparent on a page and solid only
   inside a form, so confirm-modal.js's "red accept button" rendered grey (its button is not in a
   form) while the identical class two lines away in a delete form rendered red. The
   .btn-danger-solid / .delete-confirm / .page-header-danger escape hatches that existed for that
   split were never used in any markup and are gone with it.
   Low-emphasis destructive is .btn-outline-danger. Table row actions stay neutral icon buttons
   via the .table rules further down — that is a density treatment applied to every variant, not
   a second meaning for this one. */
.btn-danger {
    --bs-btn-color: var(--btn-danger-fg);
    --bs-btn-bg: var(--btn-danger-bg);
    --bs-btn-border-color: var(--btn-danger-bg);
    --bs-btn-hover-color: var(--btn-danger-fg);
    --bs-btn-hover-bg: var(--btn-danger-bg);
    --bs-btn-hover-border-color: var(--btn-danger-bg);
    --bs-btn-active-color: var(--btn-danger-fg);
    --bs-btn-active-bg: var(--btn-danger-bg);
    --bs-btn-active-border-color: var(--btn-danger-bg);
    --bs-btn-disabled-color: var(--btn-danger-fg);
    --bs-btn-disabled-bg: var(--btn-danger-bg);
    --bs-btn-disabled-border-color: var(--btn-danger-bg);
    background: var(--btn-danger-bg);
    border: 1px solid var(--btn-danger-bg);
    color: var(--btn-danger-fg);
}

.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active,
.btn-danger.active {
    background: var(--btn-danger-bg);
    border-color: var(--btn-danger-bg);
    color: var(--btn-danger-fg);
    filter: brightness(1.08);
    box-shadow: var(--shadow-4);
}

/* Shared delete-confirmation modal body (#deleteModalContent) — previously copy-pasted as an
   inline <style> block on ~20 pages (Details and Index pages with a per-row/per-entity delete
   modal); centralized here since the rules were always identical. */
#deleteModalContent {
    background: var(--card-bg, #1e1f23);
    /* --bs-body-color is never defined by the theme (only referenced), so it fell back to
       Bootstrap's default and the modal title rendered near-invisible on dark. */
    color: var(--color-text-primary);
    border: 1px solid rgba(220, 53, 69, .35);
}
[data-theme="light"] #deleteModalContent {
    background: #fff;
    color: #212529;
}
#deleteModalContent .modal-footer {
    border-top: 1px solid var(--bs-border-color);
}

/* #confirmModalContent is the same surface for the generic confirm (see confirm-modal.js),
   which replaced the browser's native confirm() dialogs. It must share these rules or it
   renders as Bootstrap's default white card in dark mode — with white title text on it,
   so the heading disappears entirely. Border is neutral rather than red: this modal is used
   for reversible actions (resync, regenerate a code) as well as destructive ones, which get
   a red accept button via data-confirm-danger instead. */
#confirmModalContent {
    background: var(--card-bg, #1e1f23);
    /* --bs-body-color is never defined by the theme (only referenced), so it fell back to
       Bootstrap's default and the modal title rendered near-invisible on dark. */
    color: var(--color-text-primary);
    border: 1px solid var(--bs-border-color);
}
[data-theme="light"] #confirmModalContent {
    background: #fff;
    color: #212529;
}
#confirmModalContent .modal-footer {
    border-top: 1px solid var(--bs-border-color);
}

/* Consequences note inside the delete modal. Was an inline
   style="border-left:3px solid var(--bs-danger);padding-left:.75rem;" duplicated on every page
   that carried a copy of the modal. */
.delete-modal-note {
    border-left: 3px solid var(--bs-danger);
    padding-left: .75rem;
    margin-top: .75rem;
}

.btn-secondary {
    --bs-btn-active-bg: var(--color-bg-active);
    --bs-btn-active-border-color: var(--color-stroke-strong);
    --bs-btn-active-color: var(--color-text-primary);
    --bs-btn-focus-shadow-rgb: 97, 97, 97;
    background-color: var(--color-bg-subtle);
    border: 1px solid var(--color-stroke-strong);
    color: var(--color-text-primary);
}

.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active {
    background-color: var(--color-bg-hover);
    border-color: var(--color-stroke-strong);
    color: var(--color-text-primary);
}

.btn-outline-primary {
    color: var(--color-brand);
    border-color: var(--color-stroke-strong);
    background: transparent;
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    background: var(--color-brand-subtle);
    color: var(--color-brand);
    border-color: var(--color-brand);
}

.btn-outline-secondary {
    color: var(--color-text-primary);
    border-color: var(--color-stroke-strong);
    background: var(--color-bg-surface);
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus {
    background: var(--color-bg-hover);
    color: var(--color-text-primary);
    border-color: var(--color-stroke-strong);
}

/* Low-emphasis warning/destructive — same meaning as the solid variants, less weight. Both were
   inheriting Bootstrap's own palette, which hardcodes these two colours rather than reading
   --bs-warning/--bs-danger, so neither followed the theme. Warning was the worse of the pair:
   #ffc107 as label text on a light surface is about 1.9:1. */
.btn-outline-warning {
    color: var(--color-warning);
    border-color: var(--color-warning);
    background: transparent;
}

.btn-outline-warning:hover,
.btn-outline-warning:focus,
.btn-outline-warning:active {
    background: var(--btn-warning-bg);
    border-color: var(--btn-warning-bg);
    color: var(--btn-warning-fg);
}

.btn-outline-danger {
    color: var(--color-danger);
    border-color: var(--color-danger);
    background: transparent;
}

.btn-outline-danger:hover,
.btn-outline-danger:focus,
.btn-outline-danger:active {
    background: var(--btn-danger-bg);
    border-color: var(--btn-danger-bg);
    color: var(--btn-danger-fg);
}

/* Table action button groups — Fluent icon-button sizing */
.table .btn-group {
    display: inline-flex;
    gap: 4px;
    vertical-align: middle;
}

.table .btn-group > .btn {
    border-radius: var(--radius-sm) !important;
    margin-left: 0 !important;
}

.table .btn-group .btn,
.table .btn-group .btn-primary,
.table .btn-group .btn-secondary,
.table .btn-group .btn-warning,
.table .btn-group .btn-danger,
.table .btn-group.btn-group-sm .btn {
    min-width: 34px;
    min-height: 34px;
    width: 34px;
    height: 34px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    color: var(--color-text-secondary);
}

.table .btn-group .btn i,
.table .btn-group .btn .bi,
.table .btn-group.btn-group-sm .btn i {
    font-size: 1rem;
    line-height: 1;
}

.table .btn-group .btn:hover,
.table .btn-group .btn-primary:hover,
.table .btn-group .btn-secondary:hover,
.table .btn-group .btn-warning:hover {
    background-color: var(--color-bg-hover);
    border-color: var(--color-stroke-strong);
    color: var(--color-text-primary);
}

.table .btn-group .btn-danger:hover {
    background-color: var(--color-danger-subtle);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

/* Standalone table action buttons (dashboard widgets, etc.) */
.table td .btn,
.table td a.btn {
    min-height: 34px;
    padding: 0 12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background-color: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    color: var(--color-text-secondary);
}

.table td .btn:has(> i:only-child),
.table td a.btn:has(> i:only-child) {
    min-width: 34px;
    width: 34px;
    height: 34px;
    padding: 0;
}

.table td .btn i,
.table td a.btn i {
    font-size: 1rem;
    line-height: 1;
    color: inherit;
}

.table td .btn:hover,
.table td a.btn:hover,
.table td .btn-primary:hover,
.table td a.btn-primary:hover {
    background-color: var(--color-bg-hover);
    border-color: var(--color-stroke-strong);
    color: var(--color-text-primary);
}

.table td .btn-danger:hover,
.table td a.btn-danger:hover {
    background-color: var(--color-danger-subtle);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

/* General btn-group (filters, toolbars) */
.btn-group .btn {
    min-width: 38px;
    padding-left: 11px;
    padding-right: 11px;
}

.btn-group.btn-group-sm .btn {
    min-width: 36px;
    min-height: 36px;
    padding: 7px 11px;
}

.btn-group .btn i {
    font-size: 1.1rem;
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus {
    background: var(--color-bg-hover);
    color: var(--color-text-primary);
    border-color: var(--color-stroke-strong);
}

/* Segmented filters — neutral until selected */
.btn-group > .btn-outline-secondary,
.btn-group > .btn-outline-primary,
.btn-group > .btn-outline-success,
.btn-group > .btn-outline-warning,
.btn-group > .btn-outline-danger {
    color: var(--color-text-secondary);
    border-color: var(--color-stroke-default);
    background: var(--color-bg-surface);
}

.btn-group > .btn-outline-secondary:hover,
.btn-group > .btn-outline-primary:hover,
.btn-group > .btn-outline-success:hover,
.btn-group > .btn-outline-warning:hover,
.btn-group > .btn-outline-danger:hover {
    background: var(--color-bg-hover);
    color: var(--color-text-primary);
    border-color: var(--color-stroke-strong);
}

.btn-group > .btn.active,
.btn-group > .btn-outline-primary.active,
.btn-group > .btn-outline-secondary.active,
.btn-group > .btn-outline-success.active,
.btn-group > .btn-outline-warning.active,
.btn-group > .btn-outline-danger.active {
    background: var(--btn-primary-bg);
    border-color: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    z-index: 1;
    box-shadow: var(--shadow-2);
}

/* (Table row action styles defined above in btn-group section) */

/* Icon-only buttons */
.btn-icon {
    min-width: 40px;
    min-height: 40px;
    padding-left: 10px;
    padding-right: 10px;
}

/* Forms */
.form-control, .form-select {
    background-color: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-strong);
    color: var(--color-text-primary);
    padding: 7px 11px;
    font-size: 0.9rem;
    min-height: 36px;
    border-radius: var(--radius-sm);
}

.form-control:disabled, .form-control[readonly],
.form-select:disabled {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-stroke-default);
    color: var(--color-text-muted);
    opacity: 1;
}

.form-control:focus, .form-select:focus {
    background-color: var(--color-bg-surface);
    border-color: var(--color-brand);
    color: var(--color-text-primary);
    box-shadow: 0 0 0 1px var(--color-brand);
}

.form-control.is-invalid,
.form-select.is-invalid {
    border-color: var(--danger);
    box-shadow: 0 0 0 1px var(--danger);
}

/* input[type=file]'s "Choose Files" button is a native OS control rendered inside the field —
   it doesn't inherit .form-control's color/background at all, so on the dark theme it stayed a
   plain light-gray system button sitting on an otherwise-dark input. ::file-selector-button is
   the standard hook (Chrome/Edge/Safari); ::-webkit-file-upload-button is the older alias some
   engine versions still need — both target the same button, so keep them in sync. */
.form-control[type="file"]::file-selector-button,
.form-control[type="file"]::-webkit-file-upload-button {
    background-color: var(--color-bg-subtle);
    border: 1px solid var(--color-stroke-strong);
    color: var(--color-text-primary);
    padding: 6px 12px;
    margin-right: 12px;
    font-size: 0.85rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.form-control[type="file"]:hover::file-selector-button,
.form-control[type="file"]:hover::-webkit-file-upload-button {
    background-color: var(--color-brand-subtle);
    border-color: var(--color-brand);
}

.form-label {
    color: var(--color-text-primary);
    font-weight: 600;
    margin-bottom: 5px;
    font-size: 0.8125rem;
}

.form-text {
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

/* Nested form sections (e.g. mobile account on tenant create) */
.form-section {
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-md);
    background-color: var(--color-bg-subtle);
    overflow: hidden;
}

.form-section-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--color-text-primary);
    border-bottom: 1px solid var(--color-stroke-default);
    background-color: transparent;
}

.form-section-header i {
    color: var(--color-text-muted);
}

.form-section-body {
    padding: 16px;
}

.form-section-lead {
    margin: 0 0 1rem;
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

.form-section .form-control,
.form-section .form-select,
.input-group .form-control {
    background-color: var(--color-bg-surface);
    color: var(--color-text-primary);
    border-color: var(--color-stroke-strong);
}

.input-group .btn {
    flex-shrink: 0;
}

.password-input-group .form-control {
    font-family: var(--font-mono);
    letter-spacing: 0.02em;
}

/* Badges — default (outside tables) */
.badge {
    padding: 4px 9px;
    font-weight: 500;
    border-radius: var(--radius-sm);
    font-size: 0.75rem;
}

.badge-success,
.bg-success {
    background-color: var(--btn-success-bg) !important;
    color: #fff !important;
}

/* A fill and its foreground are one pair. About fifteen call sites write `bg-warning text-dark`,
   from when the fill was light enough to carry dark text; .text-dark is declared later in this
   file, so it silently won and left near-black on deep gold at ~3:1. Naming both classes outranks
   it — the badge's foreground comes from the warning pair, not from whatever utility the page
   happened to add. */
.badge-warning,
.bg-warning,
.bg-warning.text-dark {
    background-color: var(--btn-warning-bg) !important;
    color: var(--btn-warning-fg) !important;
}

.badge-danger,
.bg-danger {
    background-color: var(--btn-danger-bg) !important;
    color: #fff !important;
}

.badge-info,
.bg-info,
.badge-primary,
.bg-primary {
    background-color: var(--color-brand-subtle) !important;
    color: var(--color-brand) !important;
    border: 1px solid var(--color-stroke-default);
}

.bg-secondary {
    background-color: var(--color-bg-hover) !important;
    color: var(--color-text-secondary) !important;
}

/* ---- Table cell metrics, tags & icons (Fluent grid style) ---- */
.table-metric {
    display: inline-block;
    min-width: 2.25rem;
    font-size: 1rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
    text-align: center;
    line-height: 1.4;
}

.table-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 28px;
    padding: 4px 10px;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.2;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-stroke-default);
    background: var(--color-bg-subtle);
    color: var(--color-text-primary);
    white-space: nowrap;
}

.table-tag i {
    font-size: 1rem;
    line-height: 1;
}

.table-tag-success {
    background: var(--btn-success-bg);
    border-color: var(--btn-success-bg);
    color: #fff;
}

.table-tag-success i {
    color: #fff;
}

.table-tag-danger {
    background: var(--btn-danger-bg);
    border-color: var(--btn-danger-bg);
    color: #fff;
}

.table-tag-danger i {
    color: #fff;
}

.table-tag-muted {
    background: var(--color-bg-hover);
    border-color: var(--color-stroke-default);
    color: var(--color-text-secondary);
}

.table-tag-warning {
    background: var(--btn-warning-bg);
    border-color: var(--btn-warning-bg);
    color: var(--btn-warning-fg);
}

.table-tag-warning i {
    color: var(--btn-warning-fg);
}

.table-tag-brand {
    background: var(--color-brand-subtle);
    border-color: var(--color-stroke-default);
    color: var(--color-brand);
}

.table .badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 28px;
    padding: 4px 10px;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.2;
    border-radius: var(--radius-md);
    vertical-align: middle;
}

.table .badge i {
    font-size: 1rem;
    line-height: 1;
}

.table .badge-info,
.table .badge.badge-info,
.table .bg-primary,
.table .badge-primary {
    background: var(--color-bg-hover) !important;
    color: var(--color-text-primary) !important;
    border: 1px solid var(--color-stroke-default);
}

.table .badge-success,
.table .bg-success {
    background: var(--btn-success-bg) !important;
    color: #fff !important;
    border: 1px solid var(--btn-success-bg);
}

.table .bg-success i,
.table .badge-success i {
    color: #fff;
}

.table .bg-secondary,
.table .badge-secondary {
    background: var(--color-bg-hover) !important;
    color: var(--color-text-secondary) !important;
    border: 1px solid var(--color-stroke-default);
}

.table .bg-danger,
.table .badge-danger {
    background: var(--btn-danger-bg) !important;
    color: #fff !important;
    border: 1px solid var(--btn-danger-bg);
}

.table .bg-danger i {
    color: #fff;
}

.table td > i.bi,
.table td > .bi-check-circle,
.table td > .bi-exclamation-triangle,
.table td > .bi-x-circle,
.table td > .bi-check-circle-fill,
.table td > .bi-exclamation-triangle-fill {
    font-size: 1.35rem;
    vertical-align: middle;
    line-height: 1;
}

.table td .bi-image-fill,
.table td .bi-image {
    font-size: 1.25rem;
    vertical-align: middle;
}

.table code {
    font-size: 0.9375rem;
    padding: 6px 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
}

.table code.small,
.table code.fs-6 {
    font-size: 0.9375rem !important;
}

.table small {
    font-size: 0.875rem;
}

.table small .bi {
    font-size: 1rem;
    margin-right: 4px;
}

/* Status indicators — superseded by the status rail below, and kept only for the pages
   that still carry a dot. Migrate a page rather than adding another one of these. */
.status-indicator {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 8px;
    vertical-align: middle;
    flex-shrink: 0;
}

.table .status-indicator {
    width: 12px;
    height: 12px;
    margin-right: 10px;
}

.table td:has(.status-indicator) {
    font-size: 0.9375rem;
    font-weight: 500;
}

.status-online { background-color: var(--success); }
.status-offline { background-color: var(--danger); }
.status-pending { background-color: var(--warning); }

/* ---- The status rail ----
   The boom gate turned on its side. Every row standing for something with a live state
   carries a 3px bar on its leading edge, and the bar's *treatment* — not only its colour —
   says what kind of state it is:

       solid    settled, and known        online, offline, closed
       pulse    happening right now       an SOS in progress, a device going quiet
       dashed   not known yet             never activated, never seen, contact lost

   Three treatments rather than three colours, so the row still parses in monochrome, with
   reduced motion on, and for a colour-blind reader — and every railed row names its state
   in words beside the bar (.rail-label) rather than leaving colour to carry meaning alone.
   It is the same amber tick that marks the start of a page section
   (.page-section-head::after) stood upright and repeated down the rows, on the same left
   edge, so a device table can be read for health without reading a word of it.

   This replaces .status-indicator dots and .table-tag-* status pills wherever a row has a
   live state. It is not a general-purpose chip: .table-tag stays for the many places a
   cell states an attribute (a type, a feature flag, a plan) rather than a state.

   Hosts: a <tr>, where the bar rides the leading cell because a row box cannot carry an
   absolutely positioned child reliably under border-collapse — or any other container
   opting in with .rail-row. */
[data-state] {
    --rail-tone: var(--color-stroke-strong);
    --rail-fill: linear-gradient(var(--rail-tone), var(--rail-tone));
    --rail-motion: none;
}

/* Tone — what kind of news this is. */
[data-state="online"],
[data-state="activated"] {
    --rail-tone: var(--color-success);
}

[data-state="offline"],
[data-state="sos-live"] {
    --rail-tone: var(--color-danger);
}

[data-state="degrading"],
[data-state="signal-lost"] {
    --rail-tone: var(--color-warning);
}

[data-state="awaiting-activation"] {
    --rail-tone: var(--color-brand);
}

/* "never-seen" and "closed" keep the neutral tone above: one has not happened yet and the
   other is over, and neither is good news or bad. */

/* Treatment — a pulse for what is live, dashes for what is unknown. */
[data-state="degrading"],
[data-state="sos-live"] {
    --rail-motion: status-rail-pulse 2.2s ease-in-out infinite;
}

[data-state="awaiting-activation"],
[data-state="never-seen"],
[data-state="signal-lost"] {
    --rail-fill: repeating-linear-gradient(to bottom, var(--rail-tone) 0 5px, transparent 5px 9px);
}

tr[data-state] > :first-child,
.rail-row[data-state] {
    position: relative;
}

/* Inset top and bottom so each row's bar is its own mark. Run edge to edge and forty
   online rows fuse into one long stripe, which says something about the table rather
   than about any row in it. */
tr[data-state] > :first-child::before,
.rail-row[data-state]::before {
    content: "";
    position: absolute;
    inset-block: 6px;
    inset-inline-start: 0;
    width: 3px;
    background-image: var(--rail-fill);
    animation: var(--rail-motion);
}

@keyframes status-rail-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.28; }
}

@media (prefers-reduced-motion: reduce) {
    [data-state] {
        --rail-motion: none;
    }
}

/* The word beside the bar. Condensed caps — the signage face the column headers and
   section labels already use — and deliberately uncoloured: the rail carries the state,
   so the label only has to name it, and a name reads better in ink than in green. */
.rail-label {
    font-family: var(--font-display);
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-primary);
}

/* Alerts */
.alert {
    border: 1px solid var(--color-stroke-default);
    border-left-width: 3px;
    background-color: var(--color-bg-surface);
    color: var(--color-text-primary);
    border-radius: var(--radius-md);
    font-size: 0.875rem;
}

.alert-success {
    border-left-color: var(--success);
    background-color: var(--color-bg-surface);
}

.alert-warning {
    border-left-color: var(--warning);
}

.alert-danger {
    border-left-color: var(--danger);
}

.alert-info {
    border-left-color: var(--info);
}

.alert-secondary {
    background-color: var(--color-bg-subtle);
    border-left-color: var(--color-stroke-strong);
    color: var(--color-text-secondary);
}

.alert a:not(.btn),
.alert .alert-link {
    color: var(--color-brand);
    font-weight: 600;
}

/* ---- Dashboard ---- */
.dashboard-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 24px;
    align-items: stretch;
    padding: 22px;
    margin-bottom: 18px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    background: var(--color-bg-surface);
}

.dashboard-hero-main {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
}

.dashboard-eyebrow {
    color: var(--color-text-muted);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-bottom: 6px;
}

.dashboard-hero h2 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 2.15rem;
    font-weight: 700;
    /* Condensed already has tight sidebearings; the -0.03em the system face needed
       closes it up into a smear. */
    letter-spacing: 0;
}

.dashboard-hero p {
    max-width: 640px;
    margin: 6px 0 0;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
}

.dashboard-hero-metrics {
    display: grid;
    grid-template-columns: repeat(3, minmax(120px, 1fr));
    gap: 10px;
    align-items: stretch;
}

.dashboard-hero-metric {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 120px;
    padding: 14px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    color: inherit;
    text-decoration: none;
}

.dashboard-hero-metric:hover {
    background: var(--color-bg-hover);
    color: inherit;
    text-decoration: none;
}

.dashboard-hero-metric span {
    color: var(--color-text-primary);
    font-size: 1.55rem;
    font-weight: 650;
    line-height: 1.1;
}

.dashboard-hero-metric small {
    margin-top: 5px;
    color: var(--color-text-secondary);
    font-size: 0.8rem;
}

.dashboard-hero-good {
    border-left: 3px solid var(--success);
}

.dashboard-hero-warning {
    border-left: 3px solid var(--warning);
}

.dashboard-hero-danger {
    border-left: 3px solid var(--danger);
}

.dashboard-hero-metric-alert span {
    color: var(--danger);
}

.dashboard-metrics-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 18px;
}

.dashboard-metric-card {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "icon value"
        "icon label";
    column-gap: 10px;
    align-items: center;
    min-height: 76px;
    padding: 14px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    background: var(--color-bg-surface);
    color: inherit;
    text-decoration: none;
}

.dashboard-metric-card:hover {
    background: var(--color-bg-hover);
    border-color: var(--color-stroke-strong);
    color: inherit;
    text-decoration: none;
}

.dashboard-metric-card i {
    grid-area: icon;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    color: var(--color-text-secondary);
    font-size: 1rem;
}

.dashboard-metric-value {
    grid-area: value;
    color: var(--color-text-primary);
    font-size: 1.45rem;
    font-weight: 650;
    line-height: 1.1;
}

.dashboard-metric-label {
    grid-area: label;
    color: var(--color-text-secondary);
    font-size: 0.78rem;
    font-weight: 600;
}

.dashboard-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 18px;
    align-items: start;
}

.dashboard-main-column,
.dashboard-side-column {
    min-width: 0;
}

.dashboard-side-column {
    display: grid;
    gap: 16px;
}

.dashboard-card {
    margin-bottom: 16px;
}

.dashboard-card .card-header {
    min-height: 44px;
}

.dashboard-card .card-header > span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.dashboard-alert-card {
    border-left: 3px solid var(--danger);
}

.dashboard-map {
    height: 330px;
    border-radius: 0 0 var(--radius-lg, 8px) var(--radius-lg, 8px);
}

.dashboard-chart-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

.dashboard-device-list {
    display: grid;
    gap: 8px;
}

.dashboard-device-list-compact {
    gap: 6px;
}

.dashboard-device-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 0.8fr) auto;
    gap: 10px;
    align-items: center;
    min-height: 44px;
    padding: 9px 10px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    color: inherit;
    text-decoration: none;
}

.dashboard-device-row:hover {
    background: var(--color-bg-hover);
    color: inherit;
    text-decoration: none;
}

.dashboard-device-name {
    min-width: 0;
    overflow: hidden;
    color: var(--color-text-primary);
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dashboard-device-site,
.dashboard-device-meta {
    min-width: 0;
    overflow: hidden;
    color: var(--color-text-secondary);
    font-size: 0.8rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dashboard-device-meta {
    color: var(--color-text-muted);
    text-align: right;
}

.dashboard-health-value {
    margin-top: 6px;
    color: var(--color-text-primary);
    font-size: 1.75rem;
    font-weight: 650;
    line-height: 1.1;
}

.dashboard-quick-stat {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--color-stroke-default);
}

.dashboard-quick-stat:first-child {
    padding-top: 0;
}

.dashboard-quick-stat:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.dashboard-quick-stat span {
    color: var(--color-text-secondary);
    font-size: 0.85rem;
}

.dashboard-quick-stat strong {
    font-size: 1rem;
}

.dashboard-progress {
    height: 7px;
    margin: -4px 0 4px;
    background: var(--color-bg-hover);
}

.dash-section-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    color: var(--color-text-muted);
    margin: 0 0 10px 2px;
}

/* Constrain chart heights so responsive canvases never balloon */
.chart-wrap {
    position: relative;
    width: 100%;
    height: 240px;
}

.chart-wrap-sm {
    height: 220px;
}

.chart-wrap-gauge {
    height: 150px;
}

/* Empty-state placeholder inside cards */
.empty-state {
    text-align: center;
    padding: 34px 18px;
    color: var(--color-text-muted);
}

.empty-state i {
    font-size: 2.15rem;
    color: var(--color-stroke-strong);
    display: block;
    margin-bottom: 12px;
}

.empty-state p {
    color: var(--color-text-secondary);
    margin-bottom: 4px;
}

/* Stats cards */
.stat-card {
    background-color: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    padding: 16px;
    text-align: left;
    box-shadow: none;
    transition: box-shadow 0.15s ease;
    height: 100%;
}

.stat-card:hover {
    box-shadow: none;
    transform: none;
    border-color: var(--color-stroke-strong);
}

.stat-card-link {
    text-decoration: none;
    display: block;
    color: inherit;
}

.stat-card-link:hover {
    text-decoration: none;
}

/* A stat card that switches to another tab in the same view, rather than navigating away —
   Bootstrap's Reboot already neutralizes most default <button> chrome (font, margin); this
   only needs to fill its grid cell and left-align like the div/link variants do. */
.stat-card-button {
    display: block;
    width: 100%;
    text-align: left;
    cursor: pointer;
}

.stat-card .stat-value {
    font-size: 1.8rem;
    font-weight: 600;
    color: var(--color-text-primary);
    text-shadow: none;
    line-height: 1.2;
}

.stat-card .stat-label {
    color: var(--color-text-secondary);
    font-size: 0.8125rem;
    font-weight: 500;
    margin-top: 5px;
}

.stat-card .stat-label i {
    font-size: 1rem;
}

/* Site details page */
.site-details-page {
    display: grid;
    gap: 1rem;
    width: 100%;
}

.site-details-stats {
    display: grid;
    /* all five tiles on one row — 3+2 wasted a whole row of the details modal */
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 1rem;
    width: 100%;
}

.unit-details-stats,
.company-details-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
    width: 100%;
}

.tenant-details-stats,
.intercom-details-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1rem;
    width: 100%;
}

.site-details-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: stretch;
    width: 100%;
}

.site-details-grid > .card,
.site-details-section {
    margin-bottom: 0;
}

.site-details-grid > .card {
    height: 100%;
}

.site-details-actions .card-body {
    align-content: start;
}

.site-details-actions .btn {
    min-height: 38px;
}

@media (max-width: 768px) {
    .site-details-stats,
    .site-details-grid,
    .unit-details-stats,
    .company-details-stats,
    .tenant-details-stats,
    .intercom-details-stats {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 1200px) {
    .dashboard-metrics-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .dashboard-layout {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 768px) {
    .dashboard-hero {
        grid-template-columns: 1fr;
    }

    .dashboard-hero-metrics,
    .dashboard-chart-grid {
        grid-template-columns: 1fr;
    }

    .dashboard-metrics-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .dashboard-device-row {
        grid-template-columns: auto minmax(0, 1fr);
    }

    .dashboard-device-site,
    .dashboard-device-meta {
        grid-column: 2;
        text-align: left;
    }
}

/* Activation code */
.activation-code {
    background-color: var(--color-bg-subtle);
    border: 1px dashed var(--color-stroke-strong);
    padding: 16px;
    text-align: center;
    border-radius: var(--radius-lg);
    margin: 1rem 0;
}

.activation-code .code {
    font-size: 1.5rem;
    font-weight: 500;
    color: var(--color-text-primary);
    letter-spacing: 0.15em;
    font-family: var(--font-mono);
}

/* Scrollbar */
::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--color-stroke-strong);
    border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-muted);
}

/* Text utilities */
.text-muted {
    color: var(--color-text-muted) !important;
}

small, .small {
    color: var(--color-text-secondary);
}

strong {
    color: var(--color-text-primary);
    font-weight: 600;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--color-text-primary);
    letter-spacing: -0.02em;
}

p {
    color: var(--color-text-primary);
}

a:not(.btn):not(.sidebar-nav-link):not(.sidebar-brand):not(.stat-card-link):not(.btn-back) {
    color: var(--color-brand);
    text-decoration: none;
}

a:not(.btn):not(.sidebar-nav-link):not(.sidebar-brand):not(.stat-card-link):not(.btn-back):hover {
    text-decoration: underline;
}

code {
    background-color: var(--color-bg-subtle);
    color: var(--color-text-primary);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: 0.875em;
    border: 1px solid var(--color-stroke-default);
}

/* Bootstrap overrides */
.bg-white,
.bg-light {
    background-color: var(--color-bg-surface) !important;
}

.bg-dark.text-light,
.list-group-item.bg-dark {
    background-color: var(--color-bg-surface) !important;
    color: var(--color-text-primary) !important;
    border-color: var(--color-stroke-default) !important;
}

.text-dark {
    color: var(--color-text-primary) !important;
}

.border {
    border-color: var(--color-stroke-default) !important;
}

tbody, thead, tfoot, tr, td, th {
    background-color: transparent !important;
}

.table thead th {
    background-color: var(--color-bg-subtle) !important;
}

/* Nav tabs */
.nav-tabs {
    border-bottom-color: var(--color-stroke-default);
}

.nav-tabs .nav-link {
    color: var(--color-text-secondary);
    border-color: transparent;
    font-size: 0.95rem;
    font-weight: 500;
    padding: 0.65rem 1.1rem;
}

.nav-tabs .nav-link:hover {
    color: var(--color-text-primary);
    border-color: transparent;
}

.nav-tabs .nav-link.active {
    color: var(--color-brand);
    background: var(--color-bg-surface);
    border-color: var(--color-stroke-default) var(--color-stroke-default) var(--color-bg-surface);
    font-weight: 600;
}


/* Attachments rendered inside a conversation bubble (helpdesk thread, both the private ticket
   conversation and the public Community one). Small enough that several fit a bubble without
   pushing the text out of view; the anchor around each opens the full-size image. */
.comment-attachments {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-top: .45rem;
}
.comment-attachments img {
    /* flex-basis pinned as well as width: these are flex items, so without flex:0 0 auto a
       bubble with several images shrinks them to different widths depending on how many there
       are — which is why thumbnails came out uneven. object-fit keeps the crop centred. */
    flex: 0 0 auto;
    width: 84px;
    height: 84px;
    object-fit: cover;
    border-radius: 8px;
    /* --bs-border-color was never defined in this app (Bootstrap's own variables aren't all
       present); an invalid var() invalidates the whole border shorthand at computed-value
       time, so this silently rendered borderless. --color-stroke-default is real. */
    border: 1px solid var(--color-stroke-default);
    display: block;
    transition: transform .12s ease;
}
.comment-attachments a:hover img {
    transform: scale(1.04);
}

/* Non-image attachment shown inline in a bubble — a chip you can click to download, since a
   PDF or spreadsheet has no useful thumbnail. */
.comment-attachment-file {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .35rem .6rem;
    border-radius: 8px;
    border: 1px solid var(--color-stroke-default);
    background: var(--color-brand-subtle);
    font-size: .82rem;
    text-decoration: none;
    max-width: 100%;
}
.comment-attachment-file span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.comment-attachment-file:hover {
    background: rgba(var(--bs-primary-rgb), .16);
}


/* Attachments chosen in a reply composer but not yet sent — thumbnails rather than a bare
   "4 files selected" line, which told you how many you'd picked but not what, and gave you no
   way to drop one after a misclick. Same affordance as WhatsApp's tray and the mobile app's
   own composer. Every chip is the same square whatever the source aspect ratio, so a
   selection reads as a tidy row. */
.attachment-tray {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-bottom: .5rem;
}

.attachment-tray[hidden] {
    display: none;
}

.attachment-chip {
    position: relative;
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--color-stroke-default);
    background: var(--color-bg-subtle);
}

.attachment-chip img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Non-images have no useful preview — show the type instead, in the same square so the row
   stays even. */
.attachment-chip-file {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    gap: .1rem;
    color: var(--color-text-secondary);
    font-size: .58rem;
    text-transform: uppercase;
    overflow: hidden;
}

.attachment-chip-file i {
    font-size: 1.1rem;
}

.attachment-chip-remove {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 18px;
    height: 18px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, .65);
    color: #fff;
    font-size: .75rem;
    line-height: 1;
    cursor: pointer;
}

.attachment-chip-remove:hover {
    background: rgba(0, 0, 0, .85);
}

.attachment-tray-clear {
    background: none;
    border: none;
    padding: .2rem .35rem;
    font-size: .78rem;
    color: var(--color-text-muted);
    cursor: pointer;
    text-decoration: underline;
}

.attachment-tray-clear:hover {
    color: var(--color-text-primary);
}


/* ============================================================
   The workflow designer (Pages/AccessPoints/ConfigureWorkflow)
   ============================================================

   Two lanes — entry and exit — each an ordered procedure a guard works through at the gate.

   The signature is the spine: the status rail stood upright and run *through* the rows instead
   of beside them. Elsewhere in this portal a railed row is its own mark, deliberately inset top
   and bottom so forty rows never fuse into one stripe — because there the bar reports the state
   of one device. Here fusing is the whole point. The steps are one procedure, so the line is
   continuous, the nodes are numbered in the data face, and a step switched off breaks the line
   into the same dashes the rail uses for "not known yet" — a gap in the run, which is exactly
   what it is.

   Tone follows direction rather than health: green in, red out, matching the badge on each lane
   and the granted/denied pair used everywhere else. Amber stays where it always is — selection,
   focus, and the one control that changes something. */

.wf {
    --wf-node: 34px;
    --wf-gutter: 46px;
    --flow-tone: var(--color-stroke-strong);
}

/* ---- Lane bar ---- */
.wf-lanebar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 22px;
}

.wf-lane {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 208px;
    padding: 11px 18px 11px 16px;
    text-align: left;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.wf-lane-entry { --lane-tone: var(--color-success); }
.wf-lane-exit { --lane-tone: var(--color-danger); }

/* The rail names the direction, not the selection — it is the same green/red the flow badge and
   its spine carry, so a glance at the bar says which lane is which before any word is read. */
.wf-lane-rail {
    position: absolute;
    inset-block: 9px;
    inset-inline-start: 0;
    width: 3px;
    border-radius: 0 2px 2px 0;
    background: var(--lane-tone);
}

.wf-lane:hover {
    border-color: var(--color-stroke-strong);
    color: var(--color-text-primary);
}

.wf-lane.is-open {
    background: var(--color-brand-subtle);
    border-color: var(--color-brand);
    color: var(--color-text-primary);
}

.wf-lane-glyph {
    font-size: 1.25rem;
    color: var(--lane-tone);
}

.wf-lane-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.wf-lane-title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: inherit;
}

.wf-lane-count {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}

.wf-lanebar-note {
    flex: 1 1 280px;
    align-self: center;
    max-width: 58ch;
    margin: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--color-text-muted);
}

.wf-lanebar-note i {
    margin-right: 4px;
}

/* ---- Panel head ---- */
.wf-panel-entry { --flow-tone: var(--color-success); }
.wf-panel-exit { --flow-tone: var(--color-danger); }

/* ---- Details-page flow counts ---- */
.flow-count {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    margin-right: 6px;
    border-radius: 999px;
    font-family: var(--font-mono, "IBM Plex Mono", monospace);
    font-size: .78rem;
    letter-spacing: .02em;
}
.flow-count-entry { color: var(--color-success); background: color-mix(in srgb, var(--color-success) 12%, transparent); }
.flow-count-exit  { color: var(--color-danger);  background: color-mix(in srgb, var(--color-danger) 12%, transparent); }

/* A measure, not the window: a step card run edge to edge on a wide monitor puts its remove
   button a screen away from the name it removes. */
.wf-panel {
    max-width: 1040px;
}

.wf-panel-head {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 6px 32px;
    align-items: start;
    padding: 0 0 16px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--color-stroke-strong);
}

/* The same signal tick that opens every page section, so the designer reads as one more region
   of the portal rather than as a screen with its own rules. */
.wf-panel-head::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 40px;
    height: 2px;
    background: var(--color-brand);
}

.wf-panel-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
}

.wf-panel-title h2 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.65rem;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--color-text-primary);
}

.wf-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 11px;
    border: 1px solid var(--flow-tone);
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--flow-tone);
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

.wf-badge i {
    font-size: 0.95rem;
}

.wf-panel-blurb {
    grid-column: 1;
    max-width: 68ch;
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.55;
    color: var(--color-text-secondary);
}

.wf-stats {
    grid-column: 2;
    grid-row: 1 / span 2;
    display: flex;
    gap: 26px;
    margin: 0;
}

.wf-stat dt {
    font-family: var(--font-display);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.wf-stat dd {
    margin: 2px 0 0;
    font-family: var(--font-mono);
    font-size: 1.5rem;
    font-weight: 500;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
}

/* ---- The spine ---- */
.wf-spine {
    margin: 0;
    padding: 0;
    list-style: none;
}

.wf-step,
.wf-blank,
.wf-terminal {
    position: relative;
    display: grid;
    grid-template-columns: var(--wf-gutter) minmax(0, 1fr);
    align-items: start;
    padding-bottom: 12px;
}

/* One continuous line rather than a mark per row: consecutive steps butt against each other, so
   the run reads as a single procedure. */
.wf-step::before,
.wf-blank::before,
.wf-terminal::before {
    content: "";
    position: absolute;
    left: calc(var(--wf-node) / 2);
    top: 0;
    bottom: 0;
    width: 2px;
    transform: translateX(-1px);
    background-image: linear-gradient(var(--flow-tone), var(--flow-tone));
    opacity: 0.4;
}

.wf-step:first-child::before,
.wf-blank::before {
    top: calc(9px + var(--wf-node) / 2);
}

.wf-terminal {
    padding-bottom: 0;
}

.wf-terminal::before {
    bottom: calc(100% - 9px - var(--wf-node) / 2);
}

/* A step the guard never sees is a gap in the run, drawn with the rail own not-in-play
   treatment rather than merely greyed. */
.wf-step[data-enabled="false"] {
    --flow-tone: var(--color-stroke-strong);
}

.wf-step[data-enabled="false"]::before {
    background-image: repeating-linear-gradient(to bottom, var(--flow-tone) 0 5px, transparent 5px 9px);
    opacity: 1;
}

.wf-node {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--wf-node);
    height: var(--wf-node);
    margin-top: 9px;
    border: 2px solid var(--flow-tone);
    border-radius: 50%;
    background: var(--color-bg-canvas);
    color: var(--color-text-secondary);
    transition: border-color 0.15s ease;
}

.wf-node-num {
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
}

.wf-step[data-enabled="false"] .wf-node {
    border-style: dashed;
}

.wf-step[data-enabled="false"] .wf-node-num {
    color: var(--color-text-muted);
}

/* ---- Step card ---- */
.wf-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.wf-card:hover {
    border-color: var(--color-stroke-strong);
}

.wf-step:focus-within .wf-card {
    border-color: var(--color-brand);
}

.wf-step[data-enabled="false"] .wf-card {
    opacity: 0.66;
}

.wf-card-head {
    display: grid;
    grid-template-columns: 22px var(--wf-node) minmax(0, 1fr) auto;
    grid-template-areas: "grip icon ident tools";
    align-items: center;
    gap: 10px;
    padding: 11px 13px;
}

.wf-grip {
    grid-area: grip;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    font-size: 1.15rem;
    line-height: 1;
    opacity: 0.4;
    cursor: grab;
    transition: opacity 0.15s ease;
}

.wf-card:hover .wf-grip {
    opacity: 1;
}

.wf-grip:active {
    cursor: grabbing;
}

.wf-card-icon {
    grid-area: icon;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--wf-node);
    height: var(--wf-node);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-stroke-default);
    color: var(--color-text-secondary);
    font-size: 1.05rem;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.wf-card:hover .wf-card-icon {
    background: var(--color-brand-subtle);
    border-color: var(--color-brand);
    color: var(--color-brand);
}

.wf-card-ident {
    grid-area: ident;
    display: block;
    min-width: 0;
}

/* The label is content, not a form field — it sits as plain type until you reach for it, which
   is what stops five stacked steps from reading as a settings table. */
.wf-name {
    width: 100%;
    padding: 3px 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-primary);
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

.wf-name:hover {
    border-color: var(--color-stroke-default);
    background: var(--color-bg-subtle);
}

.wf-name:focus {
    outline: none;
    background: var(--color-bg-surface);
    border-color: var(--color-brand);
    box-shadow: 0 0 0 1px var(--color-brand);
}

/* The global code chip is a background and a border, which at block width becomes a bar under
   every step. Here the wire value is a caption, so it keeps only the face. */
.wf-code {
    display: block;
    padding: 0 0 0 9px;
    border: 0;
    background: transparent;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    color: var(--color-text-muted);
}

.wf-card-tools {
    grid-area: tools;
    display: flex;
    align-items: center;
    gap: 2px;
}

.wf-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    font-size: 0.95rem;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.wf-tool:hover:not(:disabled) {
    background: var(--color-bg-hover);
    border-color: var(--color-stroke-default);
    color: var(--color-text-primary);
}

.wf-tool:disabled {
    opacity: 0.28;
    cursor: default;
}

.wf-tool-drop:hover:not(:disabled) {
    background: var(--color-danger-subtle);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

.wf-card-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 26px;
    padding: 8px 13px 8px 79px;
    border-top: 1px solid var(--color-stroke-default);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--color-bg-subtle);
}

.wf-switch {
    min-height: 0;
    margin-bottom: 0;
}

/* Two switches on every card is ten amber pills down a five-step flow, which out-shouts both
   the spine and the one amber button that actually saves. Same control, dialled down. */
.wf-switch .form-check-input {
    width: 1.75em;
    height: 0.95em;
    margin-top: 0.22em;
}

.wf-switch .form-check-label {
    font-size: 0.8125rem;
    color: var(--color-text-secondary);
    cursor: pointer;
}

.wf-switch .form-check-input:disabled + .form-check-label {
    color: var(--color-text-muted);
    cursor: default;
}

/* ---- Dragging ---- */
.wf-step.is-dragging {
    opacity: 0.55;
}

.wf-step.is-dragging .wf-card {
    border-color: var(--color-brand);
    box-shadow: var(--shadow-8);
}

@keyframes wf-step-arrive {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: none; }
}

.wf-step.is-new {
    animation: wf-step-arrive 0.26s ease;
}

/* ---- Empty lane ---- */
.wf-blank::before {
    background-image: repeating-linear-gradient(to bottom, var(--color-stroke-strong) 0 5px, transparent 5px 9px);
    opacity: 1;
}

.wf-node-blank {
    border-style: dashed;
    border-color: var(--color-stroke-strong);
}

.wf-blank-card {
    padding: 26px 22px;
    border: 1px dashed var(--color-stroke-strong);
    border-radius: var(--radius-lg);
}

.wf-blank-title {
    margin: 0 0 5px;
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--color-text-primary);
}

.wf-blank-body {
    max-width: 52ch;
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--color-text-muted);
}

/* ---- The fixed final step ---- */
.wf-node-terminal {
    border-style: dashed;
    border-color: var(--color-stroke-strong);
    color: var(--color-text-muted);
    font-size: 0.95rem;
}

.wf-terminal-card {
    padding: 13px 16px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-lg);
    background: var(--color-bg-subtle);
}

.wf-terminal-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    color: var(--color-text-primary);
}

.wf-fixed {
    padding: 2px 8px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-sm);
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
    font-family: var(--font-display);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.wf-terminal-body {
    max-width: 62ch;
    margin: 5px 0 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--color-text-muted);
}

.wf-terminal-options {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 11px 0 0;
    padding: 0;
    list-style: none;
}

.wf-terminal-options li {
    padding: 3px 9px;
    border: 1px solid var(--color-stroke-default);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface);
    color: var(--color-text-secondary);
    font-family: var(--font-mono);
    font-size: 0.72rem;
}

/* ---- Step palette ---- */
.wf-palette {
    margin-top: 24px;
    padding-left: var(--wf-gutter);
}

.wf-palette-label {
    margin: 0 0 11px;
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.wf-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Dashed until you reach for it: the outline says a step could go here, and solidifies into the
   real thing on hover. */
.wf-chip {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 6px 12px 6px 7px;
    border: 1px dashed var(--color-stroke-strong);
    border-radius: var(--radius-lg);
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.wf-chip:hover {
    border-style: solid;
    border-color: var(--color-brand);
    background: var(--color-brand-subtle);
    color: var(--color-text-primary);
}

.wf-chip-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-sm);
    background: var(--color-bg-subtle);
    font-size: 0.95rem;
    transition: background 0.15s ease, color 0.15s ease;
}

.wf-chip:hover .wf-chip-icon {
    background: var(--color-bg-surface);
    color: var(--color-brand);
}

.wf-chip-add {
    font-size: 0.75rem;
    opacity: 0.45;
}

.wf-chip:hover .wf-chip-add {
    opacity: 1;
    color: var(--color-brand);
}

.wf-palette-done {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

/* ---- Unsaved marker ----
   A browser leave-confirmation would strand the page: page-transitions.js fades .fade-region the
   moment a link is clicked and has nothing to un-fade it if the navigation is then cancelled. So
   the warning is a mark next to Save instead of a dialog that can leave a blank screen behind. */
.wf-dirty {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding-right: 4px;
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-brand);
}

.wf-dirty::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-brand);
    animation: status-rail-pulse 2.2s ease-in-out infinite;
}

.wf-dirty[hidden] {
    display: none;
}

@media (max-width: 900px) {
    .wf-panel-head {
        grid-template-columns: minmax(0, 1fr);
    }

    .wf-stats {
        grid-column: 1;
        grid-row: auto;
        margin-top: 6px;
    }
}

/* Below this the gutter is the difference between a card and a readable card, and HTML5 drag
   does not exist on a touchscreen anyway — so the grip goes and the buttons carry reordering. */
@media (max-width: 640px) {
    .wf {
        --wf-node: 26px;
        --wf-gutter: 34px;
    }

    .wf-card-head {
        grid-template-columns: var(--wf-node) minmax(0, 1fr);
        grid-template-areas:
            "icon ident"
            "tools tools";
        row-gap: 4px;
    }

    .wf-card-tools {
        justify-self: start;
    }

    .wf-card-foot {
        padding-left: 13px;
    }

    .wf-node-num {
        font-size: 0.6875rem;
    }

    .wf-palette {
        padding-left: 0;
    }

    .wf-panel-title h2 {
        font-size: 1.35rem;
    }
}

@media (hover: none) {
    .wf-grip {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .wf-step.is-new {
        animation: none;
    }

    .wf-dirty::before {
        animation: none;
    }

    .wf-card,
    .wf-card-icon,
    .wf-chip,
    .wf-chip-icon,
    .wf-tool,
    .wf-lane,
    .wf-grip,
    .wf-node {
        transition: none;
    }
}

/* Last in the block on purpose: several parts of the designer are shown and hidden by the
   [hidden] attribute, and a display rule above would otherwise beat the UA display:none. */
.wf [hidden] {
    display: none;
}
