html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #006bb7;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.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."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}
/* ==========================================================================
   Split-panel workspace
   A list above an editor, with a divider dragged up and down between them.
   MudSplitPanel's Horizontal=true means the dividing line is horizontal, so the
   panes stack rather than sitting side by side.
   ========================================================================== */

/* MudSplitPanel lays its panels out inside a fixed-height box, so without a
   height it collapses to nothing.

   FALLBACK ONLY. Subtracting a guessed offset from the viewport is what this
   used to do, and the guess was always wrong for one page or the other. The
   flex rules below replace it; this stays so the split is still usable in a
   browser without :has() support rather than collapsing to nothing. */
.workspace-split {
    height: calc(100dvh - var(--workspace-offset, 320px));
    min-height: 460px;
}

/* Fill the window instead.

   The split needs a definite height, and the only honest source of one is the
   space actually left below the page's own header. That means flex the whole way
   down - main content, container, the page's wrapper - because a flex item can
   only claim leftover space if every ancestor is handing it out.

   Scoped with :has() so it applies only to pages carrying .workspace-fill.
   Applying it to the layout globally would trap every other page inside a
   100dvh box and break normal scrolling. */
.mud-main-content:has(.workspace-fill) {
    display: flex;
    flex-direction: column;

    /* dvh, not vh: on a laptop with a hiding toolbar, vh is the larger value and
       the bottom of the split would sit under the browser chrome. */
    height: 100dvh;
}

.mud-main-content:has(.workspace-fill) > .mud-container {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;

    /* Without this a flex item refuses to shrink below its content, so a long
       grid would push the bottom of the split off screen. */
    min-height: 0;
}

/* The operator footer sits alongside the page's own container inside main
   content, so the rule above would otherwise hand it an equal share of the
   height. It takes what it needs and the split gets the rest. Same specificity
   as the rule above, and later, so it wins. */
.mud-main-content:has(.workspace-fill) > .platform-footer {
    display: block;
    flex: 0 0 auto;
    min-height: 0;
}

/* Breathing room between the last thing on a page and the footer, matching the
   16px (mb-4) that sits above a page's grid. Without it the bottom of a grid -
   or, on a split-panel page, the bottom of the pane - ran flush into the
   footer's rule. On those pages the container is the flex column sized to the
   window, so the padding shortens the split rather than adding a scrollbar. */
.mud-main-content > .mud-container {
    padding-bottom: 16px;
}

/* The footer belongs at the bottom of the window, not wherever a short page's
   content happens to end. A ten-row grid (Drivers, Trucks) used to leave the
   footer floating two-thirds of the way down with empty page beneath it.

   The main area is at least the window's height and a flex column, and the
   page's container grows to fill whatever the content does not, which pushes
   the footer to the bottom edge. On a long page the container is already
   taller than the window and none of this has any effect. border-box sizing
   (MudBlazor's) means the app bar's padding-top is inside the 100dvh, so this
   adds no scrollbar. The workspace rules above override it with a fixed
   height on split-panel pages, which pin the footer the same way. */
