/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* PBI 1147 — the tab strip's slot in the app bar, doubling as its spacer. min-width:0 is what lets
   the strip's own horizontal scroller shrink inside the bar instead of pushing the search, theme
   and profile controls off the right edge. */
.appbar-tabs[b-ixllurku4p] {
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    display: flex;
    align-items: center;
    margin-right: 8px;
}

#blazor-error-ui[b-ixllurku4p] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-ixllurku4p] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-5tlck5nvpx],
.components-reconnect-repeated-attempt-visible[b-5tlck5nvpx],
.components-reconnect-failed-visible[b-5tlck5nvpx],
.components-pause-visible[b-5tlck5nvpx],
.components-resume-failed-visible[b-5tlck5nvpx],
.components-rejoining-animation[b-5tlck5nvpx] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-retrying[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-failed[b-5tlck5nvpx],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-5tlck5nvpx] {
    display: block;
}


#components-reconnect-modal[b-5tlck5nvpx] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-5tlck5nvpx 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-5tlck5nvpx 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-5tlck5nvpx 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-5tlck5nvpx]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-5tlck5nvpx 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-5tlck5nvpx {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-5tlck5nvpx {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-5tlck5nvpx {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-5tlck5nvpx] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-5tlck5nvpx] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-5tlck5nvpx] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-5tlck5nvpx] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-5tlck5nvpx] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-5tlck5nvpx] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-5tlck5nvpx] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-5tlck5nvpx 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-5tlck5nvpx] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-5tlck5nvpx {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}

/* PBI 175 — dark treatment. The reconnect dialog is chrome the user only ever sees when something
   has gone wrong, so a white card flashing over a dark app reads as a second failure rather than a
   status message. Ancestor selector works here exactly as the light rules above do: scoped CSS
   appends its [b-*] attribute to the subject, not to the ancestor. */
html[data-theme="dark"] #components-reconnect-modal[b-5tlck5nvpx] {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.6);
}

html[data-theme="dark"] #components-reconnect-modal button[b-5tlck5nvpx] {
    background-color: var(--mud-palette-primary);
    /* The dark palette's primary is a bright cyan, so the label has to go dark to stay legible. */
    color: #0E1B21;
}

html[data-theme="dark"] #components-reconnect-modal button:hover[b-5tlck5nvpx] {
    background-color: var(--mud-palette-primary-darken);
}

html[data-theme="dark"] .components-rejoining-animation div[b-5tlck5nvpx] {
    border-color: var(--mud-palette-primary);
}
/* /Components/Layout/TabStrip.razor.rz.scp.css */
/* PBI 1147 — the strip is hosted inside the 64px MudAppBar rather than being its own row
   under it, so it has no background or bottom rule of its own. The tabs are folder tabs that
   stand on the bar's bottom edge (rounded on top only), and the active one is underlined edge to
   edge along that edge. The overflow and Undo controls stay centred in the bar. */
.tab-strip[b-kzdcn4h33f] {
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
    height: 100%;
    user-select: none;
}

.tab-strip-scroller[b-kzdcn4h33f] {
    display: flex;
    flex: 1 1 auto;
    align-self: stretch;
    align-items: flex-end;
    gap: 4px;
    min-width: 0;
    padding: 0 4px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
}

.tab-strip-scroller[b-kzdcn4h33f]::-webkit-scrollbar {
    height: 4px;
}

.tab-strip-scroller[b-kzdcn4h33f]::-webkit-scrollbar-thumb {
    background: var(--mud-palette-lines-default);
    border-radius: 2px;
}

.tab-strip-tab[b-kzdcn4h33f] {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    /* Fixed, not shrink-to-fit: TabStrip.razor's TabBodyWidthPx must equal this for drag-to-reorder
       to pick the right drop side. */
    width: 180px;
    /* Two lines (label over breadcrumb) inside the 64px app bar. A later PBI puts name over
       type + ID here, so the second line is load-bearing: do not collapse it to save height. */
    height: 50px;
    padding: 4px 4px 4px 10px;
    border-radius: 8px 8px 0 0;
    border: 1px solid var(--mud-palette-lines-default);
    border-bottom: none;
    cursor: pointer;
    background: var(--mud-palette-background);
    color: var(--mud-palette-text-secondary);
    transition: background-color 100ms ease, color 100ms ease, transform 100ms ease;
    position: relative;
    overflow: hidden;
}

.tab-strip-tab:hover[b-kzdcn4h33f] {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
}

.tab-strip-tab-active[b-kzdcn4h33f] {
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-primary);
}

.tab-strip-tab-active[b-kzdcn4h33f]::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--mud-palette-primary);
}

.tab-strip-tab-icon[b-kzdcn4h33f] {
    flex: 0 0 auto;
    margin-right: 8px;
    color: var(--mud-palette-text-secondary);
}

.tab-strip-tab-active .tab-strip-tab-icon[b-kzdcn4h33f] {
    color: var(--mud-palette-primary);
}

.tab-strip-tab-content[b-kzdcn4h33f] {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    line-height: 1.2;
}

.tab-strip-tab-title[b-kzdcn4h33f] {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tab-strip-tab-active .tab-strip-tab-title[b-kzdcn4h33f] {
    font-weight: 600;
}

.tab-strip-tab-label[b-kzdcn4h33f] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
    min-width: 0;
}

/* A flex row, not a plain text line: the subtitle carries two things with different priorities —
   the sidebar path, which may be truncated, and the (n/8) budget, which may not. Before this the
   whole line ellipsised as one string, so the longest breadcrumbs ate the badge and tabs rendered
   "Direct Lic… › Requests 1/…". */
.tab-strip-tab-subtitle[b-kzdcn4h33f] {
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    margin-top: 2px;
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
}

/* min-width:0 is what actually permits the shrink — a flex item defaults to min-width:auto, which
   refuses to go below its content width and would push the badge out of the tab instead. */
.tab-strip-tab-crumb[b-kzdcn4h33f] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.tab-strip-tab-active .tab-strip-tab-subtitle[b-kzdcn4h33f] {
    color: var(--mud-palette-text-secondary);
}

/* PBI 478 — the panel-tab budget, e.g. "3/8", sitting after a tracker tab's subtitle.
   Deliberately quiet: it is a standing fact the agent can glance at, not a notification. It only
   raises its voice at the cap, which is the one moment it changes what they can do next. */
.tab-strip-tab-budget[b-kzdcn4h33f] {
    /* Never shrinks and never wraps: it is the whole point of the indicator that it stays legible
       at a glance, and a clipped "1/" says nothing. */
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 0 4px;
    border-radius: 6px;
    font-variant-numeric: tabular-nums;
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-disabled);
}

.tab-strip-tab-budget-full[b-kzdcn4h33f] {
    background: var(--mud-palette-warning-lighten);
    /* PBI 1292: the amber's own contrast text. Darkened amber on lightened amber was under 2:1. */
    color: var(--mud-palette-warning-text);
    font-weight: 600;
}

/* PBI 478 (absorbs PBI 828) — reopen-closed-tab control. Matched to .tab-strip-close rather than to
   the overflow button: it is a small inline affordance on the strip, not a second dropdown. */
/* The flex item is this wrapper, not the button — see the note in TabStrip.razor. MudTooltip
   inserts div.mud-tooltip-root between the strip and the button, so sizing the button itself left
   the real flex item at its default flex: 0 1 auto (squeezable) and stretched. */
.tab-strip-reopen-wrap[b-kzdcn4h33f] {
    flex: 0 0 auto;
    align-self: center;
    display: inline-flex;
}

.tab-strip-reopen[b-kzdcn4h33f] {
    margin-left: 6px;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 4px;
    border-radius: 6px;
    color: var(--mud-palette-text-secondary);
    display: inline-flex;
    align-items: center;
}

.tab-strip-reopen:hover[b-kzdcn4h33f] {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
}

.tab-strip-reopen:focus-visible[b-kzdcn4h33f] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
}

.tab-strip-close[b-kzdcn4h33f] {
    flex: 0 0 auto;
    margin-left: 6px;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 3px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--mud-palette-text-secondary);
    opacity: 0;
    transition: opacity 100ms ease, background-color 100ms ease;
}

.tab-strip-tab:hover .tab-strip-close[b-kzdcn4h33f],
.tab-strip-tab-active .tab-strip-close[b-kzdcn4h33f] {
    opacity: 1;
}

.tab-strip-close:hover[b-kzdcn4h33f] {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
}

.tab-strip-dirty-dot[b-kzdcn4h33f] {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--mud-palette-warning);
    box-shadow: 0 0 0 2px var(--mud-palette-background);
}

.tab-strip-tab-active .tab-strip-dirty-dot[b-kzdcn4h33f] {
    box-shadow: 0 0 0 2px var(--mud-palette-surface);
}

.tab-strip-tab-dragging[b-kzdcn4h33f] {
    opacity: 0.5;
}

/* While any tab is being dragged, suppress pointer events on all descendants so dragover always
   fires on the outer .tab-strip-tab — letting OffsetX be measured against the full 180px tab
   body. Child combinator (> *) would miss grandchildren (MudIcon SVG, label spans), and
   exempting .tab-strip-close would route events to its ~24px box and break the left/right-half
   placement at the right edge of every tab. The close button can't usefully accept clicks mid-
   drag anyway, so blanket suppression is correct. */
.tab-strip-drag-in-progress *[b-kzdcn4h33f] {
    pointer-events: none;
}

.tab-strip-drop-indicator[b-kzdcn4h33f] {
    flex: 0 0 auto;
    align-self: stretch;
    width: 2px;
    /* 64px bar - 50px tab: the marker spans the tab's height, not the bar's. */
    margin: 14px 0 0;
    background: var(--mud-palette-primary);
    border-radius: 1px;
    pointer-events: none;
}

/* Bug 245 — "all open tabs" overflow control. The button and click-away overlay render inline in
   this component, so they're styled here (scoped). The dropdown popover is teleported to the page
   root via MudPopoverProvider, so its content is styled globally in wwwroot/app.css
   (.tab-strip-overflow-popover and its children). */
.tab-strip-overflow[b-kzdcn4h33f] {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    padding: 0 0 0 4px;
}

.tab-strip-overflow-btn[b-kzdcn4h33f] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: 36px;
    padding: 0 8px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-background);
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
    transition: background-color 100ms ease, color 100ms ease;
}

.tab-strip-overflow-btn:hover[b-kzdcn4h33f],
.tab-strip-overflow-btn-open[b-kzdcn4h33f] {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
}

.tab-strip-overflow-count[b-kzdcn4h33f] {
    font-size: 0.78rem;
    font-weight: 600;
    min-width: 14px;
    text-align: center;
}

/* Sits just below --mud-palette-popover z-index (--mud-zindex-popover = 1200) and above page
   content, so a click outside the popover closes it. Same idiom as StatusBadgeSelect.razor. */
.tab-strip-overflow-overlay[b-kzdcn4h33f] {
    position: fixed;
    inset: 0;
    z-index: 1199;
}

@media (max-width: 768px) {
    .tab-strip[b-kzdcn4h33f] {
        display: none;
    }
}
/* /Components/Pages/CoverSongLicensing/CoverSongProjectDetail.razor.rz.scp.css */
/* PBI 1209 — the header status pill, enlarged to match the Custom Licensing project page
   (ProjectDetail.razor.css .pd-status-badge). Scoped CSS does not cross pages, so the rule is
   repeated here rather than shared. */
