/* ========================================
   BrokerApp - application styles

   The layout, colour and component rules that used to live here have moved to MudBlazor:
   the shell is Components/Layout/MainLayout.razor and the palette is Theme/BrokerAppTheme.cs.

   Removed deliberately, because each was a live bug:
     - .app-shell / .app-body / .app-main   three nested scroll containers that fought each
                                            other, so mobile pages often would not scroll
                                            to the end
     - .app-sidebar { top: 73px }           a hardcoded header height that is wrong below
                                            768px, leaving a dead unclickable strip
     - min-height: 100vh (everywhere)       excludes the mobile address bar, putting the
                                            bottom action bar out of reach
     - .container-fluid { padding: .25rem } a global override that pushed content flush
                                            against the screen edge on phones
     - the literal hex palette              repeated across ~544 lines and layered over
                                            Bootstrap with !important

   What remains is only what MudBlazor does not provide: Blazor's own validation and error
   styling, and a small number of helpers still referenced by pages that have not yet been
   migrated. Delete the transitional block once the last page is converted.
   ======================================== */

html, body {
    margin: 0;
    padding: 0;
}

h1:focus {
    outline: none;
}

/* ========================================
   Blazor framework styles
   ======================================== */

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    /* Above MudBlazor's drawer and overlay so the error bar is never buried. */
    z-index: 2000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

/* ========================================
   Utilities
   ======================================== */

/* The drawer's user card is a link to the profile. Inherits its colour so it
   reads as part of the drawer rather than as body-text link. */
.drawer-user-card {
    display: block;
    color: inherit;
    text-decoration: none;
}

    .drawer-user-card:hover {
        background-color: var(--mud-palette-action-default-hover);
        color: inherit;
    }

/* The mark and name in the app bar, wrapped in one anchor back to the dashboard.

   display: contents means the anchor generates no box of its own: the emblem and
   the name remain flex items of the app bar exactly as they were before the link
   was added, so none of the app bar's spacing or alignment changes. An anchor that
   laid itself out as a flex row here became a flex item in its own right and
   shifted everything after it. */
.app-home-link {
    display: contents;
}

    .app-home-link > * {
        cursor: pointer;
        color: inherit;
        text-decoration: none;
    }

    .app-home-link:hover > * {
        opacity: .85;
    }

    /* With no box of its own, the anchor cannot carry the focus ring - so its
       children show it instead. */
    .app-home-link:focus-visible > * {
        outline: 2px solid var(--mud-palette-primary);
        outline-offset: 2px;
        border-radius: 4px;
    }

/* Spins an icon in place, for buttons whose own icon indicates progress rather
   than sitting next to a separate spinner. */
.icon-spin {
    display: inline-block;
    animation: icon-spin 1s linear infinite;
}

@keyframes icon-spin {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg);
    }
}

/* Anyone who has asked for less motion gets a still icon; the button's label
   changes while it works, so progress is still visible. */
@media (prefers-reduced-motion: reduce) {
    .icon-spin {
        animation: none;
    }
}

/* A tab strip sits on the page background, not on its own sheet of paper.

   MudTabs gives its toolbar a surface colour by default. Stacked above a card that is the same
   colour, the two run together into one white block: the panel's top padding is still there but
   you cannot see it, and the card's top corners have nothing to round against - which is why the
   strip and the content looked welded together with square corners.

   Clearing the toolbar background lets the warm page colour show through. That turns the panel's
   padding into a visible gap and puts the card back on its own rounded surface.

   The background sits on the component root as well as the toolbar, so both are cleared here -
   targeting only the toolbar leaves the root painting the same white behind everything and looks
   like nothing happened.

   This is here rather than in Profile.razor.css because CSS isolation never stamps its scope
   attribute onto a child component's markup - the toolbar is MudTabs' own HTML, not the page's,
   so a scoped rule would never match it. */
.page-tabs,
.page-tabs .mud-tabs-toolbar,
.page-tabs .mud-tabs-panels {
    background-color: transparent !important;
    box-shadow: none !important;
}

/* The gap itself is NOT set here. It is a margin on the card inside each panel - markup this app
   owns - because a rule that depends on MudBlazor's internal class names silently does nothing
   when one of those names is wrong, and a missing gap then looks identical to a missing rule. */

/* A whole row (or card) that navigates to its own detail page.

   The record's name inside it stays a real link - that is what carries keyboard focus,
   middle-click "open in new tab" and the status-bar URL preview, none of which a click handler
   can offer. This only widens the target to the rest of the row for a mouse or a thumb, which
   matters most on a phone where the name alone is a small thing to hit.

   Any control inside that goes somewhere else must stop the click propagating, or both fire. */