.mud-main-content {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

.mud-main-content > .mud-container {
    flex: 1 0 auto;
}

/* A real footer, stuck to the bottom of the viewport rather than left in normal
   document flow.

   Sticky, not fixed: fixed would sit on top of content on every page, even ones
   short enough that the footer has no business overlapping anything. Sticky
   only leaves normal flow once the page has scrolled enough that it would
   otherwise go offscreen; on a short page the rules above already put it at
   the bottom of the window.

   The opaque background and the border are what protect it from a grid-heavy
   page: without them, content that overflows its own scroll area (a bug in its
   own right - see .workspace-list-pane) would paint through a transparent
   footer instead of being hidden behind it. */
.platform-footer {
    position: sticky;
    bottom: 0;
    z-index: 5;
    background-color: var(--mud-palette-background);
    border-top: 1px solid var(--mud-palette-divider);
}

/* The pane is the only thing on a workspace page that may scroll sideways.

   Without this the grid's width propagates out through the container and the
   document itself starts scrolling horizontally. That looks broken in a
   particular way: the layout is sized to the viewport, so scrolling the page
   right slides the whole app left and exposes empty background beyond its right
   edge, while the grid stays clipped at the container edge it was always clipped
   at. Scrolling further never reveals the last column, because the page moving
   is not the grid scrolling.

   clip rather than hidden: hidden on one axis forces the other to auto, which
   would hand the container a vertical scrollbar it has no use for and split
   scrolling between it and the pane. clip leaves overflow-y visible, verified
   against MudBlazor 9.7 - the pane keeps its own horizontal scrollbar and the
   full width of the grid stays reachable.

   min-width: 0 for the same reason .workspace-pane carries it: a flex item
   refuses to shrink below its content unless told it may. */
.mud-main-content:has(.workspace-fill) > .mud-container {
    min-width: 0;
    overflow-x: clip;
}

/* The heading, the alert and the parameter card keep their natural height at the
   top: only the workspace absorbs what is left. Without this they would be
   squashed to make room when the window is short. */
.mud-main-content:has(.workspace-fill) > .mud-container > *:not(.workspace-fill) {
    flex: 0 0 auto;
}

.workspace-fill {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.workspace-fill > .workspace-split,
.workspace-fill > .workspace-list-pane {
    /* Overrides the fallback above: take the remaining height, whatever it is. */
    height: auto;
    flex: 1 1 auto;

    /* A floor, so a very short window overflows and scrolls rather than
       presenting a two-inch-tall editor. */
    min-height: 280px;
}

/* Each pane scrolls independently, overriding MudBlazor's own overflow: hidden.
   Without this the whole page scrolls and the divider drifts off screen, which
   defeats the point of the split.

   Deliberately no height: MudSplitPanel sizes the panes itself as the divider is
   dragged, and they are flex children of a column. Forcing height: 100% here made
   both panes demand the full height at once, so flex shrank them against each
   other and they settled near 50/50 - which is why the divider appeared to stop
   halfway. min-height: 0 is the opposite instruction: shrink as far as asked.

   The second selector is what actually beats MudBlazor inside the split:
   MudBlazor 9 ships .mud-split-panel .child-panel { overflow: hidden }, which
   outranks a bare .workspace-pane, so with an editor open neither the grid nor
   the editor could scroll at all. The bare selector still covers the list pane
   on its own, before anything is opened. */
.workspace-pane,
.mud-split-panel .child-panel.workspace-pane {
    overflow: auto;
    min-height: 0;
    min-width: 0;
}

/* The pane is the horizontal scroller, not the table container inside it.

   MudBlazor ships .mud-table-container { width: 100%; overflow-y: auto } and
   leaves overflow-x alone, which per the overflow spec computes it to auto - so
   the container becomes a horizontal scroller. That is fine on an ordinary page
   and useless here: the container is as tall as a whole page of rows, so its
   scrollbar is drawn at the bottom of the table, tens of thousands of pixels
   below the bottom of the pane the table is scrolling inside. Measured on the
   loads ledger the bar sat 85px past the pane's last visible row - reachable
   only by scrolling to the end of the page of rows, which is to say not at all.
   The columns on the right simply looked truncated with no way to reach them.

   Setting BOTH axes to visible is what matters: leaving either one non-visible
   would make the other compute back to auto and re-create the trapped bar. With
   the container transparent to overflow, the table's width propagates out to
   .workspace-pane, which is the element actually bounded to the window, and its
   own overflow: auto puts the scrollbar along the bottom edge of the pane where
   it belongs.

   Safe because nothing in the application uses FixedHeader/FixedFooter, which is
   the feature that would need the container to be the scroll port. */
.workspace-pane .mud-table-container {
    overflow-x: visible;
    overflow-y: visible;
}

/* In a split pane the header sticks to the top of the pane, not below the app
   bar: the pane is the scroller (above), and with the table container made
   transparent to overflow there is nothing between the header and the pane to
   trap it. See Sticky grid headers for the rule this overrides. */
.workspace-pane .mud-table-root .mud-table-head th.mud-table-cell {
    top: 0;
}

.workspace-editor {
    height: 100%;
}

/* The drag handle. MudBlazor styles the divider as a bare gap, which against
   transparent panels leaves nothing to see or aim at.

   The grip is drawn with a background image rather than a positioned ::after,
   because MudSplitPanel positions the divider itself and adding position:
   relative here could fight it. */
.workspace-divider {
    background-color: var(--mud-palette-divider);
    background-image: linear-gradient(
        var(--mud-palette-text-secondary),
        var(--mud-palette-text-secondary));
    background-repeat: no-repeat;
    background-position: center;
    background-size: 56px 2px;
    border-radius: 3px;
    transition: background-color 120ms ease;
}

.workspace-divider:hover {
    background-color: var(--mud-palette-primary-hover);
}

/* Held: unambiguous feedback that the drag has taken, since the panes move only
   as far as the pointer does. */
.workspace-divider:active {
    background-color: var(--mud-palette-primary);
}

/* The tab strip stays put while the editor beneath it scrolls. */
.workspace-editor-body {
    flex: 1 1 auto;
    overflow-y: auto;
}

/* Let it flow at phone width instead of confining it to the viewport. The panes
   already stack, so what hurts on a small screen is the fixed height: two
   scrolling boxes inside one short box leaves neither usable. Here the split and
   both panes take their natural height and the page scrolls as a whole. The office
   screens are not phone targets anyway. */
@media (max-width: 959.98px) {
    .workspace-split,
    .workspace-fill > .workspace-split,
    .workspace-fill > .workspace-list-pane {
        height: auto;
        min-height: 0;
        flex: 0 0 auto;
    }

    .workspace-pane {
        height: auto;
        overflow: visible;
    }

    .mud-main-content:has(.workspace-fill) {
        display: block;
        height: auto;
    }

    .workspace-fill {
        display: block;
    }
}

/* ==========================================================================
   Driver portal, phone first
   Drivers work from a handset, often one-handed and outdoors.
   ========================================================================== */

/* Softens the flash-of-grey when a whole card is tapped. */
.driver-shell {
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0.06);
}

/* The status colour carried over from the spreadsheet's row highlight. */
.driver-status-bar {
    height: 6px;
    width: 100%;
}

.driver-tap {
    cursor: pointer;

    /* Stops a tap being interpreted as the start of a text selection. */
    -webkit-touch-callout: none;
    user-select: none;
}

.driver-tap:active {
    background-color: var(--mud-palette-action-default-hover);
}

/* Facts wrap onto as many lines as they need rather than overflowing sideways.
   Horizontal scrolling inside a card is miserable on a phone. */
.driver-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
    font-size: 0.8125rem;
    color: var(--mud-palette-text-secondary);
}

.driver-facts > span {
    white-space: nowrap;
}

/* Label and value stacked in rows. A two-column table would either wrap badly or
   need side-scrolling at phone widths. */
