/* Intentional product-level overrides on top of the UniFi-style UI Kit. */

/* Product typography: the kit's Inter stack (kit token, webfonts bundled). */
:root {
    --bs-body-font-family: var(--uf-font);
}
body {
    font-family: var(--uf-font);
    font-optical-sizing: auto;
    font-variation-settings: "GRAD" 0;
}

/* Authentication surface. */
.authentication-bg {
    background-color: var(--uf-auth-bg);
    background-image: linear-gradient(135deg, var(--uf-auth-bg) 0%, var(--uf-bg-subtle) 100%);
}
.authentication-bg .card {
    border: 0;
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.06);
}

#workos-google-login-form {
    width: 100%;
}

/*
 * Google Identity control rendered with the portal's outline button
 * (btn btn-outline-secondary) so it shares the theme's typography, sizing,
 * radius, and interaction states with every other action on the page. Only
 * the official multi-color "G" mark keeps Google's brand colors; its sizing
 * and label spacing live here.
 */
.google-g {
    display: inline-flex;
    width: 1.125rem;
    height: 1.125rem;
    margin-right: 0.625rem;
}

.google-g svg {
    width: 100%;
    height: 100%;
    display: block;
}

.chart-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    flex: 0 0 2.5rem;
    border-radius: 0.75rem;
    font-size: 1.25rem;
}

.vmm-list-card__identity {
    min-width: 0;
}

/* Five compact-row concepts. The kit's stock list-group, card-body, badge,
   button, border, background, spacing, and typography utilities provide the
   shared visual language; only the layouts without kit equivalents live here. */
.device-list > .list-group-item {
    min-height: 5.5rem;
    /* List rows are standalone cards (they carry shadow-sm + rounded-3), so
       they need the card surface. `.list-group-item` defaults to
       `--bs-list-group-bg` (= `--bs-bg-body` = `--uf-bg`), which makes the
       rows read as one flat block against the page and drops the elevation
       the shadow implies. Use the same surface as `.card` so the group cards
       match the processing-overview and worker-status cards. `--bs-card-bg`
       is declared on `.card` itself, so the underlying token is used here. */
    background-color: var(--uf-surface);
}

/* Spaced-card lists (dashboard/groups `list-group gap-3`): Bootstrap zeroes
   the top border of every item after the first to merge flush list rows
   (`.list-group-item + .list-group-item { border-top-width: 0 }`). With
   `gap-3` the items are standalone cards, so each one needs all four
   borders — without this the 2nd+ card (e.g. dashboard "Test") loses its
   top edge. */
.device-list > .list-group-item + .list-group-item {
    border-top-width: var(--bs-list-group-border-width);
}

.list-metric-layout {
    display: grid;
    grid-template-columns: minmax(13rem, 1fr) auto auto;
    align-items: stretch;
}

.list-metric-identity {
    align-self: center;
    min-width: 0;
}

/* Group rows (dashboard + groups list): size to content instead of the
   generic 5.5rem device-list min-height, and inset the identity tile to the
   same 18px gutter the stat cards use so the icons line up. */
.group-list > .list-group-item {
    min-height: 0;
}

.group-list .list-metric-identity {
    padding-left: 1.125rem;
}

.list-metric-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(6rem, 1fr));
}

.list-metric-strip > div {
    display: flex;
    flex-direction: column-reverse;
    justify-content: center;
    min-width: 6rem;
    padding: 0.85rem 1rem;
    text-align: center;
}