.clickable-row {
    cursor: pointer;
}

    /* The name inside reads as ordinary text, not as a link.

       It IS a link, and deliberately so - that is what carries keyboard focus, middle-click
       "open in new tab" and the status-bar URL preview. But the whole row already navigates, so
       colouring and underlining one cell would suggest that cell goes somewhere different from
       the rest of the row. The row's hover state is the affordance; the anchor is plumbing.

       !important is needed to beat MudLink, whose own classes are more specific than this
       selector can be without naming them - and naming MudBlazor's internal classes is how a
       rule silently stops working after an upgrade. */
    .clickable-row a {
        color: inherit !important;
        text-decoration: none !important;
    }

/* A shipment that has arrived with no entry number against it: it has to be lodged, and until it
   is, every day it sits there is a storage charge somebody will have to explain.

   Here in app.css rather than beside the page, because the class lands on a <tr> that MudTable
   renders. CSS isolation only reaches a component's own markup, so a scoped rule would need
   ::deep and would be naming another component's internals to do it.

   A tinted row and a left edge, not red text. The row stays as readable as any other - the point
   is to make it findable while scrolling, not to make it harder to read once found. The tint is
   deliberately light; a dozen shouting rows are the same as none. */
.entry-overdue {
    background-color: var(--mud-palette-error-hover);
    box-shadow: inset 3px 0 0 0 var(--mud-palette-error);
}

    /* Hover has to be restated. MudTable's own hover background is more specific than the rule
       above, so without this the tint disappears under the cursor - exactly when somebody is
       looking at the row. */
    .entry-overdue:hover {
        background-color: var(--mud-palette-error-hover) !important;
    }

/* Cancelled: still listed, because it happened, but nobody is going to lodge it. */
.entry-cancelled {
    opacity: 0.55;
}

/* Printing drops the application shell.

   The app bar, the drawer and the main content's padding belong to MainLayout, so a print
   stylesheet scoped to a page component cannot touch them - CSS isolation never reaches another
   component's markup. Without this, a printed payslip carries a navigation drawer down its left
   edge and wastes an inch of every sheet.

   Anything a page does not want on paper carries Bootstrap's d-print-none. */
@media print {
    .mud-appbar,
    .mud-drawer,
    .mud-overlay,
    .page-action-bar {
        display: none !important;
    }

    .mud-main-content,
    .mud-layout {
        padding: 0 !important;
        margin: 0 !important;
    }

    body,
    .mud-layout {
        background: #fff !important;
    }
}

/* ========================================
   TRANSITIONAL - for pages not yet migrated to MudBlazor

   Every rule below exists only to keep Bootstrap-markup pages readable inside the MudBlazor
   shell. Delete this whole block, and the Bootstrap links in App.razor, when the last page
   is converted.
   ======================================== */

/* Bootstrap sets a white body background that fights the MudBlazor theme surface. */
.mud-main-content .card {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

/* One section-header tint for both the Bootstrap card-header (pages not yet converted) and the
   MudCardHeader, a warm step darker than the surface so the sections read as sections. */
:root {
    --section-header-bg: color-mix(in srgb, var(--mud-palette-primary) 14%, var(--mud-palette-surface));
}

.mud-main-content .card-header,
.mud-card-header {
    background-color: var(--section-header-bg);
}

.mud-main-content .card-header {
    color: var(--mud-palette-text-primary);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    font-weight: 600;
}

.mud-main-content .table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--mud-palette-text-primary);
    color: var(--mud-palette-text-primary);
}

.mud-main-content .table > :not(caption) > * > * {
    border-bottom-color: var(--mud-palette-table-lines);
}

.mud-main-content .table-light,
.mud-main-content .table > thead > tr > th {
    background-color: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-secondary);
}

.mud-main-content .form-control,
.mud-main-content .form-select {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-lines-inputs);
    min-height: 2.75rem;
}

.mud-main-content .form-control:focus,
.mud-main-content .form-select:focus {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-primary);
    box-shadow: none;
}

/* ----------------------------------------------------------------------
   View mode reads as text, not as a page full of greyed-out boxes.

   A disabled fieldset is what enforces view mode on the detail pages (it
   blocks keyboard access, which the old "pe-none" class did not). But the
   default rendering turns every field into a dimmed input, so a record you
   are simply *looking at* appears broken or switched off.

   These rules strip the control chrome - border, fill, padding, the select
   chevron, the date picker button - and restore full text contrast, so a
   field in view mode reads as a label above a value. The inputs are still
   there and still disabled; they just stop shouting.

   When these pages are migrated to MudBlazor they will render actual text
   in view mode rather than flattened inputs. Until then this is the fix.
   ---------------------------------------------------------------------- */