.driver-detail-rows > div {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.375rem 0;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.driver-detail-rows > div:last-child {
    border-bottom: none;
}

.driver-detail-rows span {
    color: var(--mud-palette-text-secondary);
    font-size: 0.875rem;
}

.driver-detail-rows strong {
    text-align: right;
    word-break: break-word;
}

/* Comment thread. Driver messages sit right, office messages left, which reads
   the way every messaging app does. */
.driver-bubble {
    max-width: 88%;
    padding: 0.5rem 0.75rem;
    border-radius: 12px;
    background-color: var(--mud-palette-background-grey);
    align-self: flex-start;
    overflow-wrap: anywhere;
}

.driver-bubble-mine {
    align-self: flex-end;
    background-color: var(--mud-palette-primary-hover);
}

.driver-bubble-meta {
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 0.125rem;
}

.driver-bubble-flag {
    margin-left: 0.375rem;
    padding: 0 0.375rem;
    border-radius: 8px;
    background-color: var(--mud-palette-warning);
    color: var(--mud-palette-warning-text);
    font-size: 0.6875rem;
    text-transform: uppercase;
}

/* The primary actions stay within thumb reach instead of scrolling away.
   env(safe-area-inset-bottom) clears the iPhone home indicator, which otherwise
   sits on top of the buttons. */
.driver-sticky-actions {
    position: sticky;
    bottom: 0;
    z-index: 2;
    margin: 0 -0.5rem;
    padding: 0.75rem 0.5rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
    background-color: var(--mud-palette-surface);
    border-top: 1px solid var(--mud-palette-divider);
}

@media (max-width: 599.98px) {
    /* iOS zooms the whole page when a focused input's text is under 16px, and
       never zooms back out. Applies to the driver screens and SMS sign-in pages,
       which are the ones used on a phone. */
    .mud-input-input,
    .mud-input-slot,
    input.form-control,
    textarea.form-control,
    select.form-select {
        font-size: 16px;
    }

    /* Comfortable thumb targets. 44px is the usual floor for a reliable tap. */
    .driver-shell .mud-button-root,
    .btn {
        min-height: 48px;
    }
}

/* Document test drop zone.

   MudFileUpload renders its own drag area when DragAndDrop is set - that element
   is what captures the drop, so it is styled here rather than replaced with
   CustomContent. It only needs a size; MudBlazor supplies the dashed border and
   the hover state itself. */
.mud-file-upload-dragarea {
    min-height: 10rem;
    width: 100%;
}

/* ==========================================================================
   Navigation accents
   One hue per section of the drawer, so the menu is scanned by colour before it
   is read. The office menu runs to two dozen links across seven sections; colour
   is what makes "somewhere in Parties" a glance rather than a search.

   The hues are held as custom properties rather than written into each rule
   because they are inherited: a link only has to declare which section it
   belongs to, and every rule below - icon, active text, active border, hover -
   picks the colour up from --nav-accent without knowing what it is.

   Declared on the layout rather than the drawer so page content can use the
   same hues - the settings cards on the admin screens take their accent from
   here, and a hue meaning one thing in the menu and another on the page would
   defeat the point.
   ========================================================================== */

/* Light mode. These sit on a white drawer, so each is the darker end of its hue
   - the 600/700 shade rather than the 300/400 one. */
.mud-layout {
    --nav-azure:  #1565C0;
    --nav-green:  #2E7D32;
    --nav-violet: #6D28D9;
    --nav-cyan:   #00838F;
    --nav-amber:  #B45309;
    --nav-pink:   #BE185D;
    --nav-lime:   #4D7C0F;
    --nav-orange: #C2410C;
    --nav-indigo: #4338CA;
}

/* Dark mode. MudBlazor swaps its own palette variables when the theme flips but
   publishes no selector to hang other rules off, so MainLayout puts .app-dark on
   the layout root and these override by inheriting down to the drawer.

   Same eight hues, lightened to the 300/400 shades: the dark values above would
   disappear into the drawer background, and the light values here would glare
   against it. */
.mud-layout.app-dark {
    --nav-azure:  #4FA8FF;
    --nav-green:  #4ADE80;
    --nav-violet: #A78BFA;
    --nav-cyan:   #22D3EE;
    --nav-amber:  #FBBF24;
    --nav-pink:   #F472B6;
    --nav-lime:   #A3E635;
    --nav-orange: #FB923C;
    --nav-indigo: #818CF8;
}

/* Which section is which. Ordered so that no two adjacent sections land within
   60 degrees of each other on the colour wheel - neighbours are what actually
   have to be told apart, and a menu read top to bottom makes every section its
   own neighbour. */
.nav-dash      { --nav-accent: var(--nav-azure); }
.nav-driver    { --nav-accent: var(--nav-green); }
.nav-company   { --nav-accent: var(--nav-violet); }
.nav-ops       { --nav-accent: var(--nav-cyan); }
.nav-parties   { --nav-accent: var(--nav-amber); }
/* Indigo sits between Parties' amber and Reference's pink, both more than 60
   degrees away. It is close to Company's violet, but the two are never drawn
   together: that section only renders for a Company login. */
.nav-portalet  { --nav-accent: var(--nav-indigo); }
.nav-reference { --nav-accent: var(--nav-pink); }
.nav-analysis  { --nav-accent: var(--nav-lime); }
.nav-admin     { --nav-accent: var(--nav-orange); }

/* The icons themselves.

   app.css is linked before MudBlazor.min.css, so an equal-specificity rule would
   lose. Every selector in this block therefore carries .app-nav purely to
   outweigh MudBlazor's own - it is not there to scope anything, since the class
   is on the one menu that exists. */
.app-nav .mud-nav-link:not(.mud-nav-link-disabled) .mud-nav-link-icon,
.app-nav .mud-nav-link:not(.mud-nav-link-disabled) .mud-nav-link-icon.mud-nav-link-icon-default {
    color: var(--nav-accent, var(--mud-palette-drawer-icon));

    /* Held slightly back so a whole menu of saturated icons does not compete
       with the page next to it. The active link below returns to full strength,
       which is what makes it stand out. */
    opacity: 0.82;
    transition: opacity 120ms ease;
}

.app-nav .mud-nav-link:hover .mud-nav-link-icon,
.app-nav .mud-nav-link.active .mud-nav-link-icon {
    opacity: 1;
}

/* The active link takes its section's colour rather than the theme's blue, so
   the drawer agrees with itself about where you are. */
.app-nav.mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) {
    color: var(--nav-accent, var(--mud-palette-primary));
    background-color: color-mix(in srgb, var(--nav-accent, var(--mud-palette-primary)) 14%, transparent);
}