.pd-status-badge[b-uaazqp3j94]  .mud-chip {
    height: 28px;
    font-size: 0.8rem;
    font-weight: 600;
}
/* /Components/Pages/DirectLicensing/ProjectDetail.razor.rz.scp.css */
/* Bug 389 — Project Detail layout.
   Each of the three columns is the sole vertical scroll owner of its own content. Replaces the
   previous model, where the page scrolled AND the Project Notes list had its own
   `max-height: calc(100vh - 220px); overflow-y: auto` box inside it — two scrollbars fighting over
   one wheel gesture.

   The page's height comes from .app-fixed-page (app.css), which makes it the leftover space in a
   flex chain running from <html> down. No 100vh, no chrome arithmetic — see the long note there. */
.pd-root[b-c6nym0br2f] {
    min-height: 0;
}

/* Header bar and signoff strip stay pinned; only the columns below them scroll. ::deep is
   required for .pd-header because it sits on a MudPaper, and Blazor's CSS-isolation attribute is
   never applied to a MudBlazor component's root element. */
.pd-root[b-c6nym0br2f]  .pd-header {
    flex: 0 0 auto;
}

.pd-strip[b-c6nym0br2f] {
    flex: 0 0 auto;
}

/* Three-column body filling the height under the strip; the row itself never scrolls. 24px gap
   reproduces MudGrid's default Spacing="6" gutter, so the columns sit where they always did. */
.pd-body[b-c6nym0br2f] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
    gap: 24px;
}

/* Each column scrolls on its own. overflow-y:auto alone would make the browser compute overflow-x
   to auto as well, producing a phantom horizontal scrollbar whenever content exceeds the column
   width — pin it hidden (same reasoning as .cd-pane and .tw-pane).

   overscroll-behavior / scrollbar-gutter / scrollbar-width come from the shared .app-scroll-pane
   rule in app.css; this class only carries the geometry. */
.pd-col[b-c6nym0br2f] {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    min-width: 0;
}

/* ===== Header: project tallies =====
   Songs / Requests / Fees, promoted out of the foot of the Project Summary card. Same bordered-pill
   treatment as the KPI strip on the Projects tracker so the two read as one idea.

   ::deep on the MudPaper and MudText below, because Blazor's CSS-isolation attribute is never
   applied to a MudBlazor component's root element — a bare `.pd-headerstats` compiles to
   `.pd-headerstats[b-xxx]`, which matches nothing, and the pill silently rendered with no border
   at all. Same trap as .pd-header. Plain markup written in this file (the spans) does get the
   attribute, so .pd-headerstat-label needs no ::deep. */
.pd-root[b-c6nym0br2f]  .pd-headerstats {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    white-space: nowrap;
}

/* Points block: two figures on one line with a progress bar under them. Sized so the whole stats
   pill stays one row tall — the bar sits in the space the line-height already provides rather than
   adding a second row to the header. */
.pd-points[b-c6nym0br2f] {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.pd-points-figures[b-c6nym0br2f] {
    display: flex;
    align-items: baseline;
    gap: 6px;
    white-space: nowrap;
}

.pd-points-sep[b-c6nym0br2f] {
    color: var(--mud-palette-text-disabled);
}

.pd-points-bar[b-c6nym0br2f] {
    height: 3px;
    border-radius: 2px;
    background: var(--mud-palette-lines-default);
    overflow: hidden;
}

/* Primary, not success: the bar is progress toward a target, not a completed state, and success
   green would say "done" on a project that is only part-paid. */
.pd-points-bar-fill[b-c6nym0br2f] {
    height: 100%;
    background: var(--mud-palette-primary);
    border-radius: 2px;
    transition: width 240ms ease;
}

.pd-headerstat-label[b-c6nym0br2f] {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
}

/* Created-date: provenance, nobody acts on it. The quietest thing in the header row. */
.pd-root[b-c6nym0br2f]  .pd-header-meta {
    color: var(--mud-palette-text-disabled);
}

/* ===== Header: the status pill is the primary control =====
   Everything in this row is a Size.Small chip, so hierarchy came down to hue — and an amber
   outlined chip beats a grey filled one. Worse, ProjectStatusHelpers.GetProjectStatusColor only
   maps new/pending/active/closed/cancelled/on-hold, so the real vocabulary ("Screening / Need
   Info" and friends) all fall through to Color.Default. The status pill was reading as the
   quietest thing in its own header.

   Fixed structurally rather than by inventing colour meanings the domain has not agreed: the pill
   is simply bigger and heavier than its neighbours. That holds whatever colour the status resolves
   to, including grey. */
.pd-root[b-c6nym0br2f]  .pd-status-badge .mud-chip {
    height: 28px;
    font-size: 0.8rem;
    font-weight: 600;
}

/* ===== Density: the edit pencils =====
   MudIconButton at Size.Small still carries a ~30px min box, which set the height of every field's
   label row — a caption of ~18px in a 30px shell. Across the ~15 fields on this page that padding
   alone was most of a screenful, and 15 blue pencils competing for attention was most of the
   visual noise.

   Shrink rather than hide. A hover-only edit affordance is invisible on touch and undiscoverable
   without a pointer, so the pencil stays permanently present, just quiet: muted to
   text-secondary (which clears the 3:1 non-text contrast floor — it is the only route to editing,
   so it cannot be decorative) and coloured to primary on hover or keyboard focus.
   ::deep because the button is a MudBlazor component root, which scoped CSS cannot target. */
.pd-root[b-c6nym0br2f]  .pd-fieldcard .mud-icon-button {
    padding: 2px;
    min-width: 0;
    min-height: 0;
    height: auto;
    width: auto;
    color: var(--mud-palette-text-secondary);
}

.pd-root[b-c6nym0br2f]  .pd-fieldcard .mud-icon-button:hover,
.pd-root[b-c6nym0br2f]  .pd-fieldcard .mud-icon-button:focus-visible {
    color: var(--mud-palette-primary);
    background-color: transparent;
}

.pd-root[b-c6nym0br2f]  .pd-fieldcard .mud-icon-button .mud-icon-root {
    font-size: 15px;
}

/* ===== Density: the "Not set" row =====
   One line replacing what used to be up to five full-height empty fields. Reads as a quiet
   footnote, not a list of errors — an unset field is normal, not a problem. */
.pd-notset[b-c6nym0br2f] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    padding-top: 2px;
}

.pd-notset-label[b-c6nym0br2f] {
    font-size: 0.75rem;
    color: var(--mud-palette-text-disabled);
}

.pd-notset-label[b-c6nym0br2f]::after {
    content: ":";
}

/* Dotted underline rather than solid: these are "add a value" affordances, not navigation, and
   should not read as the same thing as the links in the notes feed. */
/* ::deep — these sit on MudLink, a component root, so a bare selector matched nothing and they
   rendered as ordinary blue links, reading like navigation rather than "add a value". */
/* !important on the colour only, and only because MudLink ships `.mud-primary-text`, which is
   `color: ... !important` — no amount of specificity beats it, so the links rendered in link-blue
   while the dotted underline from the same rule applied fine. Color="Color.Inherit" would drop the
   !important but replaces it with `color: inherit !important`, which then blocks the hover colour
   below, so this is the option that leaves both states working. */
.pd-notset[b-c6nym0br2f]  .pd-notset-item {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary) !important;
    border-bottom: 1px dotted var(--mud-palette-lines-default);
    cursor: pointer;
}

.pd-notset[b-c6nym0br2f]  .pd-notset-item:hover {
    color: var(--mud-palette-primary) !important;
    border-bottom-color: var(--mud-palette-primary);
}

.pd-notset[b-c6nym0br2f]  .pd-notset-item-static {
    cursor: default;
    border-bottom-color: transparent;
}

.pd-col-left[b-c6nym0br2f] { flex: 3 1 0; }
.pd-col-center[b-c6nym0br2f] { flex: 6 1 0; }
.pd-col-right[b-c6nym0br2f] { flex: 3 1 0; }

/* Narrow viewports: drop the fixed-height, independent-scroll model and let the page scroll,
   stacking the columns so nothing is crammed into a short fixed box. Matches CustomerDetail's
   breakpoint so the two detail pages behave the same way on a small screen. */
@media (max-width: 960px) {
    .pd-body[b-c6nym0br2f] {
        flex-direction: column;
        overflow: visible;
    }

    .pd-col[b-c6nym0br2f] {
        flex: 0 0 auto;
        overflow: visible;
    }
}
/* /Components/Pages/DirectLicensing/PublisherOwnershipSplits.razor.rz.scp.css */
/* PBI 464 — publisher ownership splits, rendered as a compact text list among the song's composition
   facts. The visual language here is intentionally the opposite of the PUB/MAS request-coverage bars
   sitting in the right-hand column of the same card: no bar, no fill, no side colors — just names and
   aligned figures. That contrast is what keeps an agent from reading ownership as coverage. */

.dl-ownership-splits__rows[b-rwu8c9kpaf] {
    /* Constrained so the name/percentage pairs stay a tidy adjacent column. The parent facts column is
       flex: 1 and can be very wide; without this the percentages would drift far from the publisher
       names and stop scanning as a list. */
    max-width: 320px;

    /* Subtle rule tying the rows together as one group, and setting them in from the "Composed by /
       Published by" lines above so the block reads as a nested detail of the composition. */
    border-left: 2px solid var(--mud-palette-lines-default);
    padding-left: 8px;
}

.dl-ownership-splits__row[b-rwu8c9kpaf] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    line-height: 1.5;
}

.dl-ownership-splits__pct[b-rwu8c9kpaf] {
    /* Tabular figures + fixed width + right alignment: the decimal points line up down the column, so
       66.65 / 33.35 can be eyeballed as summing to 100 without reading digit by digit. */
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    min-width: 62px;
    text-align: right;
    flex: 0 0 auto;
    font-size: 0.75rem;
    color: var(--mud-palette-text-primary);
}

.dl-ownership-splits__total[b-rwu8c9kpaf] {
    /* Only rendered when the splits don't sum to 100%. Separated by a hairline so it reads as a
       conclusion about the rows above rather than another publisher row. */
    margin-top: 2px;
    padding-top: 2px;
    border-top: 1px solid var(--mud-palette-lines-default);
}
/* /Components/Pages/DirectLicensing/RequestTicketView.razor.rz.scp.css */
/* Bug 389 — Request Detail layout.
   Each of the three columns is the sole vertical scroll owner of its own content, and the page
   itself never scrolls. Height comes from .app-fixed-page in app.css, which makes this the leftover
   space in a flex chain running from <html> down — no 100vh, no chrome arithmetic.

   Before this, the shell declared `height: 100%` with an inner `flex: 1; overflow-y: auto` body,
   which was the right shape but inert: nothing above it had a resolved height, so the percentage
   never resolved, the body never scrolled, and the document grew instead. */
.rt-root[b-1ch4m1ctmk] {
    min-height: 0;
}

/* Everything above the columns — banner, signoff strip, action row, missing-fields strip,
   screening-form row — stays pinned. Only the columns below scroll. */
.rt-root[b-1ch4m1ctmk] >  .mud-paper {
    flex: 0 0 auto;
}

/* PBI 1147 — the one two-line header that replaced the identity banner, action row and screening
   strip. Each line is a wrapping flex row: at 1080p both fit on one visual line each, and on a
   narrower screen (or with a long rightsholder / territory string) the overflow wraps down rather
   than being clipped, so nothing is ever hidden to keep the height. */
.rt-header-line[b-1ch4m1ctmk] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    min-width: 0;
}

/* Top-aligned, not centred. The identity block can wrap to two visual lines (a long territory note
   pushes the status note under it) while the actions stay one line, and centring the two put the
   identity's FIRST line visibly above "Next follow-up". Top alignment plus a first line centred in
   the same 32px as the small outlined buttons (4px padding + a 24px line box) puts both first lines
   on one row, while any wrapped identity lines stay at a compact 24px rather than 32px each. */