.list-metric-strip dt {
    color: var(--uf-text-2);
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.list-metric-strip dd {
    margin: 0 0 0.15rem;
    font-size: 1rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.list-metric-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

@media (max-width: 767.98px) {
    .list-metric-layout {
        grid-template-columns: 1fr auto;
    }

    .list-metric-strip {
        grid-column: 1 / -1;
        grid-row: 2;
        border-left: 0 !important;
        border-top: 1px solid var(--uf-border-light);
    }

    .list-metric-actions {
        grid-column: 2;
        grid-row: 1;
    }
}

@media (max-width: 575.98px) {
    .device-list .card-body {
        gap: 0.75rem !important;
    }

    .list-metric-strip {
        grid-template-columns: repeat(3, 1fr);
    }

    .list-metric-strip > div {
        min-width: 0;
        padding: 0.7rem 0.4rem;
    }

    .list-metric-strip dd {
        font-size: 0.875rem;
    }

}

/* List/grid view toggle (groups, dashboard groups, workers).
 *
 * List stays the default: the existing Design 3 metric-strip rows (groups)
 * and the workers table. Grid reuses the same kit pieces (card, soft
 * identity tile, metric strip, dots/badges, btn-default) in a responsive
 * Bootstrap row; the rules below only adapt the strip to a stacked card
 * and keep long names truncated inside grid columns. */
.group-grid-card .list-metric-strip {
    border-top: 1px solid var(--uf-border-light);
}

.group-grid-card .list-metric-strip > div {
    min-width: 0;
    padding: 0.7rem 0.5rem;
}

.group-grid-card .vmm-list-card__identity,
.worker-grid-card .worker-grid-identity {
    min-width: 0;
}

@media (max-width: 575.98px) {
    .group-grid-card .list-metric-strip dd {
        font-size: 0.875rem;
    }
}

/* Worker allocation picker (group detail "Manage workers" modal).
 * Locked rows — the worker belongs to another process group or is
 * reserved by an active attempt — mute only the NAME; the reason tag
 * ("Assigned to <group>" / "Busy") renders at full contrast so the
 * blocker reads at a glance. The narrow leading column hosts the tick
 * boxes.
 */
.worker-picker-col-select {
    width: 2.75rem;
}

.worker-picker-col-select .check {
    margin: 0 auto;
    display: block;
}

.worker-picker-row-locked .worker-picker-name {
    color: var(--bs-fg-2, #707070);
}

#group-workers-error {
    white-space: pre-wrap;
}

/*
 * Group detail filter bars (queue + Results cards). The markup uses the
 * Bootstrap grid (`row g-3`: search `col-12`, Status/Type `col-6` + `col-6`,
 * date/time `col-12` on phones), so the mobile layout comes from the grid
 * alone. These fixed widths apply from md up so both cards keep defined,
 * identical, coherent sizes on tablets/desktops instead of stretching with
 * the grid or depending on the native time-input width.
 */
@media (min-width: 768px) {
    .vpp-f-search {
        width: 18rem;
        max-width: 100%;
    }

    .vpp-f-select {
        width: 11rem;
    }

    /* Date range + start/end time group (date col-6, times col-3 each):
     * one block that sits on the same row as Search/Status/Type. */
    .vpp-f-daterange {
        width: 36rem;
        max-width: 100%;
    }
}

/* Inside the date/time group the time inputs fill their grid column
 * instead of the fixed 7rem used by the older stacked layout. */
.vpp-f-daterange .vpp-filter-time-input {
    width: 100%;
}

/* Range input + its two time inputs stack: the range spans full width,
 * the times share one row below (each flexible, same 7rem basis as the
 * former single-date rows). */
.vpp-filter-range-input {
    width: 100%;
    min-width: 0;
}

.vpp-filter-time-input {
    flex: 0 1 auto;
    width: 7rem;
    min-width: 0;
}

/*
 * Single-row date range + start/end time (used by every filter bar:
 * job Lifecycle, worker history/command/telemetry, group processed,
 * audit, API logs). Date flexes, times keep compact fixed widths so
 * all three stay on ONE line at every breakpoint, phones included.
 * Each field stacks its label above its input.
 */
.vpp-dt-row {
    display: flex;
    gap: 0.5rem;
    flex-wrap: nowrap;
    align-items: flex-start;
}

.vpp-dt-date {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.vpp-dt-time {
    flex: 0 0 6.5rem;
    width: 6.5rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.vpp-dt-row input {
    width: 100%;
    min-width: 0;
}

.vpp-dt-date input {
    text-overflow: ellipsis;
}

@media (max-width: 767.98px) {
    .vpp-dt-time {
        flex-basis: 5.5rem;
        width: 5.5rem;
    }
}

/*
 * Group detail header (process-group top buttons): the shell uses the kit
 * `.uf-page-head`, whose xs breakpoint already stacks `.ms-auto` full-width
 * below the title. The actions container wraps so "Manage access / Manage
 * workers / Edit" never overflow horizontally; on phones the buttons share
 * the row equally (two per row, wrapping) instead of being cut off.
 */
#group-detail-page #group-detail-head {
    flex-wrap: wrap;
    align-items: flex-start;
    /* Subtitle row (Group ID) sits directly under the title:
     * keep only a 4px rhythm gap instead of the kit's 16px. */
    margin-bottom: 4px;
}

#group-detail-page #group-detail-head > div:first-child {
    min-width: 0;
    flex: 1 1 0;
}

#group-detail-page #group-detail-head .group-actions {
    flex-shrink: 0;
}

#group-detail-page #group-detail-head .group-actions .btn {
    white-space: nowrap;
}