/* Bordered="true" draws the marker with border-inline-end and no colour of its
   own, so it inherits currentColor - which the rule above has already set. This
   only widens it, because two pixels of colour at the edge of a dark drawer is
   not enough to notice. */
.app-nav.mud-navmenu.mud-navmenu-bordered .mud-nav-link.active:not(.mud-nav-link-disabled) {
    border-inline-end-width: 3px;
}

/* The expand chevron on a group header, tinted to its section and faded well
   down. It is an affordance, not a label: at full strength it competes with the
   section's own icon on the same row. */
.app-nav .mud-nav-link .mud-nav-link-expand-icon {
    color: var(--nav-accent, var(--mud-palette-drawer-icon));
    opacity: 0.6;
}

.app-nav .mud-nav-link:hover .mud-nav-link-expand-icon {
    opacity: 1;
}

/* ==========================================================================
   The collapsed rail
   DrawerVariant.Mini narrows the drawer to an icon rail instead of removing it.
   MudBlazor hides the link labels itself; what it does not know about is the
   rest of what this menu puts in the drawer.
   ========================================================================== */

/* Below the breakpoint the rail has to go away completely, not shrink.

   Mini keeps a 56px strip of icons at every width, which is right on a desktop
   and wrong on a handset: a quarter of the screen spent on navigation that is
   not being used. The Responsive variant this replaced collapsed to nothing
   there, and that is the behaviour to keep.

   Done by zeroing the width variable rather than by rules on the drawer,
   because MudBlazor drives both the rail and the matching main-content margin
   from this one value - overriding the width alone would leave the page inset
   by 56px against a drawer that is no longer there. Set on the layout rather
   than :root: MudThemeProvider declares it on :root from a <style> block that
   loads after this file, and an inherited custom property is taken from the
   nearest ancestor that sets it, so proximity wins where the cascade would not. */
@media (max-width: 959.98px) {
    .mud-layout:has(.app-nav) {
        --mud-drawer-width-mini-left: 0px;
    }

    /* Elevation is a box-shadow, and a zero-width element still casts one - it
       would read as a grey seam down the left edge of every phone screen. */
    .mud-drawer-mini.mud-drawer--closed:has(.app-nav) {
        box-shadow: none;
    }
}

/* The chevron has nowhere to go in a 56px rail - it would sit on top of the
   section icon, which is the only thing identifying the row. The group still
   expands when the icon is clicked. */
.mud-drawer--closed.mud-drawer-mini .app-nav .mud-nav-link-expand-icon {
    display: none;
}

/* The icons carry the rail on their own now, so they come up to full strength
   rather than sitting at the resting opacity used in the full-width menu. */
.mud-drawer--closed.mud-drawer-mini .app-nav .mud-nav-link .mud-nav-link-icon {
    opacity: 1;
}

/* The active marker is drawn on the inline-end edge, which in a 56px rail lands
   directly under the pointer and reads as a scrollbar. Moved to the leading edge,
   where it marks the row instead of bordering it. */
.mud-drawer--closed.mud-drawer-mini .app-nav.mud-navmenu-bordered .mud-nav-link.active:not(.mud-nav-link-disabled) {
    border-inline-end-width: 0;
    border-inline-start: 3px solid var(--nav-accent, var(--mud-palette-primary));

    /* Keeps the icon where it was: the border would otherwise push the row
       across and the rail would jog in and out as you navigate. */
    padding-inline-start: 13px;
}

/* ==========================================================================
   Drawer scrollbar
   The office menu is longer than any screen, so this is on display permanently
   rather than being an occasional visitor. The platform default is a wide grey
   trough with square ends, which against a dark tinted drawer reads as damage.

   The scroll container is the <aside> itself, not the content div inside it -
   MudBlazor puts overflow: auto on the drawer element. Matched by the menu it
   contains rather than by a class of its own, so a second drawer added later
   gets none of this unless it is holding this same menu.
   ========================================================================== */

.mud-drawer:has(.app-nav) {
    /* MudBlazor sets overflow: auto on both axes. Nothing in a navigation menu
       should ever scroll sideways, and the horizontal bar it produced was real:
       it appeared across the foot of the drawer whenever a label was a few
       pixels wider than the panel, and again mid-animation as the mini rail
       expands. Vertical scrolling is the only kind this menu wants. */
    overflow-x: hidden;

    /* Firefox, and anything else that has caught up with the standard property. */
    scrollbar-width: thin;
    scrollbar-color: var(--nav-scroll-thumb) transparent;

    /* Both themes. Neutral rather than tinted: the scrollbar is furniture, and
       every accent in this drawer is already spoken for by a section. */
    --nav-scroll-thumb: rgba(15, 23, 42, 0.22);
    --nav-scroll-thumb-hover: rgba(15, 23, 42, 0.42);
}

/* Darker than the drawer rather than lighter. A pale thumb on a dark panel is
   the highest-contrast thing in the menu, which is the wrong ranking for a piece
   of furniture sitting next to eight colour-coded sections. */
.app-dark .mud-drawer:has(.app-nav) {
    --nav-scroll-thumb: rgba(3, 6, 12, 0.55);
    --nav-scroll-thumb-hover: rgba(3, 6, 12, 0.85);
}

/* Chromium and Safari, which still want the prefixed pseudo-elements. Both sets
   are needed: neither browser family understands the other's. */
.mud-drawer:has(.app-nav)::-webkit-scrollbar {
    width: 10px;
}

/* No trough. A tinted channel down the edge of the drawer is a second vertical
   line competing with the one that separates drawer from page. */
.mud-drawer:has(.app-nav)::-webkit-scrollbar-track {
    background: transparent;
}

.mud-drawer:has(.app-nav)::-webkit-scrollbar-thumb {
    background-color: var(--nav-scroll-thumb);
    border-radius: 999px;

    /* The padding that makes the thumb read as 6px inside a 10px gutter. A
       transparent border plus background-clip is the only way to inset a webkit
       thumb - it has no padding of its own. */
    border: 2px solid transparent;
    background-clip: content-box;
}