.rt-header-line-2[b-1ch4m1ctmk] {
    margin-top: 4px;
    align-items: flex-start;
}

/* The identity text takes whatever the actions leave. flex-basis plus grow is what lets it
   shrink and wrap its own spans before it forces the actions group down to a line of its own. */
.rt-identity[b-1ch4m1ctmk] {
    flex: 1 1 360px;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    line-height: 24px;
    padding-top: 4px;
}

/* ESL number, Ref ID and close move as one unit: when line 1 runs out of width they drop to the
   right end of a new line together, instead of the number staying and the buttons wrapping alone. */
.rt-header-ref[b-1ch4m1ctmk] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
    margin-left: auto;
}

.rt-status-note[b-1ch4m1ctmk] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    align-self: center;
}

.rt-screening[b-1ch4m1ctmk] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

/* The vertical rule separates "who/what this is" from "what to do next" (Adam, 2026-09-24). A
   border rather than a MudDivider so it spans exactly the actions' own height. */
.rt-actions[b-1ch4m1ctmk] {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    margin-left: auto;
    padding-left: 12px;
    border-left: 1px solid var(--mud-palette-lines-default);
}

.rt-actions-caption[b-1ch4m1ctmk] {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}

/* Three-column body filling the height under the header stack; the row itself never scrolls.
   Gap and padding reproduce MudGrid's Spacing="3" gutter and the pa-3 it carried. */
.rt-body[b-1ch4m1ctmk] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
    gap: 24px;
    padding: 12px;
}

/* overflow-y:auto alone would make the browser compute overflow-x to auto as well, producing a
   phantom horizontal scrollbar whenever content exceeds the column width — pin it hidden (same
   reasoning as .cd-pane, .tw-pane and .pd-col). Behaviour rules (overscroll containment, scrollbar
   gutter, hover-reveal) come from the shared .app-scroll-pane rule in app.css. */
.rt-col[b-1ch4m1ctmk] {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    min-width: 0;
}

/* ===== Missing fields, at the top of the Properties column =====
   Sticky to the top of the column's own scroll, so it stays reachable while you work down the
   fields it points at. An opaque background is required — the column is transparent over the page,
   and without one the content would scroll visibly underneath the chips.

   Surface, not the page background: this reads as the first card in the Properties column, and
   filling it with page-grey made it look like a band sitting behind the column rather than part of
   it. The warning border still marks it as an alert. z-index keeps it above the field cards it
   overlaps while scrolling. */
.rt-missing[b-1ch4m1ctmk] {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-warning);
    border-radius: 8px;
    padding: 8px 10px;
    margin-bottom: 12px;
}

.rt-missing-head[b-1ch4m1ctmk] {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}

/* Chips wrap freely: this column is a third of the width the old full-width band had, so a row of
   six will always become several rows. Tighter gaps keep that from becoming a wall. */
.rt-missing-chips[b-1ch4m1ctmk] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

/* ::deep — the chip is a MudBlazor component root, which scoped CSS cannot target directly. */
.rt-missing-chips[b-1ch4m1ctmk]  .rt-missing-chip {
    margin: 0;
    height: 22px;
    font-size: 0.7rem;
}

.rt-col-left[b-1ch4m1ctmk] { flex: 3 1 0; }
.rt-col-center[b-1ch4m1ctmk] { flex: 5 1 0; }
.rt-col-right[b-1ch4m1ctmk] { flex: 4 1 0; }

/* Narrow viewports: stack the columns and hand the scroll back to the document. 960px matches
   MudGrid's md breakpoint, which is what md="3"/md="5"/md="4" used before, so the stacking point is
   unchanged. The chain itself is unwound app-wide at the same width (see app.css). */
@media (max-width: 960px) {
    .rt-body[b-1ch4m1ctmk] {
        flex-direction: column;
        overflow: visible;
    }

    .rt-col[b-1ch4m1ctmk] {
        flex: 0 0 auto;
        overflow: visible;
    }
}
/* /Components/Pages/DirectLicensing/SongEditDialog.razor.rz.scp.css */
/* PBI 386 — the Recent Changes table in the song editor.

   The table has no Height of its own, so the dialog is the only thing that scrolls: a table with its own
   scrollbar nested inside the dialog's means the wheel moves whichever of the two the pointer happens to
   be over, which is never reliably the one the agent meant.

   Losing MudTable's FixedHeader would normally lose the header on the way down, so it is made sticky
   instead. sticky anchors to the nearest scrolling ancestor, which without an inner scroller is the
   dialog — so the header follows the reader without a second scrollbar. The explicit background stops the
   striped rows showing through it.

   ::deep because MudTable renders the table, and a child component's elements do not carry this
   component's CSS-isolation scope attribute. */
[b-e5hl8ulbni] .song-edit-history thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background-color: var(--mud-palette-surface);
}

/* Change values are prose (a 225-character publisher list is normal here), so they wrap rather than
   forcing the table wider than the dialog. */
[b-e5hl8ulbni] .song-edit-history td {
    white-space: normal;
    overflow-wrap: break-word;
    vertical-align: top;
}
/* /Components/Pages/DirectLicensing/SongSearchDialog.razor.rz.scp.css */
/* PBI 386 — layout for the candidate results table.

   ::deep is required throughout: the table is rendered by MudTable, a child component, so its elements do
   not carry this component's CSS-isolation scope attribute. The scope lands on the wrapping div in this
   component's own markup, and ::deep reaches through to the table inside it. */

/* table-layout: fixed is what removes the horizontal scrollbar. Without it the browser widens columns to
   fit their content, the table grows past 2000px, and the agent has to scroll sideways to reach the codes
   — which on a maximised Chrome window at 1920x1080 means the right-hand half of the row is never visible
   at rest. Fixed layout makes the th widths authoritative and scales them down proportionally when their
   sum exceeds the dialog, so the whole row always fits whatever width is available. */
.song-search-results[b-gwm1q83coy]  table {
    table-layout: fixed;
    width: 100%;
}

/* Cells WRAP. Nothing is hidden behind a hover.

   The earlier version clipped to an ellipsis to keep rows at 45px, on the reasoning that the full value
   was one hover away. That was the wrong trade for this screen: an agent comparing thirty candidates is
   reading composer and publisher strings against each other, and a comparison you can only make one
   tooltip at a time is not a comparison. Taller rows and fewer of them at once is the right price.

   break-word, NOT anywhere. The two look interchangeable and are not: `anywhere` also lets a column
   shrink below its longest word, so it broke words mid-letter even where there was room — the button read
   "Ma/tc/h", the title "Summ/ertim/e", and a link count of 831 came out as three stacked digits.
   break-word only breaks a word that cannot fit its line on its own, which is the intent: wrap at spaces,
   split a 40-character publisher name as a last resort.

   vertical-align: top so a two-line cell lines up with a ten-line one beside it. */
.song-search-results[b-gwm1q83coy]  td {
    white-space: normal;
    overflow-wrap: break-word;
    vertical-align: top;
}

/* The action button, the qualification badge and the tick columns hold controls and single characters,
   never prose. Wrapping them only ever produces the "Ma/tc/h" failure above. */
.song-search-results[b-gwm1q83coy]  td:nth-child(1),
.song-search-results[b-gwm1q83coy]  td:nth-child(2),
.song-search-results[b-gwm1q83coy]  td.mark-cell {
    white-space: nowrap;
}

/* !important is load-bearing here, not laziness. MudBlazor's own cell rule sets ~41px of horizontal
   padding per cell with a selector this file cannot outrank, and at these column widths that padding was
   eating most of the column: a 94px Composers column had 53px of content left, about seven characters, so
   every word broke mid-letter no matter which overflow-wrap keyword was used. Measured, not inferred.
   Cutting the padding returns roughly 30px of text width per column, which is what makes wrapped prose
   legible without adding a horizontal scrollbar. An earlier pass tried the same override on font-size and
   dropped it as cosmetic; it is back, just below, because the two sizes it would have reconciled turned
   out to be visibly inconsistent from column to column. */
.song-search-results[b-gwm1q83coy]  td,
.song-search-results[b-gwm1q83coy]  th {
    padding-left: 5px !important;
    padding-right: 5px !important;
}

/* One font size for every column.

   Before this, a column's size depended on how its cell happened to be built. The plain-text columns —
   Alternate Titles, Composers, Arrangers, Artists, Publishers, Catalog, the copyright years and the whole
   tick band — inherited MudBlazor's 0.875rem body-cell size. The four whose cells wrap a MudText or
   MudLink instead (SongID, Title, Links, GoThrough) rendered at Typo.caption's 0.75rem. Reading across one
   row meant reading across two type sizes, which is what it looked like.

   Unified on the smaller of the two, not the larger. This table puts 27 columns of wrapping prose inside a
   dialog, so the extra characters per line shorten both the wrap and the row; and the two columns an agent
   reads first, Title and SongID, were already at this size, so the smaller value is also the one that
   moves the fewest of the columns that matter.

   Set here rather than on each cell so this is the single place the size is decided — a stray Typo on a
   column added later cannot pull one out of line again. !important for the same reason the padding rule
   above needs it: MudBlazor sets the cell font-size with a selector this file cannot outrank.

   That last point is why the MudTable also carried an inline font-size: 0.72rem, now removed. A size set
   on the table is overridden for every cell that holds text, because MudBlazor's rule targets td directly
   and beats inheritance — so the inline value reached almost nothing while reading as though it governed
   the table, and it was a third size on top of the two it was meant to settle.

   Two things are deliberately left out. Controls keep their own sizing: the Match button, the
   qualification chip and the PD chip are not column text, and dragging them to 0.75rem would just make
   them look broken. And the header row stays at MudBlazor's 0.875rem, which is unreachable from here
   anyway (see the note below) — a slightly larger header over a smaller body is ordinary table practice,
   and every column width was measured against the header at that size. */
.song-search-results[b-gwm1q83coy]  td,
.song-search-results[b-gwm1q83coy]  td .mud-typography {
    font-size: 0.75rem !important;
}

/* Note on the header font, because it looks like an omission: MudBlazor sets font-size and white-space
   on its own header cell with a more specific selector than anything reachable from here, so trying to
   shrink or wrap the headers from this file silently does nothing — verified by reading
   getComputedStyle, which still reported 14px and nowrap after the attempt. Rather than escalate into an
   !important specificity fight with the component library, every column width in the razor is sized from
   the header's MEASURED scrollWidth at that 14px, plus a small buffer. That is why the widths look
   oddly specific (ISWC 54, ASCAP 64, GoThrough 91): each is the width its own label actually needs.
   If a label changes, re-measure rather than guess. */

/* The present/absent marks read as a column of ticks, so they are centred under their label. clip, not
   ellipsis: a tick is one character and never needs truncating, but inheriting the body's ellipsis
   rendered it as "✓…" once the surrounding markup whitespace was counted. */
.song-search-results[b-gwm1q83coy]  td.mark-cell,
.song-search-results[b-gwm1q83coy]  th.mark-col {
    text-align: center;
}

.song-search-results[b-gwm1q83coy]  td.mark-cell {
    text-overflow: clip;
}

/* The action and badge columns are sized to their measured control widths (102px for the button, 108px
   for the chip) so they need no overflow exception. An earlier version let them overflow visibly instead,
   which painted the chip straight over the SongID beside it — the ids read "18…" while the column was
   wide enough for them. Sizing the column is the fix; letting content escape its cell is not. */

/* Headers stay on one line too, so the header row matches the body's rhythm. */
.song-search-results[b-gwm1q83coy]  th {
    white-space: nowrap;
}