@media (max-width: 575.98px) {
    #group-detail-page #group-detail-head .group-actions {
        width: 100%;
        margin-left: 0 !important;
    }
    #group-detail-page #group-detail-head .group-actions .btn {
        flex: 1 1 140px;
        justify-content: center;
    }
}

/* Group ID row: the UUID must break anywhere so it never
 * overflows on narrow phones. */
#group-detail-page #group-id-row {
    min-width: 0;
}

#group-detail-page #group-id-row code {
    min-width: 0;
    overflow-wrap: anywhere;
}

/*
 * Group detail Error column (queue + processed tables): inline code plus a
 * clamped message so the Failed badge always ships with a visible reason.
 * The column keeps a bounded width so long backend messages wrap/clamp
 * instead of stretching the table; the full text stays in the cell's
 * title/aria-label and on the job-detail page.
 */
.vpp-error-cell {
    max-width: 22rem;
    min-width: 10rem;
}

.vpp-error-cell .min-w-0 {
    min-width: 0;
}

.vpp-error-msg {
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/*
 * File-name cells (group queue + processed tables, worker job history,
 * storage file table, job artifacts table): bound the width so
 * long file names (e.g. 100+ char camera exports) truncate with an
 * ellipsis instead of stretching the table and breaking the layout.
 * A common name like AKNV_S07_20260909_090000-090100.mp4 (~35 chars)
 * still fits without truncation on desktop; longer names clamp and the
 * full text stays in the element's title tooltip. The client-reference
 * subline truncates the same way.
 */
.vpp-file-cell {
    max-width: 26rem;
    min-width: 10rem;
}

.vpp-file-link,
.vpp-file-ref {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

.vpp-file-ref {
    display: block;
}

/* Job tags (v3.6): list/table chips clamp at the 20ch storage max so a
 * full label set stays scannable; the full value stays in the chip's
 * title tooltip (rendered by group-detail.js / job-detail.js). */
.vpp-tag {
    display: inline-block;
    max-width: 20ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

@media (max-width: 575.98px) {
    .vpp-file-cell {
        max-width: 12rem;
        min-width: 0;
    }
}

/*
 * Audit log table: fixed layout with defined column widths so narrow
 * columns (timestamp, user, action, resource type) always fit their
 * content on one line while the smaller resource-id truncates and the
 * content (JSON) column takes the remainder. Timestamp/user/ids/action
 * stay on one line with ellipsis; content wraps anywhere instead of
 * stretching.
 */
.audit-table {
    table-layout: fixed;
    width: 100%;
    min-width: 80rem;
}

.audit-col-time { width: 15rem; }
.audit-col-user { width: 14rem; }
.audit-col-action { width: 16rem; }
.audit-col-restype { width: 11rem; }
.audit-col-resid { width: 7rem; }
.audit-col-content { width: auto; }

.audit-table th,
.audit-table td {
    vertical-align: middle;
}

.audit-cell-nowrap {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.audit-cell-nowrap .uf-badge {
    display: inline-block;
    vertical-align: middle;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.audit-cell-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.audit-cell-time {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.audit-cell-time .audit-time-absolute {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.audit-cell-content {
    min-width: 0;
}

.audit-cell-content code {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
    text-overflow: ellipsis;
    overflow-wrap: anywhere;
    word-break: break-word;
    white-space: pre-wrap;
    font-size: 0.75rem;
}

/* Clickable audit rows open the event-details modal. */
.audit-row {
    cursor: pointer;
}

.audit-row:hover {
    background-color: var(--bs-bg-1);
}

.audit-row:focus-visible {
    outline: 2px solid var(--bs-primary-bg);
    outline-offset: -2px;
}

.audit-detail-content {
    max-height: 24rem;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: 0.8rem;
}

/* Worker library intro card (worker-docs): same card surface as the docs
 * .prose boxes above (kit-level), kept here because the selector is
 * page-specific. Without this it renders transparent against var(--uf-bg). */
#worker-library-panel > .border {
    background-color: var(--uf-surface);
}

/*
 * Worker docs headers (library card + protocol toolbar): the intro text
 * grows (flex-basis 18rem) while the button groups keep their natural
 * size, so wide screens keep text-left/buttons-right on one row and narrow
 * screens stack the full-width text above left-aligned buttons. Without the
 * grow, the text shrink-wraps to its content (~27rem) and mid-range widths
 * wrap the buttons onto a second row while leaving the first row's right
 * half empty.
 */
.worker-docs-intro {
    flex: 1 1 18rem;
    min-width: min(100%, 18rem);
}

/* Compact soft toasts (see static/js/toast.js). The header tint comes from
   the kit's .toast-success / .toast-danger / … soft rules in unifi-ui.css;
   here the toast is only made smaller and calmer: narrower than Bootstrap's
   350px default, smaller type, tighter header padding and a soft shadow so
   it sits quietly in the bottom-right corner in both themes. */
.toast-compact {
    width: auto;
    max-width: 20rem;
    font-size: 0.8125rem;
    border-radius: 0.625rem;
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.12);
}
.toast-compact .toast-header {
    padding: 0.45rem 0.7rem;
    font-size: 0.75rem;
    font-weight: 600;
}
.toast-compact .toast-header .fs-lg {
    font-size: 1rem;
}
.toast-compact .toast-body {
    padding: 0.55rem 0.7rem;
}

/* Toast container in the top layer (see static/js/toast.js): the container
   is a manual popover so toasts paint above native <dialog> overlays
   (Dialog/Drawer via showModal) and their ::backdrops, which ignore z-index.
   The UA popover stylesheet centers with inset:0/margin:auto and adds a
   bordered box — reset it so the Bootstrap position utilities (bottom-0 /
   top-0 + end-0) keep pinning the corner, and never show a backdrop.
   WORKAROUND — retire with the toast.js popover promotion once the kit
   top-layers toasts itself; see the comment there. */
#toast-container[popover] {
    margin: 0;
    border: 0;
    background: transparent;
    overflow: visible;
}
/* UA popover styles center with inset:0/margin:auto. Pin the corner
   explicitly for each placement: unlayered author rules beat the layered
   position utilities (.bottom-0/.top-0/.end-0), so every side is set here
   instead of relying on those utilities in the popover case. (Without
   Popover API support toast.js drops the attribute and the utilities apply
   normally.) */
#toast-container[popover].bottom-0 {
    top: auto;
    bottom: 0;
    left: auto;
    right: 0;
}
#toast-container[popover].top-0 {
    top: 0;
    bottom: auto;
    left: auto;
    right: 0;
}
#toast-container::backdrop {
    display: none;
    background: transparent;
}

/*
 * Job detail page head on narrow screens: the title can be a long
 * unbroken stream URL or file path, and streams carry up to seven
 * action buttons — without wrapping, both push the page sideways.
 * The title block may shrink (min-width: 0) and breaks anywhere;
 * the action row wraps between buttons, each keeping icon + label
 * on one line. No-op on wide screens (everything fits one line).
 */
#job-detail-page .uf-page-head > div:first-child {
    min-width: 0;
    /* Zero basis (not content-sized): the file name must never squeeze the
     * action buttons off the row. The title takes whatever is left after
     * the buttons' natural width and clamps to three lines; the buttons
     * stay top-right (tablet/desktop). Phones stack via the query below. */
    flex: 1 1 0;
}
#job-detail-page #job-detail-heading {
    min-width: 0;
    overflow-wrap: anywhere;
    /* Long file names clamp to three lines with an ellipsis instead of
     * pushing the action buttons or stretching the page head; the full
     * name stays in the heading's title tooltip and in the Details row.
     * Doubled ID wins over the kit's `.uf-page-title` display rule, and
     * the legacy box model is required: `line-clamp` alone does not
     * engage in this browser (verified: block/flow-root render all
     * lines, -webkit-box clamps to 3). */
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    line-clamp: 3;
}
/* Details "File" value: keep the full name but break long unbroken
 * strings anywhere so the facts column never overflows. The !important
 * wins over Bootstrap's `.text-break` (which sets break-word with
 * !important and would otherwise keep mid-extension splits). */