.mud-main-content fieldset[disabled] .form-control,
.mud-main-content fieldset[disabled] .form-select {
    padding-left: 0;
    padding-right: 0;
    min-height: 0;
    color: var(--mud-palette-text-primary);
    background-color: transparent;
    border-color: transparent;
    box-shadow: none;
    opacity: 1;
    font-weight: 500;
}

    /* Nothing to open, so drop the chevron. */
    .mud-main-content fieldset[disabled] .form-select {
        background-image: none;
    }

    /* Nothing to pick, so drop the calendar button. */
    .mud-main-content fieldset[disabled] input[type="date"]::-webkit-calendar-picker-indicator,
    .mud-main-content fieldset[disabled] input[type="time"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    /* Spinners on a read-only number are noise. */
    .mud-main-content fieldset[disabled] input[type="number"]::-webkit-outer-spin-button,
    .mud-main-content fieldset[disabled] input[type="number"]::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
    }

    .mud-main-content fieldset[disabled] input[type="number"] {
        -moz-appearance: textfield;
        appearance: textfield;
    }

    /* An upload button means nothing when you cannot upload. The adjacent
       "Current: <filename>" text still shows what is attached. */
    .mud-main-content fieldset[disabled] input[type="file"] {
        display: none;
    }

    /* Switches and checkboxes stay legible rather than washed out - they are
       carrying a yes/no value the reader needs. */
    .mud-main-content fieldset[disabled] .form-check-input {
        opacity: 1;
    }

    /* Labels become the caption above each value. */
    .mud-main-content fieldset[disabled] .form-label {
        margin-bottom: 0.125rem;
        color: var(--mud-palette-text-secondary);
        font-size: 0.8125rem;
    }

    /* Hint text only applies while editing. */
    .mud-main-content fieldset[disabled] .form-text {
        display: none;
    }

/* ========================================
   Text utilities

   MudBlazor ships utilities for spacing, display and flexbox, and those are used as-is. It does
   NOT ship text alignment or font weight - Bootstrap was quietly providing those, so they are
   defined here now that it is gone.

   Deliberately NOT redefined here: mb-*, pa-*, gap-*, d-flex, justify-*, align-*. MudBlazor's
   spacing scale steps in 4px where Bootstrap's stepped in 4-48px, so redefining those names
   would silently resize every already-migrated page that uses them.
   ======================================== */

.text-start  { text-align: left; }
.text-center { text-align: center; }
.text-end    { text-align: right; }

.fw-normal   { font-weight: 400; }
.fw-semibold { font-weight: 600; }
.fw-bold     { font-weight: 700; }

.text-nowrap { white-space: nowrap; }

/* Reads from the theme, so it follows dark mode instead of being a fixed grey. */
.text-muted {
    color: var(--mud-palette-text-secondary);
}

/* Present to a screen reader, invisible on screen. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* One receivable - a loan or a cash advance - inside an employee's card.

   Shared rather than scoped to one page: both screens present the same shape, and a scoped copy
   in each would be two definitions that drift apart the first time one is adjusted. Scoped CSS
   applies only to the component it is named for, so these class names did nothing at all on the
   second page until this moved here.

   A flex row rather than a table: the loans under one employee are a short list of objects, not
   a grid of comparable values, and a table would force the expanded payment history to live in
   a colspan cell pretending to be a row. */

.ledger-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 1rem;
    border-top: 1px solid var(--mud-palette-lines-default);
}

    /* The first loan sits directly under the card header, which already has its own rule. */
    .ledger-row:first-of-type {
        border-top: none;
    }

.ledger-row-main {
    flex: 1 1 auto;
    min-width: 0;
}

.ledger-row-progress {
    flex: 0 0 9rem;
}