/* The header sticks to the top of the DIALOG's scroll area rather than to a scroll area of the table's
   own. MudTable's FixedHeader needs an explicit Height, which gives the table a second scrollbar nested
   inside the dialog's — and a nested scroll means the wheel moves whichever one the pointer is over,
   which is never reliably the one the agent meant. sticky anchors to the nearest scrolling ancestor, so
   dropping the height makes that ancestor the dialog and the header still follows the reader down.

   The explicit background is required: without it the striped rows show straight through the header as it
   passes over them. */
.song-search-results[b-gwm1q83coy]  thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background-color: var(--mud-palette-surface);
}

/* PBI 386 — the unqualified-match confirmation, drawn under the pointer.

   Fixed positioning with a very high z-index because it has to sit above the dialog it is rendered
   inside, and above the results table's own scroll container, which would otherwise clip it. The
   coordinates come from the click; the viewport clamp lives in the inline style (the browser knows the
   viewport size, the server does not).

   The backdrop is a transparent full-screen click target, so clicking anywhere else dismisses — what a
   popover is expected to do, and cheaper than wiring up an outside-click handler. */
.song-match-confirm-backdrop[b-gwm1q83coy] {
    position: fixed;
    inset: 0;
    z-index: 2400;
}

.song-match-confirm[b-gwm1q83coy] {
    position: fixed;
    z-index: 2401;
    width: 340px;
}
/* /Components/Pages/DirectLicensing/TicketReplyComposer.razor.rz.scp.css */
.tc-composer[b-oeouolylys] {
    border-top: 1px solid var(--mud-palette-lines-default);
    padding: 12px;
    background: var(--mud-palette-surface);
}

/* Internal-note tint mirrors Zendesk's yellow internal-note affordance so the agent can't
   mistake an internal note for a customer-facing reply. */
.tc-composer.tc-internal .tc-editor[b-oeouolylys] {
    background: var(--es-draft-bg);
}

.tc-toolbar[b-oeouolylys] {
    border: 1px solid var(--mud-palette-lines-default);
    border-bottom: none;
    border-radius: 6px 6px 0 0;
    padding: 2px 4px;
}

/* PBI 164.2 — closed ticket: grey the editor + toolbar so it reads as locked. Buttons disable
   themselves; this greys the contenteditable box (which has no disabled state of its own) and
   blocks stray interaction with it. The notice + disabled controls carry the "why". */
.tc-composer.tc-readonly .tc-editor[b-oeouolylys],
.tc-composer.tc-readonly .tc-toolbar[b-oeouolylys] {
    background: var(--mud-palette-action-disabled-background);
    opacity: 0.7;
}

.tc-composer.tc-readonly .tc-editor[b-oeouolylys] {
    cursor: not-allowed;
}

.tc-editor[b-oeouolylys] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 0 0 6px 6px;
    min-height: 90px;
    max-height: 240px;
    overflow-y: auto;
    padding: 8px 10px;
    outline: none;
    font-size: 0.9rem;
    line-height: 1.4;
    word-break: break-word;
}

.tc-editor:focus[b-oeouolylys] {
    border-color: var(--mud-palette-primary);
}

/* Placeholder for the empty contenteditable — attr() reads data-placeholder off the div. */
.tc-editor:empty[b-oeouolylys]::before {
    content: attr(data-placeholder);
    color: var(--mud-palette-text-disabled);
    pointer-events: none;
}

.tc-emoji-grid[b-oeouolylys] {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 2px;
    padding: 4px;
    max-width: 240px;
}

.tc-emoji-glyph[b-oeouolylys] {
    font-size: 1.1rem;
    line-height: 1;
}
/* /Components/Pages/DirectLicensing/TicketWorkspaceView.razor.rz.scp.css */
/* The three panes scroll independently (Zendesk-style) instead of the whole page growing. Height
   comes from .app-fixed-page in app.css, which makes this the leftover space in a flex chain
   running from <html> down; it used to be a hard-coded `calc(100vh - 163px)` repeated here and in
   CustomerDetail's (Bug 389). On narrow viewports the model is disengaged app-wide and the layout
   falls back to natural page scroll. */
.tw-root[b-o1ztn54lic] {
    min-height: 0;
}

.tw-header[b-o1ztn54lic] {
    border-bottom: 1px solid var(--mud-palette-lines-default);
    flex: 0 0 auto;
}

.tw-title-wrap[b-o1ztn54lic] {
    min-width: 0;
    overflow: hidden;
    flex: 0 1 auto;
}

.tw-title[b-o1ztn54lic] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* In-place refresh indicator — a thin bar under the header while a soft refresh runs (after a
   reply submit). Fixed height so it never steals height from the three-pane body below it. */
.tw-refresh-bar[b-o1ztn54lic] {
    flex: 0 0 auto;
}

.tw-center-message[b-o1ztn54lic] {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Three-pane body. Panes scroll independently; the whole row fills the remaining height. */
.tw-body[b-o1ztn54lic] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
}

.tw-pane[b-o1ztn54lic] {
    padding: 12px;
    min-width: 0;
    overflow-y: auto;
    /* Hard stop: never scroll horizontally. overflow-y:auto alone makes the browser compute
       overflow-x to auto (visible+auto is illegal), which produced a horizontal scrollbar as
       soon as a long value/tag exceeded the pane. Long content wraps (below) instead. */
    overflow-x: hidden;
}

.tw-pane-left[b-o1ztn54lic] {
    flex: 0 0 26%;
    border-right: 1px solid var(--mud-palette-lines-default);
}

.tw-pane-right[b-o1ztn54lic] {
    flex: 0 0 26%;
    border-left: 1px solid var(--mud-palette-lines-default);
}

/* Center pane holds the scrolling thread + the pinned composer, so it manages its own
   vertical layout and does NOT scroll as a whole (the thread scrolls instead). */
.tw-pane-center[b-o1ztn54lic] {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding-bottom: 0;
}

/* The scrolling conversation. Subtle grey inset so the white comment cards read as distinct
   messages (issue: cards were the same color as the pane).

   This — not .tw-pane-center around it — is the element that owns the scroll, so it is the one
   carrying .app-scroll-pane (and the tabindex/role/aria-label that go with it, in the markup).
   Behaviour rules come from that shared class in app.css; only the geometry and colour are here. */
.tw-thread[b-o1ztn54lic] {
    flex: 1 1 auto;
    overflow-y: auto;
    background: var(--mud-palette-background-grey);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    padding: 8px;
    /* The thread sits on background-grey, not the page background the shared rule assumes and not
       the surface the card-style panes use, so the "more below" fade has to end in its own inset
       colour or it reads as a band rather than a fade. */
    --app-scroll-fade-color: var(--mud-palette-background-grey);
}

.tw-card[b-o1ztn54lic] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
}

/* Fields stack label-above-value so long labels (CreationSourceURL, UserNameStringEmployee, …)
   can't overlap their value the way a fixed-width label column did. */
.tw-field[b-o1ztn54lic] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tw-field-label[b-o1ztn54lic] {
    line-height: 1.2;
}