/* Only fully present while the pointer is in the drawer. Idle, it is a hint that
   there is more below; in use, it is a control worth aiming at. */
.mud-drawer:has(.app-nav):hover::-webkit-scrollbar-thumb,
.mud-drawer:has(.app-nav)::-webkit-scrollbar-thumb:hover {
    background-color: var(--nav-scroll-thumb-hover);
}

/* The corner square where two scrollbars would meet. There is only ever one bar
   now, but the platform still paints the box in its own grey. */
.mud-drawer:has(.app-nav)::-webkit-scrollbar-corner {
    background: transparent;
}

/* ==========================================================================
   Right-aligned grid cells
   The actions column on every grid, and the odd money column.

   Replaces `d-flex justify-end`, which was applied to the <td> itself. A table
   cell told to be a flex container stops being a table cell: it no longer shares
   the row's box, so its bottom border is drawn a pixel or two above the borders
   either side of it, and because row heights land on fractional pixels the error
   accumulates down the table. The dividers visibly stair-stepped by the tenth
   row. Right-aligning the contents does the same job without evicting the cell
   from its own row.
   ========================================================================== */

/* Qualified by the element rather than written as a bare class. MudBlazor sets
   text-align: start on .mud-table-cell, app.css is linked before its stylesheet,
   and a bare .grid-actions ties on specificity and therefore loses. Naming the
   <td> is enough to win, and it also covers the hand-written tables whose cells
   never carry .mud-table-cell at all. */
td.grid-actions,
th.grid-actions {
    text-align: right;

    /* An actions column is sized to its buttons. Without this a narrow window
       wraps them onto a second line and the row doubles in height. */
    white-space: nowrap;
}

/* MudTooltip and MudStack both render block-level flex boxes. A block box fills
   the cell regardless of text-align, so tooltip-wrapped icons - the warning and
   driver-issue markers on Loads, the map links on Verify locations - would sit
   left, and two of them would stack vertically rather than sit side by side. */
.grid-actions .mud-tooltip-root {
    display: inline-flex;
    vertical-align: middle;
}

.grid-actions > .mud-stack {
    justify-content: flex-end;
}

/* ==========================================================================
   Input labels
   Every field label in the primary colour, not only the focused one.
   MudBlazor greys a resting label, whitens it once it floats up, and turns it
   blue only while the field has focus - so a form full of filled-in fields
   read as undifferentiated grey-and-white text, and the labels were hard to
   pick out from the values under them.

   Error and disabled labels are excluded so they keep MudBlazor's red and
   dimmed colours: a label that stays blue on an invalid field would hide the
   one state it most needs to show. The selector is deliberately heavy -
   MudBlazor's focused-and-errored rule is (0,5,1), and app.css is linked
   before its stylesheet, so this has to outrank it rather than tie.
   ========================================================================== */
.mud-input-control > .mud-input-control-input-container > label.mud-input-label.mud-input-label-inputcontrol:not(.mud-input-error):not(.mud-disabled) {
    color: var(--mud-palette-primary);
}

/* ==========================================================================
   Account menu on static pages
   The app bar's account menu, as MainLayout renders it on a page with no
   circuit (the Identity pages). A <details> element opens and closes in the
   browser with no script, where a MudMenu needs the circuit to open at all.
   Drawn to match the MudMenu it stands in for: an icon button in the bar, a
   raised paper panel dropping from its right edge.
   ========================================================================== */
.static-account-menu {
    position: relative;
}

.static-account-menu > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    padding: 12px;
    border-radius: 50%;
    color: inherit;
}

.static-account-menu > summary::-webkit-details-marker {
    display: none;
}

.static-account-menu > summary:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.static-account-menu-panel {
    position: absolute;
    right: 0;
    top: 100%;
    min-width: 200px;
    padding: 8px 0;
    z-index: 1400;
    color: var(--mud-palette-text-primary);
    background-color: var(--mud-palette-surface);
    border-radius: var(--mud-default-borderradius);
}

.static-account-menu-name {
    font-size: 0.875rem;
}

.static-account-menu-panel hr {
    margin: 4px 0;
}

.static-account-menu-item {
    display: flex;
    align-items: center;

    /* Explicit because the Log out item is a <button>, which another sheet on
       these pages centres - it sat indented under Profile. */
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 8px 16px;
    font: inherit;
    font-size: 0.875rem;
    text-align: left;
    color: inherit;
    text-decoration: none;
    background: none;
    border: 0;
    cursor: pointer;
}

.static-account-menu-item:hover {
    background-color: var(--mud-palette-action-default-hover);
}

/* ==========================================================================
   Settings cards (SettingsCard.razor)
   The admin screens' cards: a header band tinted with the card's accent, the
   icon in the accent itself, and a bar down the left edge. The accent is one
   of the navigation hues (--nav-*), passed in as --card-accent, so it is
   already tuned for each theme; the tints are mixed against the surface for
   the same reason, and come out pale in light mode and deep in dark mode
   without a rule per theme.
   ========================================================================== */
.mud-paper.settings-card {
    padding: 0;
    overflow: hidden;
    border-left: 4px solid var(--card-accent);
}

.settings-card-head {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 56px;
    padding: 8px 16px;
    background-color: color-mix(in srgb, var(--card-accent) 12%, var(--mud-palette-surface));
    border-bottom: 1px solid color-mix(in srgb, var(--card-accent) 30%, transparent);
}

.settings-card-icon {
    color: var(--card-accent);
}