.ledger-row-balance {
    flex: 0 0 6rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.ledger-row-actions {
    flex: 0 0 auto;
    display: flex;
    gap: 0.15rem;
}

/* The payment history, indented under the loan it belongs to and on a slightly recessed
   surface so it reads as detail of the row above rather than as another loan. */
.ledger-detail {
    padding: 0.5rem 1rem 0.9rem 3.25rem;
    background-color: var(--mud-palette-background-gray);
    border-top: 1px solid var(--mud-palette-lines-default);
}

/* Below sm the row would squeeze the progress bar and balance into unreadable slivers, so it
   stacks instead: identity first, then the numbers, then the actions. */
@media (max-width: 599.98px) {
    .ledger-row {
        flex-wrap: wrap;
    }

    .ledger-row-main {
        flex: 1 1 100%;
        order: 1;
    }

    .ledger-row-progress {
        flex: 1 1 auto;
        order: 2;
    }

    .ledger-row-balance {
        flex: 0 0 auto;
        order: 3;
    }

    .ledger-row-actions {
        order: 4;
        margin-left: auto;
    }

    .ledger-detail {
        padding-left: 1rem;
    }
}

/* The payroll totals panel: a statement, not a table.

   Rows are flex pairs rather than table cells because nothing here is tabular - it is a list of
   labels with one figure each, and a table brings borders, cell padding and a header row that all
   have to be argued back down again.

   Lines worth nothing are dimmed rather than hidden. On a twenty-two line statement the eye
   should land on what is actually carrying money, but a payroll reader still needs to see that a
   line exists and is zero, not wonder whether it was left out. */
.totals-group {
    margin: 1rem 0 0.35rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

    .totals-group:first-child {
        margin-top: 0;
    }

.totals-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.2rem 0;
    font-size: 0.875rem;
}

    .totals-line.is-zero {
        opacity: 0.45;
    }

/* Tabular figures so the decimal points line up down the column, which is the whole reason a
   statement is readable at a glance. */
.totals-amount {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.totals-subtotal {
    margin-top: 0.35rem;
    padding-top: 0.45rem;
    border-top: 1px solid var(--mud-palette-lines-default);
    font-weight: 600;
}

/* Net pay sits in the card footer: the answer the card is working towards, and the one place it
   cannot be mistaken for another component of a subtotal. */
.totals-net {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    font-weight: 700;
    font-size: 1.0625rem;
}

/* Daily time record grid: the hours box keeps a fixed narrow width inside its input group.

   Bootstrap gives every .form-control in an input group "flex: 1 1 auto", so the hours field and
   the two payment-type selects beside it would each take a third of the column - leaving the
   selects too narrow to read their own options while the hours box sits mostly empty.

   Selector is ".input-group > .dtr-hours" rather than ".dtr-hours" on purpose: it has to match
   Bootstrap's own ".input-group > .form-control" specificity to override it, and app.css is
   loaded after Bootstrap, so an equal-specificity rule wins. */
.input-group > .dtr-hours {
    flex: 0 0 4.75rem;
    width: 4.75rem;

    /* Bootstrap's 0.75rem side padding costs 24px of a 76px box. Trimmed so "0.00" has room
       without widening the column and squeezing the selects beside it. */
    padding-left: 0.35rem;
    padding-right: 0.35rem;
}

/* Table cells inside a view-mode fieldset (the payroll delivery grid) should
   sit flush rather than keeping input-sized padding. */
.mud-main-content fieldset[disabled] td .form-control {
    text-align: inherit;
}

/* The save/cancel bar on a long detail page, pinned to the bottom of the screen.

   position: sticky rather than fixed, for three reasons:
     - it spans the content column on its own, with no need to offset it by the drawer's width
       and no need to recompute that when the drawer opens or closes;
     - it keeps its place in the layout, so it reserves its own space and nothing ends up hidden
       behind it - a fixed bar needs the page padded by hand to match its height, and that padding
       silently goes wrong the moment the bar wraps to two lines;
     - it stops at the end of the content instead of hovering over the page footer.

   The parent must not have overflow hidden, or sticky quietly stops working. */
.page-action-bar {
    position: sticky;
    bottom: 0;
    z-index: 3;

    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;

    margin-top: 1rem;
    padding: 0.75rem 1rem;
    /* Clears the home indicator on a phone. */
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));

    background: var(--mud-palette-surface);
    border-top: 1px solid var(--mud-palette-lines-default);
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
}

/* Thumb-sized targets on a phone: the buttons share the width instead of huddling on the left. */
@media (max-width: 575.98px) {
    .page-action-bar .btn {
        flex: 1 1 auto;
    }
}

@media print {
    .page-action-bar {
        display: none;
    }
}



/* Section headers on cards (Release, Entry, Cargo, Delivery Orders...). Heavier title, a
   primary-coloured accent bar and a rule beneath, so the sections read as sections. */
.mud-card-header {
    border-bottom: 1px solid var(--mud-palette-lines-default);
    border-left: 4px solid var(--mud-palette-primary);
}

.mud-card-header .mud-typography-subtitle1 {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

/* Action buttons (Save, Cancel, Edit, Update...) sit at the right edge, on card footers and the
   sticky page bar alike. Dialog actions are already right-aligned by MudBlazor. */
.mud-card-actions,
.page-action-bar {
    justify-content: flex-end;
}