.tw-field-value[b-o1ztn54lic] {
    min-width: 0;
    /* overflow-wrap:anywhere breaks even an unbroken token (a long URL, a slug) so it can never
       push the field wider than the pane. word-break is the older-engine fallback. */
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* URL-valued fields wrap to fit the column (multi-line is fine, and fully readable) rather than
   a single nowrap line that overflowed the pane and forced a horizontal scrollbar. */
.tw-field-link[b-o1ztn54lic] {
    display: block;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.tw-tags[b-o1ztn54lic] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

/* Outlined chip-like pill rendered as a plain span (not MudChip) so we fully control clipping:
   a tag too long for the column ellipsizes and shows its full text on hover, instead of the
   MudChip label overflowing and overlapping neighbors. */
.tw-tag[b-o1ztn54lic] {
    display: inline-block;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    box-sizing: border-box;
    height: 20px;
    line-height: 18px;
    padding: 0 8px;
    font-size: 0.65rem;
    color: var(--mud-palette-text-secondary);
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 10px;
}

.tw-tags-toggle[b-o1ztn54lic] {
    margin-top: 2px;
    text-transform: none;
    font-size: 0.72rem;
}

/* Public replies are white cards on the grey thread so each message stands out. */
.tw-comment[b-o1ztn54lic] {
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    padding: 8px 10px;
    margin-bottom: 8px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

.tw-comment:last-child[b-o1ztn54lic] {
    margin-bottom: 0;
}

/* Internal notes are staff coordination — tint them apart from customer-facing replies. */
.tw-comment.tw-internal[b-o1ztn54lic] {
    background: var(--es-draft-bg);
    border-color: var(--es-draft-border);
}

/* Avatar-left, content-right message layout (Zendesk-style). */
.tw-comment-row[b-o1ztn54lic] {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.tw-comment-main[b-o1ztn54lic] {
    flex: 1 1 auto;
    min-width: 0;
}

/* Initials disc standing in for a profile photo. */
.tw-avatar[b-o1ztn54lic] {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1;
    user-select: none;
}

/* Staff: filled brand blue, white initials. */
.tw-avatar-agent[b-o1ztn54lic] {
    background: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
}

/* End user: inverted — white disc, blue initials + brand ring. */
.tw-avatar-customer[b-o1ztn54lic] {
    background: var(--mud-palette-surface);
    color: var(--mud-palette-primary);
    border: 2px solid var(--mud-palette-primary);
}

.tw-comment-head[b-o1ztn54lic] {
    margin-bottom: 4px;
}

.tw-comment-body[b-o1ztn54lic] {
    white-space: pre-wrap;
    word-break: break-word;
    font-size: 0.9rem;
    line-height: 1.45;
}

/* PBI 164.2 — comment rendered from sanitized html_body. Block elements handle spacing, so drop
   pre-wrap (which would double up the HTML's own whitespace). ::deep is required because the
   sanitized markup is injected via MarkupString and does NOT receive this component's CSS-isolation
   scope attribute — a plain `.tw-html p` selector would never match it. */
.tw-comment-body.tw-html[b-o1ztn54lic] {
    white-space: normal;
}

/* PBI 164.3 — give paragraphs a real TOP margin (browser/Gmail default is ~1em), not just a
   bottom one. Zendesk wraps an agent's signature in <div class="signature"><p>…</p></div> and
   leans on that <p>'s top margin for the blank line between the message and the signature. We
   strip the class for safety, so without a top margin here the signature butted directly against
   the last body line. Adjacent paragraphs collapse to a single 0.75em gap, so body spacing stays
   tight. */
.tw-comment-body.tw-html[b-o1ztn54lic]  p {
    margin: 0.75em 0;
}

/* NB: no p:first-child reset — Zendesk's signature <p> is the first (only) child of its wrapper
   <div>, so zeroing first-child top margins would kill the very gap this fixes. A leading <p> at
   the top of a comment just gets a harmless 0.75em of lead-in space (comments open with text, not
   a <p>, so this is rare). */
.tw-comment-body.tw-html[b-o1ztn54lic]  p:last-child {
    margin-bottom: 0;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  ul,
.tw-comment-body.tw-html[b-o1ztn54lic]  ol {
    margin: 0 0 8px;
    padding-left: 20px;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  img {
    max-width: 100%;
    height: auto;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  a {
    color: var(--es-link);
    text-decoration: underline;
    word-break: break-all;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  blockquote {
    margin: 0 0 8px;
    padding-left: 10px;
    border-left: 3px solid var(--mud-palette-lines-default);
    color: var(--mud-palette-text-secondary);
}

.tw-comment-body.tw-html[b-o1ztn54lic]  pre {
    white-space: pre-wrap;
    word-break: break-word;
    background: rgba(0, 0, 0, 0.04);
    padding: 6px 8px;
    border-radius: 4px;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  code {
    background: rgba(0, 0, 0, 0.04);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 0.85em;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  table {
    border-collapse: collapse;
    max-width: 100%;
}

.tw-comment-body.tw-html[b-o1ztn54lic]  td,
.tw-comment-body.tw-html[b-o1ztn54lic]  th {
    border: 1px solid var(--mud-palette-lines-default);
    padding: 4px 8px;
}

/* Stack the panes on narrow viewports so nothing is clipped (AC-friendly graceful degrade).
   The fixed viewport height + independent-scroll model is desktop-only; below this, fall back
   to natural page scroll so the panes aren't crammed into a short fixed box. */
@media (max-width: 960px) {
    .tw-body[b-o1ztn54lic] {
        flex-direction: column;
        overflow-y: auto;
    }

    .tw-pane-left[b-o1ztn54lic],
    .tw-pane-right[b-o1ztn54lic] {
        flex: 0 0 auto;
        border: none;
        border-bottom: 1px solid var(--mud-palette-lines-default);
    }

    .tw-pane-center[b-o1ztn54lic] {
        flex: 0 0 auto;
        overflow: visible;
        min-height: 420px;
    }
}
/* /Components/Pages/Distro/ReleaseDetail.razor.rz.scp.css */
/* PBI 1284 / 1285 — the Distro release page's layout, modelled on Project Detail
   (ProjectDetail.razor.css). The page's height comes from .app-fixed-page (app.css), which makes it
   the leftover space in a flex chain running from <html> down; each of the three columns is the
   sole vertical scroll owner of its own content.

   ::deep wherever a class sits on a MudBlazor component (MudPaper, MudText): Blazor's CSS-isolation
   attribute is never applied to a MudBlazor component's root element, so a bare selector compiles to
   something that matches nothing. Plain markup written in this file does get the attribute. */

.rd-root[b-yf8ktu5d8v] {
    min-height: 0;
}

/* The header bar and its path stay pinned; only the columns below scroll. */
.rd-root[b-yf8ktu5d8v]  .rd-header {
    flex: 0 0 auto;
}

.rd-header-line[b-yf8ktu5d8v] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
}

.rd-header-sub[b-yf8ktu5d8v] {
    margin-top: 4px;
    gap: 6px;
    font-size: 0.875rem;
    color: var(--mud-palette-text-secondary);
}

.rd-sep[b-yf8ktu5d8v] {
    color: var(--mud-palette-text-disabled);
}

/* The title takes what is left of line 1 and ellipses rather than pushing the chips to a new line. */
.rd-header-line[b-yf8ktu5d8v]  .rd-title {
    min-width: 0;
    max-width: 34ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rd-header-line[b-yf8ktu5d8v]  .rd-reviewer-text {
    white-space: nowrap;
    font-size: 0.8125rem;
}

/* PBI 1327 — "Assign to me and start review" is the longest thing on line 1; below the page's
   960px breakpoint it shortens to "Start review", and the tooltip and aria-label keep the full label.
   ::deep because the spans sit inside MudButton's content. */
.rd-header-line[b-yf8ktu5d8v]  .rd-claim-short {
    display: none;
}

@media (max-width: 960px) {
    .rd-header-line[b-yf8ktu5d8v]  .rd-claim-full {
        display: none;
    }

    .rd-header-line[b-yf8ktu5d8v]  .rd-claim-short {
        display: inline;
    }
}

/* Tracks | Platforms | live — the same bordered-pill treatment as Project Detail's header tallies. */
.rd-headerstats[b-yf8ktu5d8v] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 10px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    font-size: 0.8125rem;
    white-space: nowrap;
}

.rd-headerstats-sep[b-yf8ktu5d8v] {
    color: var(--mud-palette-text-disabled);
}

/* Three-column body filling the height under the header; the row itself never scrolls. 24px gap
   reproduces MudGrid's default gutter, as on Project Detail. */
.rd-body[b-yf8ktu5d8v] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
    gap: 24px;
}

/* Each column scrolls on its own. overflow-x pinned hidden so overflow-y:auto does not make the
   browser compute a phantom horizontal scrollbar (same reasoning as .pd-col). */
.rd-col[b-yf8ktu5d8v] {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    min-width: 0;
}

.rd-col-left[b-yf8ktu5d8v] { flex: 3 1 0; }
.rd-col-center[b-yf8ktu5d8v] { flex: 6 1 0; }
.rd-col-right[b-yf8ktu5d8v] { flex: 3 1 0; }

/* PBI 1292 — the toggle row (and the Tracks view's Expand all / Review line) pinned to the top of the
   centre column, which is its own scroll owner (.rd-col). Painted with the page canvas so cards
   scroll UNDER it rather than showing through, and padded rather than margined at the foot - a
   margin is transparent, so a strip of scrolling card would show between the bar and the content.
   z-index clears the cards' elevation shadows. */
.rd-center-sticky[b-yf8ktu5d8v] {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--mud-palette-background);
    padding-bottom: 8px;
    margin-bottom: 4px;
    box-shadow: 0 1px 0 var(--mud-palette-lines-default);
}

/* The toggle and the release's actions on one line above the centre column. Wraps rather than
   overflowing on a narrow centre column; the actions keep together at the right. */
.rd-toggle-row[b-yf8ktu5d8v] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.rd-center-sticky[b-yf8ktu5d8v]  .rd-tracks-bar {
    margin-top: 6px;
}

/* One unit, pushed right: when the centre column is too narrow for both, the actions drop to their
   own line together rather than Publish staying beside the toggle and Actions wrapping under it. */
.rd-toggle-actions[b-yf8ktu5d8v] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

/* Narrow viewports (AC 1): drop the fixed-height, independent-scroll model and let the page scroll,
   stacking the columns. Same breakpoint as Project Detail and Customer Detail. */
@media (max-width: 960px) {
    .rd-body[b-yf8ktu5d8v] {
        flex-direction: column;
        overflow: visible;
    }

    .rd-col[b-yf8ktu5d8v] {
        flex: 0 0 auto;
        overflow: visible;
    }

    /* The page scrolls here, not the column, and the app bar would cover a bar stuck at top: 0. */
    .rd-center-sticky[b-yf8ktu5d8v] {
        position: static;
        box-shadow: none;
    }
}
/* /Components/Pages/Distro/Review/ArtworkZoom.razor.rz.scp.css */
/* The review dialog's evidence pane is max-height 62vh (ReviewGroupDialog); the caption row takes
   ~40px of it, so the image gets the rest and never makes the pane scroll. */

.awz[b-z2ibrzzkpt] {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.awz-fit[b-z2ibrzzkpt] {
    display: block;
    max-width: 100%;
    max-height: calc(62vh - 48px);
    width: auto;
    height: auto;
    margin: 0 auto;
    border-radius: 6px;
    border: 1px solid var(--mud-palette-lines-default);
    cursor: zoom-in;
}

.awz-pan[b-z2ibrzzkpt] {
    max-height: calc(62vh - 48px);
    overflow: auto;
    border-radius: 6px;
    border: 1px solid var(--mud-palette-lines-default);
}

.awz-actual[b-z2ibrzzkpt] {
    display: block;
    max-width: none;
    width: auto;
    height: auto;
    margin: 0 auto;
    cursor: zoom-out;
}

.awz-caption[b-z2ibrzzkpt] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
/* /Components/Pages/Distro/Review/TrackWaveform.razor.rz.scp.css */
.track-waveform[b-6iugcvmlbl] {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
}

/* Sized before anything loads, so the row never reflows when the waveform arrives. The centre line
   is the baseline every waveform sits on, and is all a track without peaks shows. */
.track-waveform-frame[b-6iugcvmlbl] {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    background: linear-gradient(to bottom,
        transparent calc(50% - 0.5px),
        var(--mud-palette-lines-default) calc(50% - 0.5px),
        var(--mud-palette-lines-default) calc(50% + 0.5px),
        transparent calc(50% + 0.5px));
}

.track-waveform-wave[b-6iugcvmlbl] {
    width: 100%;
    cursor: pointer;
}

.track-waveform-nodata[b-6iugcvmlbl] {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0 6px;
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary);
    background: var(--mud-palette-surface);
    pointer-events: none;
    white-space: nowrap;
    /* Above WaveSurfer's own layers (wave 2, cursor 5), which otherwise draw the line through it. */
    z-index: 6;
}

/* Fixed width (fits "00:00 / 00:00") and a placeholder while loading, so the waveform's width is the
   same before and after the readout is filled in. */
.track-waveform-time[b-6iugcvmlbl] {
    flex: 0 0 auto;
    width: 13ch;
    text-align: right;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}

.track-waveform-time:empty[b-6iugcvmlbl]::before {
    content: "–:–– / –:––";
}
/* /Components/Pages/Distro/TrackSubmittedData.razor.rz.scp.css */
/* PBI 1292 — a track's submitted data. See TrackSubmittedData.razor for the seven decisions. */

.tsd[b-yfruvn8gg4] {
    padding-top: 4px;
}

/* Sections flow into as many columns as fit: two in the release page's centre column at 1440px,
   one when it narrows. Each section keeps its own height rather than stretching to its neighbour. */
.tsd-grid[b-yfruvn8gg4] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 10px 24px;
    align-items: start;
}

.tsd-section[b-yfruvn8gg4] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

/* Label beside value (Components/Shared/LabelledValue.razor's layout): a fixed label column, so
   values line up down the section and a reviewer reads one column instead of zig-zagging. */
.tsd-rows[b-yfruvn8gg4] {
    display: grid;
    grid-template-columns: 120px minmax(0, 1fr);
    column-gap: 10px;
    row-gap: 1px;
    align-items: baseline;
}

.tsd-label[b-yfruvn8gg4] {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
}

.tsd-value[b-yfruvn8gg4] {
    font-size: 0.875rem;
    overflow-wrap: anywhere;
}

.tsd-value-muted[b-yfruvn8gg4] {
    color: var(--mud-palette-text-secondary);
    font-style: italic;
}

/* "Not set": Project Detail's fold (ProjectDetail.razor.css, "the Not set row"). A quiet footnote,
   not a list of errors - an unset field is normal. Dotted underline: these add a value, they are
   not navigation. ::deep because MudLink is a component root; !important on colour only because
   MudLink ships .mud-primary-text with !important (see the ProjectDetail note). */
.tsd-notset[b-yfruvn8gg4] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 10px;
    margin-top: 8px;
    padding-top: 6px;
    border-top: 1px dashed var(--mud-palette-lines-default);
}

.tsd-notset-label[b-yfruvn8gg4] {
    font-size: 0.75rem;
    color: var(--mud-palette-text-disabled);
}

.tsd-notset-label[b-yfruvn8gg4]::after {
    content: ":";
}

.tsd-notset[b-yfruvn8gg4]  .tsd-notset-item {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary) !important;
    border-bottom: 1px dotted var(--mud-palette-lines-default);
    cursor: pointer;
}

.tsd-notset[b-yfruvn8gg4]  .tsd-notset-item:hover {
    color: var(--mud-palette-primary) !important;
    border-bottom-color: var(--mud-palette-primary);
}

.tsd-notset .tsd-notset-item-static[b-yfruvn8gg4] {
    cursor: default;
    border-bottom: 0;
}
/* /Components/Pages/Giddy/GiddyUserCard.razor.rz.scp.css */
/* PBI 796 — the Giddy person card's layout.
 *
 * THE COLUMN SCROLLS, NOT THE CARD. This is the one place the card deliberately departs from
 * CustomerDetail, whose panes each scroll behind a frozen header. Tim's call, and the better fit here:
 * a person's sections are wildly uneven — a two-line subscription beside a fifty-visit history — so
 * per-pane scrolling hands the short ones a scrollbar they never need while boxing the long ones into
 * a sliver. Three columns that scroll as a whole let each card take the height it actually wants.
 *
 * As there, the PAGE never scrolls. Height comes from `.app-fixed-page` in app.css, which makes this
 * the leftover space in a flex chain running from <html> down (Bug 389 replaced a hard-coded
 * calc(100vh - 163px) with it). Below 960px the fixed-height model is dropped app-wide in favour of
 * natural page scroll, so this file only has to stack its own columns at that breakpoint.
 *
 * The class names are this component's own because Blazor CSS isolation scopes every rule here to its
 * own elements — CustomerDetail's `.cd-*` rules cannot reach this component, and importing them is not
 * something the framework offers.
 */
.gu-root[b-8sve4ph4ky] {
    min-height: 0;
}

.gu-header[b-8sve4ph4ky] {
    flex: 0 0 auto;
    background: var(--mud-palette-surface);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Three columns filling the height under the banner. The BODY does not scroll — each column does. */
.gu-body[b-8sve4ph4ky] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
    gap: 16px;
    padding-top: 12px;
}

/* A column: a vertical stack of natural-height cards, scrolling as one region.
 *
 * overflow-x is pinned hidden because overflow-y:auto alone makes the browser compute overflow-x to
 * auto, which shows a phantom horizontal scrollbar whenever content exceeds the width — the same trap
 * the customer card's panes hit.
 *
 * padding-right leaves the scrollbar somewhere to sit without it overlapping a card's border. */
.gu-col[b-8sve4ph4ky] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 4px;
}

/* 3:5:4, the proportions the customer card uses. The centre is widest because it holds the activity
   chart, which is the one thing here that is unreadable when narrow; the right is wider than the left
   because it carries the account details and the sign-in list rather than short figure rows. */
.gu-col-left[b-8sve4ph4ky] { flex: 3 1 0; }
.gu-col-center[b-8sve4ph4ky] { flex: 5 1 0; }
.gu-col-right[b-8sve4ph4ky] { flex: 4 1 0; }

/* A card: natural height, no scrolling of its own.
 *
 * flex: 0 0 auto is what makes the column the scroll region rather than the card — without it the
 * cards would share out the column's height between them and each need its own scrollbar again, which
 * is precisely the arrangement this replaces. */
.gu-card[b-8sve4ph4ky] {
    flex: 0 0 auto;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-surface);
    box-sizing: border-box;
}

/* Plain <div>s rather than MudPaper: Blazor's CSS-isolation attribute is not added to MudBlazor
   component roots, so these scoped rules would silently not apply. Restyled as the outlined cards they
   replace. */
.gu-card-header[b-8sve4ph4ky] {
    padding: 12px 16px 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.gu-card-body[b-8sve4ph4ky] {
    padding: 8px 16px 16px;
}

/* A label/value pair in a card. */
.gu-field[b-8sve4ph4ky] {
    margin-bottom: 8px;
}

/* One row of the sign-in history. A list rather than a table: AC #5 asks for a list, and each entry
   carries only a date and a length. */
.gu-session-row[b-8sve4ph4ky] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.gu-session-row:last-child[b-8sve4ph4ky] {
    border-bottom: none;
}

/* Narrow viewports: drop the fixed-height, independent-scroll model and let the page scroll, stacking
   the columns so nothing is crammed into a short fixed box. */
@media (max-width: 960px) {
    .gu-body[b-8sve4ph4ky] {
        flex-direction: column;
        overflow: visible;
    }

    .gu-col[b-8sve4ph4ky] {
        flex: 0 0 auto;
        overflow: visible;
        padding-right: 0;
    }
}
/* /Components/Pages/Home.razor.rz.scp.css */
/* UI/UX review (chore/2026-07-16): scoped styles for the Home hub. All colours come from MudBlazor
   palette CSS variables so the page follows the light/dark toggle automatically. */

.home-hero-title[b-9g4pfp6o81] {
    font-weight: 700;
}

.home-hero-subtitle[b-9g4pfp6o81] {
    color: var(--mud-palette-text-secondary);
    max-width: 62ch;
}

/* Auto-fill grid: cards flow into as many columns as the viewport allows and collapse to one on
   narrow screens — no manual breakpoints needed. */
.home-grid[b-9g4pfp6o81] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
}

.home-card[b-9g4pfp6o81] {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 20px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    text-decoration: none;
    transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

.home-card:hover[b-9g4pfp6o81] {
    border-color: var(--mud-palette-primary);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10);
    transform: translateY(-2px);
}

.home-card:focus-visible[b-9g4pfp6o81] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

.home-card-icon[b-9g4pfp6o81] {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 12px;
    /* Fallback for engines without color-mix; the tinted version wins where supported. */
    background: rgba(62, 176, 213, 0.12);
    background: color-mix(in srgb, var(--mud-palette-primary) 14%, transparent);
}

.home-card-body[b-9g4pfp6o81] {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.home-card-title[b-9g4pfp6o81] {
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.2;
}

.home-card-desc[b-9g4pfp6o81] {
    font-size: 0.85rem;
    color: var(--mud-palette-text-secondary);
    line-height: 1.35;
}

/* Wrapper span (not the MudIcon itself) so the icon inherits currentColor and this scoped rule can
   drive it — scoped-CSS attributes aren't applied to child-component roots. */
.home-card-arrow[b-9g4pfp6o81] {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--mud-palette-text-disabled);
    transition: transform 120ms ease, color 120ms ease;
}

.home-card:hover .home-card-arrow[b-9g4pfp6o81] {
    color: var(--mud-palette-primary);
    transform: translateX(3px);
}
/* /Components/Pages/Sales/CustomerDetail.razor.rz.scp.css */
/* Customer detail page layout. The PAGE never scrolls — each section pane scrolls on its own (no
   nested page + section scrollbars). Height comes from .app-fixed-page in app.css, which makes this
   the leftover space in a flex chain running from <html> down; it used to be a hard-coded
   `calc(100vh - 163px)` repeated in this file and TicketWorkspaceView's (Bug 389). Below 960px the
   fixed-height/independent-scroll model is dropped app-wide in favour of natural page scroll, so
   this file only has to stack its own columns at that breakpoint. */
.cd-root[b-cexsg4m73f] {
    min-height: 0;
}

.cd-header[b-cexsg4m73f] {
    flex: 0 0 auto;
    background: var(--mud-palette-surface);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Three-column body; the columns fill the height under the banner and never scroll as a whole. */
.cd-body[b-cexsg4m73f] {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
    overflow: hidden;
    gap: 16px;
    padding-top: 12px;
}

/* A column is a vertical flex stack of panes. Ratios 3:5:4 mirror the old MudGrid xs=3/5/4. */
.cd-col[b-cexsg4m73f] {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
    gap: 12px;
}

.cd-col-left[b-cexsg4m73f] { flex: 3 1 0; }
.cd-col-center[b-cexsg4m73f] { flex: 5 1 0; }
.cd-col-right[b-cexsg4m73f] { flex: 4 1 0; }

/* A scrolling section pane: vertical scroll only. overflow-y:auto alone makes the browser compute
   overflow-x to auto, which showed a phantom horizontal scrollbar whenever content exceeded the
   pane width — pin it hidden (matches the .tw-pane rule). */
.cd-pane[b-cexsg4m73f] {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    /* These panes are surface-coloured cards, not transparent columns, so the "more below" fade
       has to end in surface rather than the page background it defaults to (see app.css). */
    --app-scroll-fade-color: var(--mud-palette-surface);
}

.cd-pane-fill[b-cexsg4m73f] { flex: 1 1 auto; }
.cd-pane-42[b-cexsg4m73f] { flex: 1 1 42%; }
.cd-pane-58[b-cexsg4m73f] { flex: 1 1 58%; }
.cd-pane-50[b-cexsg4m73f] { flex: 1 1 50%; }
.cd-pane-natural[b-cexsg4m73f] { flex: 0 0 auto; }

/* Panes are plain <div>s (not MudPaper) so the scoped scroll rules above actually apply — Blazor's
   CSS-isolation attribute is not added to MudBlazor component roots, which silently dropped the
   overflow rules when these were MudPaper. Restyle them as the Outlined cards they replace. */
.cd-pane[b-cexsg4m73f],
.cd-pane-natural[b-cexsg4m73f] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-surface);
    box-sizing: border-box;
}

.cd-section-body[b-cexsg4m73f] {
    padding: 8px 16px 16px;
}

/* Frozen section header inside a scrolling pane; surface background so content passes underneath it
   rather than through it. */
.cd-sticky-header[b-cexsg4m73f] {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--mud-palette-surface);
    padding: 12px 16px 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Narrow viewports: drop the fixed-height, independent-scroll model and let the page scroll,
   stacking the columns so nothing is crammed into a short fixed box. */
@media (max-width: 960px) {
    .cd-body[b-cexsg4m73f] {
        flex-direction: column;
        overflow: visible;
    }

    .cd-col[b-cexsg4m73f] {
        flex: 0 0 auto;
    }

    .cd-pane[b-cexsg4m73f],
    .cd-pane-fill[b-cexsg4m73f],
    .cd-pane-42[b-cexsg4m73f],
    .cd-pane-58[b-cexsg4m73f],
    .cd-pane-50[b-cexsg4m73f] {
        flex: 0 0 auto;
        overflow: visible;
    }
}
/* /Components/Pages/SongSearch/SearchQueue.razor.rz.scp.css */
/* PBI 394 — the Search Queue's split view.

   The queue keeps the full width until a row is clicked, then gives the track roughly 40% of it. Two
   panes rather than a navigation, because the decision an agent is making ("is this the right song?")
   is made against the neighbouring rows: the same song arrives on many projects, and the group is the
   context. Losing the list to see one track loses the reason to look.

   Height comes from .app-fixed-page (app.css, Bug 389) — the page is simply the space left under the
   chrome, whatever that turns out to be. No viewport arithmetic here or on the grid: the two panes
   have to end level, and two independent guesses at the chrome height would eventually disagree. */
.sq-root[b-m4wcn5gm4e] {
    min-height: 0;
}

/* Everything above the panes stays its own size; only .sq-split grows. Written as a catch-all on the
   root's children rather than a class per band, because three of those bands are child components
   (SavedViewsToolbar, TrackerTruncationAlert, the progress bar) whose roots never receive this
   component's scope attribute — hence ::deep, which scopes the left half of the selector and leaves
   the right half alone. Without it a long filter bar would be squashed instead of the grid. */
.sq-root[b-m4wcn5gm4e]  > * {
    flex: 0 0 auto;
}

.sq-root[b-m4wcn5gm4e]  > .sq-split {
    flex: 1 1 auto;
}

.sq-split[b-m4wcn5gm4e] {
    display: flex;
    gap: 12px;
    align-items: stretch;

    /* The one element that takes the leftover height, and hands it to both panes. */
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

/* min-width: 0 is load-bearing, not defensive. A flex item's default min-width is auto, which is its
   content's intrinsic width — a data grid with a dozen columns refuses to shrink below that, so
   without this the list simply pushes the detail pane off the page instead of narrowing. min-height
   does the same job vertically, and without it the grid floors the row at its content height and the
   whole page grows past the viewport. */
.sq-split__list[b-m4wcn5gm4e] {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* The grid is a child component, so it needs ::deep to be told to fill the column rather than sit at
   its content height. Height="100%" on the grid itself is what makes its own internal scroller take
   the pane's height instead of the whole document's. */
.sq-split__list[b-m4wcn5gm4e]  .mud-table-container,
.sq-split__list[b-m4wcn5gm4e]  .mud-data-grid {
    flex: 1 1 auto;
    min-height: 0;
}

.sq-split__detail[b-m4wcn5gm4e] {
    flex: 0 0 clamp(380px, 40%, 620px);
    min-width: 0;
    min-height: 0;
    display: flex;
}

/* ::deep on the MudPaper and MudStack below: Blazor's CSS-isolation attribute is stamped on the HTML
   elements this component writes itself, never on a child component's own root, so a bare
   .sq-split__panel would silently match nothing. The plain divs above need no ::deep. */
.sq-split__detail[b-m4wcn5gm4e]  .sq-split__panel {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.sq-split__detail[b-m4wcn5gm4e]  .sq-split__header {
    flex: 0 0 auto;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background-color: var(--mud-palette-background-gray);
}

/* The pane's own scroll. overflow-x is pinned hidden because overflow-y:auto alone makes the browser
   compute overflow-x to auto too, producing a phantom horizontal scrollbar the moment a card is wider
   than the pane. The scroll behaviour itself — overscroll containment, stable gutter, thin bar —
   comes from the shared .app-scroll-pane rule; this class only carries the geometry. */
.sq-split__body[b-m4wcn5gm4e] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Below a laptop width .app-fixed-page has already handed the scroll back to the document, so the
   panes stack and neither one owns a height any more. Matching app.css's own breakpoint: two places
   disagreeing about where the model disengages is how a page ends up with no scrollbar at all. */
@media (max-width: 960px) {
    .sq-split[b-m4wcn5gm4e] {
        flex-direction: column;
        overflow: visible;
    }

    .sq-split__detail[b-m4wcn5gm4e] {
        flex: 1 1 auto;
        width: 100%;
    }

    .sq-split__detail[b-m4wcn5gm4e]  .sq-split__panel {
        max-height: 70vh;
    }
}
/* /Components/Pages/SongSearch/SearchTool.razor.rz.scp.css */
/* PBI 394 — the Search Tool's bands and rows.

   Two rules carry this page. What the customer submitted and what the catalogue offers sit in adjacent
   columns; and a row gets the density that matches what it needs from the agent — a nod, a decision,
   or a handoff.

   ON ::deep. Rows are rendered by SearchToolRowView, and Blazor's CSS-isolation attribute is stamped
   per component — so a plain `.st-row` here compiles to `.st-row[b-parent]` and matches nothing the
   child wrote. Everything row-level therefore hangs off `.st-bands ::deep`, anchored on a plain div
   this component owns. It also happens to cover the one table this component renders itself (the
   nothing-found band), so the rules live in one place rather than two. */

/* ============================================================================
   Bands — this component's own markup, so no ::deep needed
   ============================================================================ */
.st-bands[b-rhw87fc3i2] {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.st-band[b-rhw87fc3i2] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 6px;
    background: var(--mud-palette-surface);
    overflow: hidden;
}

.st-band-head[b-rhw87fc3i2] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 4px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    font-size: 0.875rem;
}

.st-band-title[b-rhw87fc3i2] { font-weight: 600; }

.st-band-count[b-rhw87fc3i2] {
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.st-band-spacer[b-rhw87fc3i2] { flex: 1 1 auto; }

/* The band's own colour says what it is without another chip to read. Kept to the header strip:
   tinting the rows as well would fight the difference grid, which uses tint to mean "the candidates
   disagree here" — one page should not say two things with the same device.

   Four bands, and the colour ramp is the amount of review each needs: settled, then two degrees of
   "look at this", then neutral for the ones this tool cannot answer at all. */
.st-band--exacttitleandartist .st-band-head[b-rhw87fc3i2] {
    background: var(--mud-palette-success-hover);
    color: var(--mud-palette-success-darken);
}

.st-band--exacttitlefuzzyartist .st-band-head[b-rhw87fc3i2] {
    background: var(--mud-palette-warning-hover);
    color: var(--es-warning-text);   /* PBI 1292 - app.css, WARNING AS TEXT */
}

.st-band--fuzzytitleandartist .st-band-head[b-rhw87fc3i2] {
    background: var(--mud-palette-error-hover);
    color: var(--mud-palette-error-darken);
}

.st-band--nomatch .st-band-head[b-rhw87fc3i2] {
    background: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-secondary);
}

/* The stage chips. A plain div rather than a MudStack carrying the class, so the isolation attribute
   actually lands on it — and the chips themselves are reached with ::deep for the same reason.
   Clickable, so they must not read as status badges: outlined until selected. */
.st-stages[b-rhw87fc3i2] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
}

.st-stages[b-rhw87fc3i2]  .st-stage { cursor: pointer; }

.st-band-sub[b-rhw87fc3i2] {
    font-size: 0.72rem;
    font-weight: 400;
    opacity: .85;
    white-space: nowrap;
}

.st-table[b-rhw87fc3i2] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 6px;
    background: var(--mud-palette-surface);
}

.st-state[b-rhw87fc3i2] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 22px 16px;
    font-size: 0.85rem;
    color: var(--mud-palette-text-secondary);
}