#job-meta-file {
    overflow-wrap: anywhere !important;
}
/* Delete/terminate confirmations quote the file name in the modal body:
 * break long unbroken names anywhere so the modal never overflows. */
#job-confirm-message {
    overflow-wrap: anywhere;
}
#job-detail-page .uf-page-head {
    flex-wrap: wrap;
    /* Buttons pin to the top row (first title line), never vertically
     * centered against a multi-line file name. */
    align-items: flex-start;
}
/* Tablet/desktop: never wrap the buttons below the title — the title
 * above shrinks (zero-basis flex) while the actions keep their natural
 * size at the top right. */
@media (min-width: 768px) {
    #job-detail-page .uf-page-head {
        flex-wrap: nowrap;
    }
}
#job-detail-page .uf-page-head .ms-auto {
    flex-wrap: wrap;
    flex-shrink: 0;
}
@media (max-width: 767.98px) {
    #job-detail-page .uf-page-head > div:first-child {
        max-width: 100%;
        flex-basis: 100%;
    }
}
#job-detail-page .uf-page-head .ms-auto .btn {
    white-space: nowrap;
}

/*
 * Tables on narrow phones: cell content (file names, URLs, IDs) must not
 * wrap — wrapped fragments like "det / ect / ion / s.j / so / n" are
 * unreadable. Every data table already lives in a horizontally scrollable
 * `.table-responsive` wrapper, so keep cells on one line and let wide tables
 * scroll instead. No-op on wider screens.
 */