.settings-card-heading {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.settings-card-title {
    line-height: 1.3;
}

.settings-card-body {
    padding: 16px;
}

/* Something switched off: the accent drops to the secondary text colour, so a
   disabled sequence reads as dormant beside its live neighbours. */
.mud-paper.settings-card.settings-card-muted {
    --card-accent: var(--mud-palette-text-secondary);
}

/* A value the card exists to show - the next number a sequence will hand out,
   a queue count. Tinted from the enclosing card's accent. */
.settings-highlight {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-radius: 8px;
    background-color: color-mix(in srgb, var(--card-accent, var(--mud-palette-primary)) 10%, var(--mud-palette-surface));
    border: 1px solid color-mix(in srgb, var(--card-accent, var(--mud-palette-primary)) 35%, transparent);
}

.settings-highlight-value {
    color: var(--card-accent, var(--mud-palette-primary));
    font-weight: 600;
}

/* ==========================================================================
   Buttons beside inputs
   A button sitting in a row of fields - Upload next to Document type, Add on
   Dispatch, Queue test e-mail next to its address. Every input is dense: a
   40px box, 8px down from the top of its field, plus helper text underneath when it
   has any. A standard button is 36.5px and was centred against the whole
   field, helper text included, so it rode anywhere from 2px to 11px off the
   box it sits beside.

   input-button makes the button the box's height and puts it where the box
   is: pinned to the top of the row, down the same 8px - the field's own 4px
   margin plus the 4px an outlined dense box sits inside it. align-self overrides a
   row that centres its items, so the button no longer depends on how tall its
   neighbour's helper text makes the row.
   ========================================================================== */
.mud-button-root.input-button {
    height: 40px;
    margin-top: 8px;
    align-self: flex-start;
}

/* ==========================================================================
   Grid column headers
   MudBlazor draws a header row in the same colour, on the same background, as
   the rows under it - only a font weight of 500 against 400 sets it apart, and
   on a long striped grid the header read as just another row. A recessed band
   and small muted capitals make it plainly a label rather than data.

   Covers all three grid components: MudTable and MudDataGrid render
   .mud-table-head, MudSimpleTable renders a bare <thead>. The selectors are
   deliberately heavier than MudBlazor's own: app.css is linked first, so a tie
   on specificity goes to MudBlazor (see Right-aligned grid cells above).

   The two themes want different treatments, so the colours are variables set
   per theme below rather than derived from one palette entry for both:
   - Dark: a recessed band, part way from the page background towards the card
     surface. The page background alone was a near-black slab against the card.
   - Light: a brand-blue band with blue lettering. A grey band on a white card
     is one shade from invisible, and light mode had no colour anywhere else.
   Scoped to .mud-layout because .app-dark is set on it (see MainLayout). No
   grid renders inside a dialog, which sits outside the layout; the fallbacks
   are the light values for anything that ever does.
   ========================================================================== */
.mud-layout {
    --app-grid-head-bg: #DCE8F7;
    --app-grid-head-fg: #164A8A;
    --app-grid-head-rule: #A9C1E2;
}

.mud-layout.app-dark {
    --app-grid-head-bg: color-mix(in srgb, var(--mud-palette-background-gray) 55%, var(--mud-palette-surface));
    --app-grid-head-fg: var(--mud-palette-text-secondary);
    --app-grid-head-rule: var(--mud-palette-lines-inputs);
}

.mud-table-root .mud-table-head th.mud-table-cell,
.mud-simple-table table thead tr > th {
    background-color: var(--app-grid-head-bg, #DCE8F7);
    color: var(--app-grid-head-fg, #164A8A);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--app-grid-head-rule, #A9C1E2);

    /* A header is one or two words. Letting it wrap stacked "Load" over "#"
       and made the header row taller than any data row beneath it. */
    white-space: nowrap;
}

/* ==========================================================================
   Filter panels
   The card of filters above a grid (Loads, Messages, Invoices, Hauler pay,
   Reports, Portalet units), Dispatch's add-a-job controls and the Loads Quick add, which do the
   same job of steering what is below them. In light mode it was one more white card on the
   page, indistinguishable from the results it controls. A pale blue from the
   same family as the grid headers marks it as the controls rather than the
   data, and the fields inside keep a white box so they still read as inputs
   against the tint.

   Light mode only, by request: the dark theme already separates the panel
   from the page through the surface colour.
   ========================================================================== */
.mud-layout:not(.app-dark) .mud-paper.filter-panel {
    background-color: #DDE8F7;
    border: 1px solid #B3C8E6;
}

.mud-layout:not(.app-dark) .mud-paper.filter-panel .mud-input.mud-input-outlined {
    background-color: var(--mud-palette-surface);
}

/* The dark counterpart. The panel is the card surface here, and an outlined
   field is transparent, so the fields were the panel's own colour with only a
   thin outline to find them by. Recessing them into the darker page background
   does what the white box does in light mode. */
.mud-layout.app-dark .mud-paper.filter-panel .mud-input.mud-input-outlined {
    background-color: var(--mud-palette-background);
}

/* The search box in a grid's own toolbar (Jobs, Companies, Drivers, Trucks,
   Customers, Users, Portalet sites and customers). It sits on the grid's card
   rather than a filter panel, so it had the same problem as the panels' fields
   before them: transparent over the card, found only by its outline. The page
   background sets it into the card in both themes - recessed in dark, a faint
   blue-grey on white in light - without tinting the whole toolbar, which in
   light mode would merge into the blue header band directly beneath it. */
.mud-table-toolbar .mud-input.mud-input-outlined {
    background-color: var(--mud-palette-background);
}

/* The row whose record is open in the visible editor tab, on the split-panel
   screens (Loads, Jobs). With the editor below and the grid scrolled or
   re-sorted, nothing tied the form back to its row, so it was easy to lose
   track of which load was being changed.

   The tint is painted on the cells rather than the row: striping and hover
   colour the <tr>, and a cell background sits on top of both, so the marked
   row stays marked while the pointer is over it. The accent bar on the first
   cell is what still reads at a glance on a long page of striped rows. */
tr.mud-table-row.row-editing > td.mud-table-cell {
    background-color: color-mix(in srgb, var(--mud-palette-primary) 18%, transparent);
}

tr.mud-table-row.row-editing > td.mud-table-cell:first-child {
    box-shadow: inset 4px 0 0 var(--mud-palette-primary);
}

/* Sort labels and filter buttons inside the header keep the muted colour
   rather than MudBlazor's own text colour. */
.mud-table-root .mud-table-head .mud-table-sort-label,
.mud-table-root .mud-table-head th.mud-table-cell .mud-icon-button {
    color: inherit;
}

/* ==========================================================================
   Sticky grid headers
   Column headers stay in view while a long grid scrolls under them.

   A sticky element sticks to its nearest scrolling ancestor. On an ordinary
   page that is the page itself, with the fixed app bar over its top edge, so
   the header sticks just below the bar. Split panes override the offset to 0
   (see Split-panel workspace), because there the pane is the scroller.

   MudBlazor makes .mud-table-container a scroller (overflow: auto) so a grid
   too wide for its card can scroll sideways - and a scroller in between traps
   the header against a box that never scrolls vertically, so it never sticks.
   A browser cannot give one element both. So on a wide screen, where every
   grid fits (measured at 1440px across each screen), the container clips
   sideways instead of scrolling and the headers stick; below that width the
   sideways scroll is kept and the headers simply scroll away. clip rather than
   hidden, because hidden would make the container a scroller again.
   ========================================================================== */
.mud-table-root .mud-table-head th.mud-table-cell,
.mud-simple-table table thead tr > th {
    position: sticky;
    top: var(--mud-appbar-height);

    /* Above cell content that forms its own stacking context - chips,
       tooltips, the edited row's accent bar - and below the app bar. */
    z-index: 2;
}

@media (min-width: 1400px) {
    /* Qualified by its parent so it outranks MudBlazor's own .mud-table-container
       rule, which is linked after this file and would otherwise win the tie -
       and its overflow-y: auto would turn this clip back into a scroller. */
    .mud-table > .mud-table-container {
        overflow-x: clip;
        overflow-y: visible;
    }
}

/* ==========================================================================
   Grid cards
   Slightly rounder than MudBlazor's 4px, and clipped to that curve so the
   header band and the striping follow the corners instead of poking square
   out of them. clip, not hidden: hidden would make the card a scroller and
   trap the sticky headers above.

   Not in a split pane: there the grid is allowed to be wider than the pane so
   the pane can scroll to its last columns, and clipping the card would cut
   those columns off rather than let them be scrolled to.

   div.mud-table rather than .mud-paper.mud-table: MudSimpleTable is not a
   MudPaper, and the element name is what outranks MudBlazor's own .mud-table
   radius, which is linked after this file.
   ========================================================================== */
div.mud-table {
    border-radius: 8px;
    overflow: clip;
}

.workspace-pane div.mud-table {
    overflow: visible;
}

/* ==========================================================================
   Grid cell helpers
   Wide grids (the loads ledger, a company's drivers) have more columns than a
   laptop has room for at MudBlazor's 16px/24px cell padding. Left alone, the
   browser starves whichever column has the longest text - the lane - down to
   a word per line, while short columns like Truck keep their full padding, so
   rows grew five lines tall and the right-hand columns still overflowed.
   ========================================================================== */

/* Cuts the horizontal padding to 6px. MudBlazor sets both the shorthand and the
   logical inline properties, so both are overridden. */
.mud-table.grid-compact .mud-table-row .mud-table-cell,
.mud-simple-table.grid-compact table tr > th,
.mud-simple-table.grid-compact table tr > td {
    padding-left: 6px;
    padding-right: 6px;
    padding-inline-start: 6px;
    padding-inline-end: 6px;
}

/* Short, atomic values - a load number, a date, a phone number - that are
   unreadable split across two lines. */
td.cell-nowrap,
.cell-nowrap {
    white-space: nowrap;
}

/* The column that is allowed to wrap, given a floor so it wraps at a sensible
   width rather than one word per line. */
td.cell-lane,
th.cell-lane {
    min-width: 10rem;
}

/* A stack of small tables that must line up with each other - one per driver
   on Dispatch, one per customer on Invoices. Each table otherwise sizes its
   columns to its own contents, so Truck and Status landed at a different place
   on every card and the board could not be scanned down a column. Fixed layout
   takes the widths from the table's <colgroup> instead, which is the same on
   every card. */
.grid-aligned table {
    table-layout: fixed;
    width: 100%;
}

.grid-aligned td {
    overflow-wrap: anywhere;
}

/* Free text - a description - that should use whatever room is left. */
td.cell-grow,
th.cell-grow {
    width: 100%;
    min-width: 12rem;
}

/* ==========================================================================
   Sign-in card
   The account pages are the only screens in the application with one job and
   nothing else on them, so they get a card in the middle of the page rather
   than the left-hand column the Identity scaffolding shipped with.

   Written against Bootstrap rather than MudBlazor: the Identity pages render
   statically, and their form controls are .form-control, not MudBlazor inputs.
   Colours come from the theme's own variables so the card follows the app.
   ========================================================================== */

.auth-page {
    display: flex;
    align-items: center;
    justify-content: center;

    /* Enough of the window that the card sits nearer the middle than the top,
       without the guessed viewport arithmetic that would fight the app bar and
       the operator footer either side of it. */
    min-height: 70vh;
    padding: 2rem 1rem;
}

.auth-card {
    width: 100%;

    /* A sign-in form gets no wider than a comfortable line of text. Left to
       fill the container it would stretch the full width of a desk monitor and
       the two fields would look lost in it. */
    max-width: 26rem;

    padding: 2rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    background-color: var(--mud-palette-surface);
}

.auth-title {
    margin: 0 0 1.25rem;
    text-align: center;

    /* Light and large. The weight is what keeps a 2.5rem heading from shouting
       on a page with only two fields under it. */
    font-size: 2.5rem;
    font-weight: 300;
    line-height: 1.2;
}

/* The rules above the fields and below the button, which are what divide the
   card into its three parts: greeting, form, everything else. */
.auth-rule {
    margin: 1.5rem 0;
    border: 0;
    border-top: 1px solid var(--mud-palette-lines-default);
    opacity: 1;
}

/* Stacked, not a paragraph of prose with links buried in it. Each route out of
   this page is its own line and its own target. */
.auth-links {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.auth-links > * {
    margin: 0;
}

.auth-note {
    color: var(--mud-palette-text-secondary);
    font-size: 0.875rem;
}

/* "or" between the password form and the drivers' text-message button: a rule
   either side of the word, so the two read as alternatives. */
.auth-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 1rem 0;
    color: var(--mud-palette-text-secondary);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.auth-divider::before,
.auth-divider::after {
    content: "";
    flex: 1;
    border-top: 1px solid var(--mud-palette-lines-default);
}

/* The drivers' way in, as prominent as the Log in button but outlined so the
   password form's button stays the primary action for the office. Colours from
   the theme rather than Bootstrap's blue, so it matches the Log in button. */
.auth-card .auth-sms-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-size: 1rem;
    color: var(--mud-palette-primary);
    border-color: var(--mud-palette-primary);
    border-width: 2px;
}

.auth-card .auth-sms-button:hover,
.auth-card .auth-sms-button:focus-visible {
    color: var(--mud-palette-primary-text);
    background-color: var(--mud-palette-primary);
    border-color: var(--mud-palette-primary);
}

/* The card is already the page's only content, so on a phone it drops the frame
   and simply uses the width it has. A 1px border inset a few millimetres from
   the screen edge reads as a rendering fault rather than a design. */
@media (max-width: 575.98px) {
    .auth-page {
        min-height: 0;
        padding: 1rem 0;
    }

    .auth-card {
        padding: 1.5rem 1rem;
        border: 0;
        background-color: transparent;
    }
}

/* ==========================================================================
   Operator logo
   Stands in for the operator's name in the app bar.
   ========================================================================== */

.platform-logo {
    /* Height, never width: the app bar is a fixed-height strip and a wordmark is
       far wider than it is tall, so height is the dimension that has to fit and
       width follows from it. */
    height: 26px;
    width: auto;

    /* A wordmark on a phone would otherwise push the toolbar buttons off the
       right-hand edge. */
    max-width: 46vw;
    object-fit: contain;

    /* MudText sits on the app bar's baseline; a replaced element does not, and
       without this the logo rides a few pixels low against the icons. */
    display: block;
}

@media (max-width: 599.98px) {
    .platform-logo {
        height: 22px;
    }
}

/* The logo and the caption beside it are one mark, not two things that happen to
   share a strip. The app bar centres its children, which leaves the short caption
   hovering against the middle of the taller wordmark; these sit the two on a
   common bottom edge instead. line-height:1 is what makes that edge the lettering
   rather than the empty leading underneath it. */
.platform-brand {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;

    /* The caption is the part that gives way when the bar runs out of room. */
    min-width: 0;
}

.platform-brand .platform-caption {
    line-height: 1;
    margin: 0;

    /* The app bar's own lettering, softened, rather than the page's secondary
       text colour: that grey was chosen to sit on a card, and on the light
       theme's deep-blue bar it all but disappeared. */
    color: var(--mud-palette-appbar-text);
    opacity: 0.8;
}

/* The sign-in card's fields.

   data-bs-theme="dark" on <html> gets Bootstrap's controls into the right family,
   but it paints an input the same colour as the card behind it - 1.06:1, so the
   field is invisible except for its border. These pull the input down to the
   page background, the way a well is sunk into a panel, and hand the border and
   the lettering to the app's own palette so the card agrees with the rest of the
   application rather than with Bootstrap's greys.

   Scoped to the card: the other Identity screens are plain Bootstrap pages and
   are left to Bootstrap's own dark theme. */
.auth-card .form-control {
    background-color: var(--mud-palette-background);
    border-color: var(--mud-palette-lines-inputs);
    color: var(--mud-palette-text-primary);
}

.auth-card .form-control:focus {
    background-color: var(--mud-palette-background);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-primary);

    /* Bootstrap's own focus ring is a blue that has nothing to do with this
       theme. Same idea, drawn in the theme's primary. */
    box-shadow: 0 0 0 0.2rem rgba(var(--mud-palette-primary-rgb), 0.25);
}

/* The floating label sits on top of the field, so it is read against the input
   rather than the card. */
.auth-card .form-floating > label {
    color: var(--mud-palette-text-secondary);
}

.auth-card .form-control::placeholder {
    color: var(--mud-palette-text-secondary);
}

/* Bootstrap fills an unchecked box with the body background, which against a
   dark card reads as an already-filled control. */
.auth-card .form-check-input {
    background-color: var(--mud-palette-background);
    border-color: var(--mud-palette-lines-inputs);
}

.auth-card .form-check-input:checked {
    background-color: var(--mud-palette-primary);
    border-color: var(--mud-palette-primary);
}

/* Dashboard tiles.

   Only the loads tile carries a caption naming its week, so without this it
   stands a line taller than the three beside it and the row reads as ragged
   rather than as a set. Filling the grid cell squares them off, and leaves room
   for any of the others to gain a second line later without the same fix being
   needed again. */
.dashboard-tile {
    height: 100%;
}

/* Status pill.

   Replaces the full-row status tint on the loads ledger. Shading the whole row
   put the loudest colour in the grid behind the text of every column, which made
   a table of numbers harder to read to say one thing about one field. The pill
   says the same thing, in the column the status belongs to. */
.status-pill {
    display: inline-block;
    padding: 1px 10px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.7;
    white-space: nowrap;

    /* The grid is dense; without this the pill's own line-height pushes the row
       taller than the cells beside it. */
    vertical-align: middle;
}

/* A status with no colour of its own. */
.status-pill-plain {
    border: 1px solid var(--mud-palette-lines-default);
    color: var(--mud-palette-text-secondary);
}