/* ============================================================================
   Rows — written by SearchToolRowView, so reached with ::deep
   ============================================================================ */
.st-bands[b-rhw87fc3i2]  table.st-rows {
    border-collapse: collapse;
    width: 100%;
    table-layout: fixed;
}

.st-bands[b-rhw87fc3i2]  table.st-rows--plain { table-layout: auto; }

.st-bands[b-rhw87fc3i2]  table.st-rows thead th {
    text-align: left;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    padding: 8px 14px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.st-bands[b-rhw87fc3i2]  table.st-rows td {
    padding: 10px 14px;
    border-bottom: 1px solid var(--mud-palette-lines-default);

    /* Top, not middle. A row can carry three candidates while its neighbour carries one, and centring
       would put the two things being compared on different baselines — the exact problem this layout
       exists to fix. */
    vertical-align: top;
}

.st-bands[b-rhw87fc3i2]  table.st-rows tbody tr:last-child > td { border-bottom: none; }

.st-bands[b-rhw87fc3i2]  .st-cell-tick { padding-right: 0; }
.st-bands[b-rhw87fc3i2]  .st-cell-action { text-align: right; white-space: nowrap; }

/* A ticked row is a nod, so it is a line rather than a block. */
.st-bands[b-rhw87fc3i2]  .st-row--compact > td { padding-top: 6px; padding-bottom: 6px; }

/* One line means one line: no wrap, and anything that will not fit is ellipsed rather than allowed to
   push the row to two. Thirty of these is meant to be a scan. */
.st-bands[b-rhw87fc3i2]  .st-oneline {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
    white-space: nowrap;
}

/* Composer and artist take whatever the title leaves, and give way before it does: the title has
   already been matched by construction, so it is the shorter read. */
.st-bands[b-rhw87fc3i2]  .st-oneline-fields {
    flex: 1 1 auto;
    min-width: 0;
}

.st-bands[b-rhw87fc3i2]  .st-oneline-title {
    font-size: 0.875rem;
    font-weight: 500;
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The artist is the part that gives way when the row runs out of room: the title has already been
   matched by construction, so the artist is the shorter read, and the publisher and track count
   behind it are the evidence an agent is actually spot-checking. */
.st-bands[b-rhw87fc3i2]  .st-oneline-sub {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.st-bands[b-rhw87fc3i2]  .st-oneline-meta {
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}

.st-bands[b-rhw87fc3i2]  .st-oneline-link {
    font-size: 0.7rem;
    flex: 0 0 auto;
}

.st-bands[b-rhw87fc3i2]  .st-submitted {
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.4;
}

/* ---- LABELLED PERSON FIELDS -------------------------------------------------------------------
   Composer and artist, on both the submitted and the catalogue side, with the label carried rather
   than inferred.

   The label earns its space because the two fields are NOT interchangeable to read even though
   customers fill them interchangeably: an agent checking a match has to know which name they are
   looking at. Sized and coloured to be skimmed past on every row after the first, and set as a
   two-column grid so the values line up in a column the eye can run down.

   `display: contents` on the pair is what puts the label and the value into the grid as separate
   cells while keeping them one element to write. */
.st-bands[b-rhw87fc3i2]  .st-fields {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: 8px;
    align-items: baseline;
    line-height: 1.4;
}

.st-bands[b-rhw87fc3i2]  .st-field { display: contents; }

.st-bands[b-rhw87fc3i2]  .st-field-label {
    font-size: 0.62rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mud-palette-text-disabled);
    white-space: nowrap;
}

.st-bands[b-rhw87fc3i2]  .st-field-value {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* The compact band runs them along one line instead of stacking them, so a ticked row stays two
   lines total. Values ellipse rather than wrap: thirty of these is meant to be a scan. */
.st-bands[b-rhw87fc3i2]  .st-fields--inline {
    display: flex;
    flex-wrap: nowrap;
    align-items: baseline;
    gap: 4px 12px;
    min-width: 0;
}

.st-bands[b-rhw87fc3i2]  .st-fields--inline .st-field {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    min-width: 0;
}

.st-bands[b-rhw87fc3i2]  .st-fields--inline .st-field-value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- THE TRACKS ONE DECISION WRITES TO --------------------------------------------------------
   A grouped row lists them rather than counting them, and every one is a way into the Search Queue,
   because the grouping is the tool's claim that these are the same question. */
.st-bands[b-rhw87fc3i2]  .st-members {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px;
    margin-top: 3px;
}

.st-bands[b-rhw87fc3i2]  .st-members-count {
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    font-variant-numeric: tabular-nums;
}

.st-bands[b-rhw87fc3i2]  .st-member {
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    color: var(--mud-palette-text-secondary);
    background: var(--mud-palette-background-grey);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 3px;
    padding: 0 4px;
    cursor: pointer;
}

.st-bands[b-rhw87fc3i2]  .st-member:hover {
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary);
}

.st-bands[b-rhw87fc3i2]  .st-member:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
}

.st-bands[b-rhw87fc3i2]  .st-submitted-sub {
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--mud-palette-text-secondary);
}