@media (max-width: 575.98px) {
    .table-responsive > .table th,
    .table-responsive > .table td {
        white-space: nowrap;
    }
}

/*
 * Job header action row on phones: the title takes the full row and the
 * actions get their own full row below it, sharing the width equally (like
 * four col-3: star, pin, delete, share) instead of keeping their minimized
 * square look. Extra stream controls wrap onto further equal-width rows.
 * Tablet and up keep the desktop look (buttons top-right, title shrinks).
 */
@media (max-width: 767.98px) {
    #job-detail-page .uf-page-head .ms-auto.job-actions {
        width: 100%;
        margin-left: 0 !important;
    }
    #job-detail-page .uf-page-head .ms-auto.job-actions .btn {
        flex: 1 1 0;
        width: auto;
        max-width: none;
        min-width: fit-content;
        justify-content: center;
    }
}

/* Offline-license status banner (licensed builds): the first in-flow element
   takes up its normal space on arrival, then remains reachable at the
   viewport edge after the user scrolls past it. Signal red with white text
   and action link. The icon rail is fixed-positioned (kit), so while the
   banner is present the rail — and the sticky filter panels hanging off the
   top bar — are offset below it by the measured banner height (set on
   :root by the inline script in base.html; 0 when the banner is absent). */
#license-status-banner {
    --bs-alert-color: #ffffff;
    --bs-alert-bg: #c62828;
    --bs-alert-border-color: #c62828;
    --bs-alert-link-color: #ffffff;
    position: sticky;
    top: 0;
    z-index: 1040;
    background-color: #c62828;
    color: #ffffff;
}

body.has-license-banner .uf-topbar {
    top: var(--license-banner-h, 0px);
}

body.has-license-banner .uf-rail {
    top: calc(var(--uf-topbar-h) + var(--license-banner-h, 0px));
}

body.has-license-banner .uf-panel {
    top: calc(var(--uf-topbar-h) + var(--license-banner-h, 0px) + 16px);
    max-height: calc(100vh - var(--uf-topbar-h) - var(--license-banner-h, 0px) - 32px);
}