/* Reference data — track id, project number, album size. Real, occasionally needed, and not part of
   any decision on this page. Sized to be readable when looked for and invisible when not, rather than
   competing with the comparison beside it. */
.st-bands[b-rhw87fc3i2]  .st-refmeta {
    font-size: 0.7rem;
    line-height: 1.45;
    color: var(--mud-palette-text-disabled);
    font-variant-numeric: tabular-nums;
}

.st-bands[b-rhw87fc3i2]  .st-empty {
    color: var(--mud-palette-text-disabled);
    font-style: italic;
}

/* An open comparison and its summary row are one unit, so the summary loses its bottom rule and the
   pair share a tint. Without this the expansion reads as an unrelated block that happens to follow. */
.st-bands[b-rhw87fc3i2]  .st-row--comparing > td {
    background: var(--mud-palette-background-gray);
    border-bottom: none;
}

.st-bands[b-rhw87fc3i2]  .st-expansion > td {
    padding: 0 14px 14px;
    background: var(--mud-palette-background-gray);
}

/* ============================================================================
   Controls set through a component's Class= parameter
   ============================================================================ */
.st-bands[b-rhw87fc3i2]  .st-compare {
    display: inline-block;
    margin-top: 6px;
    font-size: 0.72rem;
}

.st-bands[b-rhw87fc3i2]  .st-band-action {
    font-size: 0.72rem;
    text-transform: none;
    letter-spacing: 0;
    color: inherit;
}


/* Below a laptop width the five columns cannot all hold their content, so each band's table scrolls
   sideways inside its own box rather than pushing the page. Horizontal only — the vertical scroll
   stays with the document, which is what makes a long worklist readable on a short screen. */
/* The band owns its scroll, so <Virtualize> has a height to measure — and so a 535-row band does not
   push the filter bar and the stage chips off the top of the screen while you work it.

   70vh rather than chrome arithmetic: subtracting a fixed app-bar height from the viewport is the
   habit Bug 389 exists to stop, and a fraction needs no knowledge of what is above it.

   overscroll-behavior, the stable gutter and the thin bar come from the shared .app-scroll-pane rule
   in app.css; this class carries only the geometry. */
.st-band-body[b-rhw87fc3i2] {
    max-height: 70vh;
    overflow-y: auto;
    overflow-x: hidden;
}

@media (max-width: 1279px) {
    .st-band-body[b-rhw87fc3i2] { overflow-x: auto; }
    .st-bands[b-rhw87fc3i2]  table.st-rows { min-width: 1100px; }
    .st-bands[b-rhw87fc3i2]  table.st-rows--plain { min-width: 0; }
}
/* /Components/Pages/SongSearch/SearchToolCandidateStack.razor.rz.scp.css */
/* PBI 394 — the candidate stack inside a Search Tool row.

   Every rule here exists to make three lines comparable at a glance: same left edge, same field order,
   same colour for the same kind of fact. The chosen one is the only thing that changes weight. */

.st-stack[b-wx3jswj6sq] {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.st-cand[b-wx3jswj6sq] {
    padding: 6px 10px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 7px;
    background: var(--mud-palette-background-gray);
    cursor: pointer;
    transition: border-color 120ms ease, background-color 120ms ease;
}

.st-cand:hover[b-wx3jswj6sq] { border-color: var(--mud-palette-primary); }

/* Keyboard focus has to be visible: the candidate is a radio, and a keyboard user who cannot see which
   one they are on cannot use it (WCAG 2.4.7). */
.st-cand:focus-visible[b-wx3jswj6sq] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
}

.st-cand--chosen[b-wx3jswj6sq] {
    border-color: var(--mud-palette-primary);
    background: var(--mud-palette-primary-hover);
}

.st-cand-line[b-wx3jswj6sq] {
    display: flex;
    align-items: baseline;
    gap: 7px;
    flex-wrap: wrap;
}

.st-cand-title[b-wx3jswj6sq] {
    font-weight: 500;
    font-size: 0.875rem;
}

/* Composer and artist, labelled, aligned under the title rather than under the radio so the two
   values form a column the eye can run down across three candidates. */
.st-cand-fields[b-wx3jswj6sq] {
    margin-left: 20px;
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: 8px;
    align-items: baseline;
    line-height: 1.45;
}

/* Indented to the title's left edge rather than the radio's, so the eye reads a column of
   publisher / track-count / codes down the stack instead of a ragged one. */
.st-cand-meta[b-wx3jswj6sq] {
    margin-left: 20px;
    font-size: 0.72rem;
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

.st-dot[b-wx3jswj6sq] { margin: 0 5px; opacity: .5; }

.st-sub[b-wx3jswj6sq] {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
}

.st-empty[b-wx3jswj6sq] {
    color: var(--mud-palette-text-disabled);
    font-style: italic;
}

.st-warn[b-wx3jswj6sq] { color: var(--es-warning-text); }   /* PBI 1292 - app.css, WARNING AS TEXT */

.st-more[b-wx3jswj6sq] {
    font-size: 0.72rem;
    color: var(--mud-palette-text-disabled);
    padding-left: 2px;
}

.st-radio[b-wx3jswj6sq] {
    display: inline-block;
    flex: 0 0 auto;
    width: 13px;
    height: 13px;
    border: 1.5px solid var(--mud-palette-text-disabled);
    border-radius: 50%;
    align-self: center;
}

.st-radio--on[b-wx3jswj6sq] {
    border-color: var(--mud-palette-primary);
    border-width: 4px;
}
/* /Components/Pages/SongSearch/SearchToolDifferenceGrid.razor.rz.scp.css */
/* PBI 394 — the difference grid.

   Everything here serves one reading: run your eye down the tinted rows and the decision is made. The
   tint is on disagreement, not on "bad" — a differing field is where the information is. */

.st-diff[b-rz29d5vnyy] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-surface);
    overflow: hidden;
}

.st-diff-head[b-rz29d5vnyy] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 12px;
    padding: 9px 14px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-background-gray);
}

.st-diff-title[b-rz29d5vnyy] { font-weight: 600; font-size: 0.9rem; }

.st-diff-sub[b-rz29d5vnyy] {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
}

.st-diff-meta[b-rz29d5vnyy] {
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    font-variant-numeric: tabular-nums;
}

/* The grid is wider than a narrow viewport on a three-candidate row, so it scrolls inside its own
   container — the page body must never scroll sideways. */
.st-diff-scroll[b-rz29d5vnyy] { overflow-x: auto; }

table.st-cmp[b-rz29d5vnyy] {
    border-collapse: collapse;
    width: 100%;
    min-width: 720px;
    font-size: 0.8rem;
}

table.st-cmp th[b-rz29d5vnyy],
table.st-cmp td[b-rz29d5vnyy] {
    text-align: left;
    vertical-align: top;
    padding: 6px 14px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

table.st-cmp thead th[b-rz29d5vnyy] {
    font-size: 0.68rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.st-field[b-rz29d5vnyy] {
    font-size: 0.68rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--mud-palette-text-disabled);
    white-space: nowrap;
}

col.st-col-field[b-rz29d5vnyy] { width: 140px; }
col.st-col-ref[b-rz29d5vnyy]   { width: 20%; background: var(--mud-palette-background-gray); }
col.st-col-picked[b-rz29d5vnyy] { background: var(--mud-palette-primary-hover); }

.st-ref[b-rz29d5vnyy] { color: var(--mud-palette-text-secondary); }

/* The tint marks "the candidates disagree here", which is the only thing that can decide the row.
   Deliberately not a warning colour: disagreement is information, not a problem. */
.st-differs > td:not(.st-ref)[b-rz29d5vnyy],
.st-differs > th.st-field[b-rz29d5vnyy] {
    background: var(--mud-palette-action-default-hover);
}

.st-strong[b-rz29d5vnyy] { font-weight: 700; }

.st-agrees[b-rz29d5vnyy] { opacity: .72; }

.st-agree[b-rz29d5vnyy] {
    font-size: 0.72rem;
    color: var(--mud-palette-text-disabled);
    background: var(--mud-palette-surface);
}

.st-diff-warn[b-rz29d5vnyy] { color: var(--es-warning-text); font-weight: 400; }   /* PBI 1292 - app.css, WARNING AS TEXT */

.st-pick > td[b-rz29d5vnyy] { padding-top: 10px; padding-bottom: 12px; }
.st-pick > th[b-rz29d5vnyy], .st-pick > td[b-rz29d5vnyy] { border-bottom: none; }

.st-diff-foot[b-rz29d5vnyy] {
    padding: 7px 14px;
    font-size: 0.72rem;
    color: var(--mud-palette-text-disabled);
    border-top: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-background-gray);
}
/* /Components/Pages/SongSearch/SearchToolMatchedValue.razor.rz.scp.css */
/* PBI 394 — the agreement tick.

   Quiet on purpose. It appears on most candidates in the ticked band, so anything louder would become
   the page's dominant texture and stop being read — which is exactly what happened to the first build's
   highlight. Green because it is the only semantic colour on this page that means "agrees"; the
   difference grid's tint means "these disagree", and the two must not be confusable. */
.st-agree-mark[b-79i5f6zf49] {
    color: var(--mud-palette-success);
    font-size: 0.72em;
    margin-right: 3px;
    vertical-align: 1px;
}

.st-empty[b-79i5f6zf49] {
    color: var(--mud-palette-text-disabled);
    font-style: italic;
}
/* /Components/Shared/SortableLookupTable.razor.rz.scp.css */
.sortable-lookup-table[b-29d5iuf636] {
    width: 100%;
    user-select: none;
}

.sortable-lookup-grid[b-29d5iuf636] {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 4px;
    overflow: hidden;
    font-size: 0.875rem;
}

/* The ::deep combinator is required because the consumer renders <th> / <td> elements
   via the Headers and RowTemplate RenderFragments. Blazor's scoped CSS only marks
   elements that this component renders directly, so without ::deep the th/td styling
   falls back to browser defaults (centered headers, no padding, etc.). */
.sortable-lookup-grid[b-29d5iuf636]  thead th {
    text-align: left;
    padding: 8px 10px;
    background: var(--mud-palette-background-grey);
    color: var(--mud-palette-text-secondary);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    font-weight: 500;
}

.sortable-lookup-grid[b-29d5iuf636]  tbody td {
    padding: 6px 10px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    vertical-align: middle;
    background: var(--mud-palette-surface);
}

.sortable-lookup-grid[b-29d5iuf636]  tbody tr:last-child td {
    border-bottom: none;
}

.sortable-lookup-row:hover[b-29d5iuf636]  td {
    background: var(--mud-palette-action-default-hover);
}

.sortable-lookup-handle-col[b-29d5iuf636],
.sortable-lookup-handle-cell[b-29d5iuf636] {
    width: 32px;
    padding: 0 4px;
    text-align: center;
}

.sortable-lookup-handle[b-29d5iuf636] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    color: var(--mud-palette-text-secondary);
    padding: 4px;
    border-radius: 4px;
}

.sortable-lookup-handle:hover[b-29d5iuf636] {
    color: var(--mud-palette-text-primary);
    background: var(--mud-palette-action-default-hover);
}

/* Active drag: switch the cursor on the handle itself (only the handle is draggable
   in this component, unlike TabStrip where the whole tab is). */
.sortable-lookup-table.is-dragging .sortable-lookup-handle[b-29d5iuf636] {
    cursor: grabbing;
}

.sortable-lookup-handle.is-disabled[b-29d5iuf636] {
    cursor: not-allowed;
    color: var(--mud-palette-text-disabled);
    opacity: 0.5;
}

.sortable-lookup-handle.is-disabled:hover[b-29d5iuf636] {
    background: transparent;
    color: var(--mud-palette-text-disabled);
}

/* The row currently being dragged is dimmed so the user tracks where it will land
   rather than where it's leaving from. ::deep so the opacity reaches consumer cells. */
.sortable-lookup-row.is-row-dragging[b-29d5iuf636]  td {
    opacity: 0.4;
}

/* Drop indicator: a 2px primary-color rule along the top/bottom edge of the row where
   the dragged item will land. Using inset box-shadow avoids the cross-browser position:
   relative-on-tr quirk and keeps the row from shifting layout when the indicator
   appears. ::deep so the shadow paints on consumer-owned cells too. */
.sortable-lookup-row.drop-above[b-29d5iuf636]  td {
    box-shadow: inset 0 2px 0 0 var(--mud-palette-primary);
}

.sortable-lookup-row.drop-below[b-29d5iuf636]  td {
    box-shadow: inset 0 -2px 0 0 var(--mud-palette-primary);
}
/* /Components/Shared/TrackerPlayBar.razor.rz.scp.css */
.tracker-play-bar[b-o8apt77qul] {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 4px 12px;
    margin-bottom: 8px;
    border: 1px solid var(--mud-palette-primary);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-primary-hover);
    font-size: 0.875rem;
    /* Stays reachable while the agent scrolls a long request or release. */
    position: sticky;
    top: 0;
    z-index: 5;
}

.tracker-play-count[b-o8apt77qul] {
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}