#license-status-banner .alert-link,
#license-status-banner .alert-link:hover {
    color: #ffffff;
    text-decoration: underline;
}

/* Offline-license lock shell (licensed builds): locked non-root users get a
   full-page shell — base.html skips the icon rail markup, so the page area
   drops the rail offset here (mirrors the kit's below-desktop-breakpoint
   rule). Navigation survives in the top-bar user menu and the mobile
   drawer; sidebar.js is a no-op without its toggle button. */
body.license-locked .uf-shell {
    margin-left: 0;
}

/*
 * Worker detail fact list: identifiers are shown in full (never truncated
 * with an ellipsis) and wrap anywhere so long UUIDs/URLs stay inside the
 * column on narrow phones. Generous row spacing + relaxed line-height keep
 * the dense mono values readable.
 */
.vpp-id-full,
#worker-hero-job.vpp-chip-wrap {
    overflow-wrap: anywhere;
    word-break: break-word;
}
#worker-hero-job.vpp-chip-wrap {
    max-width: 100%;
    white-space: normal;
    text-align: left;
}
#worker-facts,
#worker-provision {
    row-gap: 0.65rem;
}
#worker-facts > dt,
#worker-facts > dd,
#worker-provision > dt,
#worker-provision > dd {
    margin-bottom: 0;
    line-height: 1.6;
}
#worker-signals-attempt {
    margin-top: 0.15rem;
}

/*
 * Worker detail copy rows: the value wraps (min-width: 0) while the copy
 * button stays a compact inline action next to the first text line.
 * The button itself is the kit's `.btn-icon btn-xs` (24px square, see
 * portal-theme-override.css) so it matches the fact-list line box and
 * does not stand taller than the text; the old custom `.vpp-copy-inline`
 * box (and the earlier `.btn-icon` at a fixed 2.25rem) both read as
 * misaligned against the mono value.
 */
.vpp-copy-row {
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0.5rem;
    min-width: 0;
}
.vpp-copy-row .vpp-copy-text {
    flex: 0 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Group settings use the Application Config subnav within a scrollable
   dialog; the navigation and Save/Cancel footer stay reachable. */
.dialog.group-settings-dialog {
    width: min(1080px, calc(100vw - 2rem));
    max-width: min(1080px, calc(100vw - 2rem));
}
.group-settings-dialog .dialog-body.group-settings-layout {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    padding: 0;
    overflow: hidden;
    min-height: 0;
}
.group-settings-dialog .group-settings-sidebar {
    width: auto;
    min-width: 0;
    padding: 16px;
    border-radius: 0;
    border-right: 1px solid var(--uf-border, var(--bs-border-color));
    overflow-y: auto;
}
.group-settings-content {
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    padding: 24px;
    overscroll-behavior: contain;
}
.group-settings-section + .group-settings-section {
    padding-top: 24px;
    margin-top: 24px;
    border-top: 1px solid var(--uf-border, var(--bs-border-color));
}

/* CodeMirror 5 JSON editors (PortalUtils.enhanceJsonEditor): the library's
   own stylesheets own the token colors — this only bridges box metrics and
   the kit border to the editor frame. */
.CodeMirror {
    height: auto;
    min-width: 0;
    max-width: 100%;
    border: 1px solid var(--bs-border-color, #e5e7eb);
    border-radius: var(--bs-border-radius, 0.5rem);
    font-size: 0.8125rem;
    line-height: 1.5;
}
.CodeMirror-scroll { min-height: 10rem; max-height: 28rem; }
.CodeMirror-focused { border-color: var(--bs-primary, #0d6efd); }
.group-settings-nav .uf-subnav-item { white-space: normal; }
.group-settings-mobile-nav { display: none; }
.group-settings-dialog .uf-choice-row { flex-wrap: wrap; }
.group-settings-dialog .uf-choice { flex: 1 1 150px; min-width: 0; }
@media (max-width: 767.98px) {
    .group-settings-dialog .dialog-body.group-settings-layout {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr);
    }
    .group-settings-dialog .group-settings-sidebar { border-right: 0; padding: 12px 16px; }
    .group-settings-nav { display: none; }
    .group-settings-mobile-nav { display: block; }
    .group-settings-content { padding: 16px; }
}
