/*
 * Lowboy.
 *
 * The same design system as lcsof.com — identical tokens, type and theme
 * toggle — but shaped for an application rather than a marketing site.
 * Where that site has heroes and washes, this has a rail, dense tables and
 * numbers that have to line up.
 *
 * Two worlds, one structure: light is bright and iridescent, dark is deep
 * space with a cyan beam, and each is drawn on its own terms rather than
 * being an inversion of the other.
 *
 * The gradient washes are used sparingly here. On a page somebody stares at
 * for eight hours they would be exhausting, so they appear on the sign-in
 * screen and nowhere else.
 */

/* The one rule the stylesheet was missing.

   Without it `width: 100%` on an input means 100% *plus* its padding and
   border — so every text field in the application was about 29px wider
   than the column it sat in. On the sign-in card that showed up as the
   boxes running past the right edge while the left looked fine; on a
   dense form it quietly pushed columns around. */
*, *::before, *::after { box-sizing: border-box; }

/* `hidden` is a browser default of `display: none`, which means any author
   rule that sets a display beats it. `.check { display: flex }` did exactly
   that, so the "save to the address book" offer was visible on every empty
   box however carefully the script hid it. */
[hidden] { display: none !important; }

/* -------------------------------------------------------------- palettes

   The colours live in App\Support\Themes and are generated into
   themes.css, which loads before this file. Two reasons they are not here:
   the profile page draws its swatches from the same values and must not be
   able to show a colour the page does not use, and there are nine of them
   now — nine hand-maintained blocks of twenty-two custom properties is a
   place for a typo to hide.

   Everything below styles components through those tokens and never names
   a colour directly. */

:root {
    --display: "Bricolage Grotesque", "Helvetica Neue", Helvetica, Arial, sans-serif;
    --body: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    --rail: 232px;
    --gutter: clamp(1rem, 2.5vw, 2rem);
    --radius: 14px;
    --step: 0.25s cubic-bezier(0.2, 0.7, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--body);
    font-size: 15px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
    font-family: var(--display);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.1;
    margin: 0;
    text-wrap: balance;
}

a {
    color: var(--signal);
    text-underline-offset: 0.18em;
}

:focus-visible {
    outline: 2px solid var(--signal);
    outline-offset: 2px;
    border-radius: 4px;
}

img { max-width: 100%; height: auto; display: block; }

.skip {
    position: absolute;
    left: -9999px;
    background: var(--ink);
    color: var(--paper);
    padding: 0.7rem 1.1rem;
    z-index: 200;
    border-radius: 8px;
    font-family: var(--mono);
    font-size: 0.8rem;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

/* ----------------------------------------------------------------- shell */

.shell {
    display: grid;
    grid-template-columns: var(--rail) minmax(0, 1fr);
    min-height: 100vh;
}

/* A grid item defaults to min-width:auto, which means "as wide as my
   content" — so a 1,300px table stretched the column past the window and
   the whole page scrolled sideways instead. Every wide table in the app
   was affected: the last columns simply sat off the right edge, which on
   the cash report is the margin.
 
   minmax(0, 1fr) above bounds the track; this bounds the item inside it.
   Both are needed. With them, .table-scroll is finally narrower than its
   table and its overflow-x actually engages. */
.shell > * { min-width: 0; }

.rail {
    background: var(--paper-raised);
    border-right: 1px solid var(--rule);
    padding: 1.1rem 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 1.4rem;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--display);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.03em;
    color: var(--ink);
    text-decoration: none;
    padding: 0.2rem 0.35rem;
}

.brand__mark {
    width: 28px;
    height: 28px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    background: linear-gradient(135deg, var(--signal), var(--blueprint-bright));
    color: var(--signal-ink);
    flex: none;
}

.brand__mark svg { width: 17px; height: 17px; }

/* The mark in the rail. Sized by width because it is wide and short, and
   capped so it never crowds the navigation under it. */
.brand__logo {
    width: 100%;
    max-width: 172px;
    height: auto;
}

.nav-group__label {
    font-family: var(--mono);
    font-size: 0.6rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--graphite-light);
    padding: 0 0.55rem;
    margin-bottom: 0.5rem;
}

.nav-list { list-style: none; margin: 0 0 0.2rem; padding: 0; }

.nav-list a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.55rem;
    border-radius: 9px;
    color: var(--graphite);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 500;
    transition: background var(--step), color var(--step);
}

.nav-list a:hover { background: var(--paper-sunk); color: var(--ink); }

.nav-list a[aria-current="page"] {
    background: var(--signal-wash);
    color: var(--signal);
    font-weight: 600;
}

.nav-list svg { width: 16px; height: 16px; flex: none; }

.nav-list .count {
    margin-left: auto;
    font-family: var(--mono);
    font-size: 0.7rem;
    color: var(--graphite-light);
    font-variant-numeric: tabular-nums;
}

.rail__foot { margin-top: auto; }

/* ------------------------------------------------------------------ topbar */

.topbar {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 var(--gutter);
    min-height: 62px;
    border-bottom: 1px solid var(--rule);
    background: color-mix(in srgb, var(--paper) 82%, transparent);
    backdrop-filter: blur(14px) saturate(1.5);
    position: sticky;
    top: 0;
    z-index: 40;
}

.topbar h1 { font-size: 1.12rem; }

.topbar__end { margin-left: auto; display: flex; align-items: center; gap: 0.6rem; }

.who {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.25rem 0.3rem 0.25rem 0.6rem;
    border-radius: 999px;
    text-decoration: none;
    color: inherit;
    line-height: 1.25;
}

.who:hover { background: var(--signal-wash); }

.who__text { display: flex; flex-direction: column; align-items: flex-end; }

.who__face {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--paper-sunk);
    border: 1px solid var(--rule);
}
.who strong { font-size: 0.86rem; font-weight: 600; }

/* Only the role line, not the wrapper the name now sits in — `.who span`
   caught both and shouted the person's name at them. */
.who__text > span {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.075em;
    text-transform: uppercase;
    color: var(--graphite);
}

main { padding: var(--gutter); min-width: 0; }

/* --------------------------------------------------------------- controls */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-family: var(--body);
    font-size: 0.88rem;
    font-weight: 600;
    line-height: 1;
    padding: 0.65rem 1rem;
    border: 1px solid transparent;
    border-radius: 10px;
    cursor: pointer;
    text-decoration: none;
    transition: transform var(--step), box-shadow var(--step), border-color var(--step);
}

.btn--primary {
    background: linear-gradient(135deg, var(--signal), color-mix(in srgb, var(--signal) 65%, var(--blueprint-bright)));
    color: var(--signal-ink);
    box-shadow: 0 4px 16px var(--signal-wash);
}
.btn--primary:hover { transform: translateY(-1px); box-shadow: 0 8px 22px var(--signal-wash); }

.btn--ghost {
    background: var(--paper-raised);
    border-color: var(--rule);
    color: var(--ink);
    box-shadow: var(--shadow-sm);
}
.btn--ghost:hover { border-color: color-mix(in srgb, var(--signal) 35%, var(--rule)); }

.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: 1px solid var(--rule);
    background: var(--paper-raised);
    color: var(--graphite);
    cursor: pointer;
    padding: 0;
    box-shadow: var(--shadow-sm);
    transition: color var(--step), border-color var(--step);
}
.icon-btn:hover { color: var(--ink); border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }
.icon-btn svg { width: 16px; height: 16px; }

/* Which theme icon shows is decided by the theme in force, in CSS — not by
   a class the script has to keep in sync. No `display` on the svg rule:
   it is (0,1,1) and would out-rank these. */
.theme__moon { display: block; }
.theme__sun { display: none; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme__moon { display: none; }
    :root:not([data-theme="light"]) .theme__sun { display: block; }
}
:root[data-theme="dark"] .theme__moon { display: none; }
:root[data-theme="dark"] .theme__sun { display: block; }
:root[data-theme="light"] .theme__moon { display: block; }
:root[data-theme="light"] .theme__sun { display: none; }

/* ------------------------------------------------------------ stat cards */

.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.9rem;
    margin-bottom: 1.6rem;
}

.stat {
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1rem 1.1rem;
    box-shadow: var(--shadow-sm);
    position: relative;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    display: block;
    transition: transform var(--step), box-shadow var(--step), border-color var(--step);
}

a.stat:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
    border-color: color-mix(in srgb, var(--signal) 30%, var(--rule));
}

/* A state stripe, so "needs billing" is recognisable before it is read. */
.stat::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--accent, var(--rule));
}

.stat__label {
    display: block;
    margin-bottom: 0.5rem;
}

.stat__value {
    display: block;
    font-family: var(--display);
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.stat__note {
    display: block;
    font-size: 0.84rem;
    line-height: 1.45;
    color: var(--graphite);
    margin-top: 0.4rem;
}

.stat--open { --accent: var(--open); }
.stat--pending { --accent: var(--pending); }
.stat--billing { --accent: var(--billing); }
.stat--closed { --accent: var(--closed); }

/* ---------------------------------------------------------------- panels */

.panel {
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    margin-bottom: 1.4rem;
}

.panel__head {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.85rem 1.1rem;
    border-bottom: 1px solid var(--rule);
}

.panel__head h2 { font-size: 0.98rem; }
.panel__head .btn { margin-left: auto; }

.panel__label { line-height: 1.4; }

.panel__body { padding: 1.1rem; }

/* ------------------------------------------------------------- eyebrows

   The small uppercase mono labels above a figure, over a panel, across a
   section rule. They set the tone of the whole interface, and they were
   also the least readable thing in it: DM Mono at 0.6rem is under 10px,
   and all-caps with 0.14em tracking in the lightest grey on top of that
   asks somebody to decode "TOTAL PAY OUT SEPTEMBER" rather than read it.

   Kept as a treatment — it is the design language — but sized and spaced
   so it is legible: nearer 12px, tracking loosened only enough to keep
   the caps from touching, and a grey with real contrast against the
   panel. The one rule below is what every eyebrow now uses. */

.eyebrow,
.stat__label,
.panel__label,
.figure__label,
.section-rule {
    font-family: var(--mono);
    font-size: 0.73rem;
    font-weight: 500;
    letter-spacing: 0.085em;
    text-transform: uppercase;
    color: var(--graphite);
}

/* ---------------------------------------------------------------- tables */

.table-scroll { overflow-x: auto; }

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
    min-width: 720px;
}

table.data th {
    text-align: left;
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.075em;
    text-transform: uppercase;
    color: var(--graphite);
    font-weight: 500;
    padding: 0.6rem 0.9rem;
    background: var(--paper-sunk);
    border-bottom: 1px solid var(--rule);
    white-space: nowrap;
    position: sticky;
    top: 0;
}

table.data td {
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--rule-soft);
    vertical-align: middle;
}

table.data tbody tr:hover { background: var(--paper-sunk); }
table.data tbody tr:last-child td { border-bottom: 0; }

/* Money and dates line up or they are harder to scan than useless. */
td.num, th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

td.mono { font-family: var(--mono); font-size: 0.82rem; }

.row-link { color: var(--ink); text-decoration: none; font-weight: 600; }
.row-link:hover { color: var(--signal); }

.muted { color: var(--graphite-light); }

/* ------------------------------------------------------------------ pill */

.pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: var(--mono);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    padding: 0.24rem 0.55rem;
    border-radius: 6px;
    white-space: nowrap;
    border: 1px solid transparent;
}

/* The dot carried the colour when the fill was a wash. On a filled pill it
   is a hole punched in the middle of the word. */
.pill::before { content: none; }

/* Solid, not a 12% tint.

   The state is the one thing on a row somebody scans for, and coloured
   text on a wash of the same colour is the least readable way to say it —
   at 0.63rem in tracked-out capitals it was a smudge. Filled pills read
   from across a desk.

   `--pill-ink` is white on the light themes and the theme's own near-black
   on the dark ones, which is what lets one rule work in both worlds. */
.pill--open { background: var(--open); color: var(--pill-ink); }
.pill--pending { background: var(--pending); color: var(--pill-ink); }
.pill--billing { background: var(--billing); color: var(--pill-ink); }
.pill--closed { background: var(--closed); color: var(--pill-ink); }

/* Whether somebody can sign in — not a state a BOL can be in. It borrowed
   the BOL classes, so "Active" was about to turn red along with Closed. */
.pill--yes { background: var(--billing); color: var(--pill-ink); }
.pill--no { background: var(--graphite); color: var(--pill-ink); }

/* ----------------------------------------------------------------- forms */

.field { margin-bottom: 1.1rem; }

.field label {
    display: block;
    font-family: var(--mono);
    font-size: 0.62rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--graphite);
    margin-bottom: 0.45rem;
}

.field input,
.field select {
    width: 100%;
    font-family: var(--body);
    font-size: 0.95rem;
    color: var(--ink);
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: 10px;
    padding: 0.7rem 0.85rem;
    box-shadow: var(--shadow-sm);
    transition: border-color var(--step), box-shadow var(--step);
}

.field input:focus,
.field select:focus {
    outline: none;
    border-color: var(--signal);
    box-shadow: 0 0 0 4px var(--signal-wash);
}

.field__error { display: block; color: var(--danger); font-size: 0.82rem; margin-top: 0.35rem; }

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    align-items: flex-end;
    padding: 0.9rem 1.1rem;
    border-bottom: 1px solid var(--rule);
}
.filters .field { margin-bottom: 0; }
.filters input, .filters select { min-width: 150px; }

/* ----------------------------------------------------------- sign-in page */

/* The one screen that gets the marketing site's wash, because it is the one
   screen nobody spends the day looking at. */
/* A centred card on a blue field.

   Fixed blue rather than the palette's accent: this is the one screen a
   person sees before the application knows anything about them, including
   which theme they chose, and it should look the same every time rather
   than shifting with whatever the browser last remembered.

   The card is opaque and unblurred. Earlier versions put a flag behind it
   and then beside it, and both times the card needed glass to stay
   readable — which is what made it look smeared. Nothing behind it now
   needs reading past. */
.signin {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 2rem 1.25rem;
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(70rem 48rem at 20% 8%, #2a4c8f 0%, transparent 62%),
        radial-gradient(60rem 44rem at 82% 92%, #123063 0%, transparent 58%),
        linear-gradient(160deg, #1b3767 0%, #0b1730 100%);
}

.signin__card {
    position: relative;
    width: 100%;
    max-width: 25rem;
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: 20px;
    padding: 2rem;
    box-shadow: var(--shadow-lg);
}

.signin__card h1 { font-size: 1.5rem; margin-bottom: 0.4rem; }
.signin__card .lede { color: var(--graphite); font-size: 0.92rem; margin: 0 0 1.6rem; }

.signin__logo {
    /* The mark inside the card, on paper-white. Sized to sit level with the
       theme toggle beside it rather than towering over it. */
    width: clamp(8rem, 42%, 11rem);
    height: auto;
}

.signin__brand { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.6rem; }

.alert {
    border: 1px solid var(--rule);
    border-left: 3px solid var(--danger);
    background: var(--paper-raised);
    border-radius: 10px;
    padding: 0.8rem 1rem;
    margin-bottom: 1.2rem;
    font-size: 0.88rem;
}

/* ---------------------------------------------------------------- detail */

.detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0;
    border-top: 1px solid var(--rule-soft);
}

.detail-grid > div {
    padding: 0.75rem 1.1rem;
    border-bottom: 1px solid var(--rule-soft);
    border-right: 1px solid var(--rule-soft);
}

.detail-grid dt {
    font-family: var(--mono);
    font-size: 0.6rem;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--graphite-light);
    margin-bottom: 0.25rem;
}

.detail-grid dd { margin: 0; font-size: 0.92rem; font-weight: 500; font-variant-numeric: tabular-nums; }

.money-columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.1rem;
    padding: 1.1rem;
}

.money-columns h3 {
    font-family: var(--mono);
    font-size: 0.62rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--graphite-light);
    margin-bottom: 0.7rem;
}

.money-line {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--rule-soft);
    font-size: 0.9rem;
}
.money-line:last-child { border-bottom: 0; }
.money-line span:first-child { color: var(--graphite); }
.money-line span:last-child { font-variant-numeric: tabular-nums; font-weight: 500; }
.money-line--total { font-weight: 700; border-top: 1px solid var(--rule); margin-top: 0.3rem; padding-top: 0.6rem; }

.empty { padding: 3rem 1rem; text-align: center; color: var(--graphite); }

.pagination { padding: 0.9rem 1.1rem; border-top: 1px solid var(--rule); }
.pagination svg { width: 16px; height: 16px; }

/* --------------------------------------------------------------- responsive */

.rail-toggle { display: none; }

@media (max-width: 900px) {
    .shell { grid-template-columns: minmax(0, 1fr); }

    .rail {
        position: fixed;
        inset: 0 auto 0 0;
        width: var(--rail);
        z-index: 100;
        transform: translateX(-100%);
        transition: transform var(--step);
        box-shadow: var(--shadow-lg);
    }

    .rail.is-open { transform: none; }

    .rail-toggle { display: inline-grid; }
}

/* ------------------------------------------------------------- form grids */

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0 1rem;
    padding: 1.1rem;
}

.form-grid--wide { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.form-grid--money { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }

.field textarea {
    width: 100%;
    font-family: var(--body);
    font-size: 0.95rem;
    color: var(--ink);
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: 10px;
    padding: 0.7rem 0.85rem;
    box-shadow: var(--shadow-sm);
    resize: vertical;
    min-height: 4.5rem;
}

.field textarea:focus {
    outline: none;
    border-color: var(--signal);
    box-shadow: 0 0 0 4px var(--signal-wash);
}

/* Derived figures are not editable, and must not look editable either. */
.field input[readonly] {
    background: var(--paper-sunk);
    color: var(--graphite);
    box-shadow: none;
    cursor: default;
}

.field label .muted { text-transform: none; letter-spacing: 0; }

/* --------------------------------------------------- list-specific bits */

/* The old list printed an unassigned driver in red. It is a real signal —
   a haul nobody is driving is a haul nobody is doing — so it survives,
   using the warning colour rather than a hard red. */
.unassigned {
    color: var(--pending);
    font-weight: 600;
}

/* Addresses are multi-line in the source and worth showing in full; the
   column is capped rather than the text truncated. */
td.addr {
    max-width: 15rem;
    white-space: normal;
    line-height: 1.35;
    font-size: 0.83rem;
}

.badge {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 22px;
    padding-inline: 0.35rem;
    border-radius: 6px;
    font-family: var(--mono);
    font-size: 0.68rem;
    background: var(--paper-sunk);
    color: var(--graphite-light);
    border: 1px solid var(--rule);
}

.badge--has {
    background: color-mix(in srgb, var(--billing) 16%, transparent);
    color: var(--billing);
    border-color: transparent;
}

.row-actions { white-space: nowrap; text-align: right; }
.row-actions .icon-btn { margin-left: 0.3rem; }

.icon-btn--sm { width: 28px; height: 28px; border-radius: 8px; }
.icon-btn--sm svg { width: 14px; height: 14px; }

.page-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.1rem;
}
.page-actions h2 { font-size: 1.1rem; display: flex; align-items: center; gap: 0.55rem; }
.page-actions .btn { margin-left: auto; }

.count-chip {
    font-family: var(--mono);
    font-size: 0.7rem;
    padding: 0.15rem 0.45rem;
    border-radius: 6px;
    background: var(--signal-wash);
    color: var(--signal);
    font-variant-numeric: tabular-nums;
}

.alert--info { border-left-color: var(--signal); }

/* A button label that wraps reads as two buttons. */
.btn { white-space: nowrap; }

/* ------------------------------------------------------- the BOL itself */

/* Laid out as the paper form is, because the people filling it in have the
   order memorised: route, then who and what, then the clock, then money. */
/* The BOL is a document, not a dashboard, so it sits in the middle of the
   window rather than hugging the rail. On a wide monitor the card was 1,180px
   of form against 800px of nothing, and the eye had to travel back to the
   left edge for every row.

   On the wrapper as well as the card so that an alert above it — "that did
   not save" — lines up with the form it is talking about instead of running
   the full width of the screen. */
.bol-page { max-width: 1180px; margin-inline: auto; }

.bol {
    margin-inline: auto;
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: clamp(1rem, 2.5vw, 1.75rem);
    max-width: 1180px;
}

/* The sheet's fields, grouped so a closed BOL can be disabled in one go.
   A fieldset carries a border, padding and a min-width of its content by
   default, all of which would break the layout it wraps. */
.bol__fields {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

/* Say it is not editable rather than leaving somebody to work out why their
   typing does nothing. Each browser greys a disabled control its own way, so
   the whole sheet is dimmed a little to make the state read as deliberate. */
.bol__fields:disabled { opacity: 0.85; }

.bol__head {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
    margin-bottom: 1.8rem;
}

.bol__brand { display: flex; align-items: center; gap: 0.7rem; }
.bol__brand strong { display: block; font-family: var(--display); font-size: 1.05rem; letter-spacing: -0.03em; }
.bol__brand span { font-family: var(--mono); font-size: 0.68rem; color: var(--graphite-light); }

.bol__number {
    margin-left: auto;
    text-align: right;
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
}

.bol__number span {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--graphite-light);
}

.bol__number strong {
    font-family: var(--display);
    font-size: clamp(1.3rem, 3vw, 1.9rem);
    letter-spacing: -0.03em;
    color: var(--signal);
}

.bol__number input { width: 8rem; font-family: var(--mono); }

.bol__row { display: grid; gap: 0 1rem; }
.bol__row--1 { grid-template-columns: 1fr; }
.bol__row--2 { grid-template-columns: repeat(2, 1fr); }
.bol__row--3 { grid-template-columns: repeat(3, 1fr); }
.bol__row--4 { grid-template-columns: repeat(4, 1fr); }
.bol__row--5 { grid-template-columns: repeat(5, 1fr); }

@media (max-width: 1000px) {
    .bol__row--4, .bol__row--5 { grid-template-columns: repeat(2, 1fr); }
    .bol__row--3 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 620px) {
    .bol__row { grid-template-columns: 1fr !important; }
}

.bol__rule { border: 0; border-top: 1px solid var(--rule); margin: 1.4rem 0 1.6rem; }

.bol__rates-head {
    font-size: 1rem;
    color: var(--signal);
    margin-bottom: 1rem;
}

/* The grand total is the figure everyone looks for. */
.field label.is-total { color: var(--signal); }

.consent {
    display: flex;
    gap: 0.65rem;
    align-items: flex-start;
    font-family: var(--body);
    font-size: 0.86rem;
    line-height: 1.5;
    color: var(--graphite);
    text-transform: none;
    letter-spacing: 0;
    margin-bottom: 0.4rem;
}

.consent input { width: auto; margin-top: 0.25rem; box-shadow: none; }

.bol__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }

/* Closing a BOL is the irreversible one for a non-admin, so it does not
   look like the ordinary save beside it. */
.btn--finalise {
    background: var(--danger);
    color: #fff;
}
.btn--finalise:hover { filter: brightness(1.08); color: #fff; }

/* ------------------------------------------------------------- map links */

.map-link {
    display: inline-flex;
    align-items: flex-start;
    gap: 0.3rem;
    color: inherit;
    text-decoration: none;
    white-space: pre-line;
}

.map-link svg {
    width: 13px;
    height: 13px;
    flex: none;
    margin-top: 0.15rem;
    color: var(--graphite-light);
    opacity: 0;
    transition: opacity var(--step), color var(--step);
}

.map-link:hover { color: var(--signal); }
.map-link:hover svg, .map-link:focus-visible svg { opacity: 1; color: var(--signal); }

/* Always visible where there is room for it. */
.detail-grid .map-link svg { opacity: 1; }

.detail-grid__wide {
    grid-column: 1 / -1;
    padding: 0.75rem 1.1rem;
    border-bottom: 1px solid var(--rule-soft);
}

.btn--print {
    background: var(--paper-sunk);
    border-color: var(--rule);
    color: var(--graphite);
}
.btn--print:hover { color: var(--ink); border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }

/* Each onward step gets its own colour, because "send to billing" and
   "send back to the driver" are opposite decisions sitting side by side. */
.btn--billing { background: var(--billing); color: #fff; }
.btn--billing:hover { filter: brightness(1.08); color: #fff; }

.btn--return { background: var(--pending); color: #fff; }
.btn--return:hover { filter: brightness(1.08); color: #fff; }

.alert--ok { border-left-color: var(--billing); }

/* --------------------------------------------------------- signature pad */

.sigpad { margin-bottom: 1.1rem; }

.sigpad__frame {
    position: relative;
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--paper-raised);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.sigpad__frame canvas {
    display: block;
    width: 100%;
    height: 150px;
    /* Stops a phone scrolling the page when somebody signs. */
    touch-action: none;
    cursor: crosshair;
}

.sigpad__hint {
    position: absolute;
    inset: auto 0 1.6rem 0;
    text-align: center;
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--graphite-light);
    pointer-events: none;
}

/* A signing line, as on the paper form. */
.sigpad__frame::after {
    content: "";
    position: absolute;
    left: 1.5rem;
    right: 1.5rem;
    bottom: 1.4rem;
    border-bottom: 1px solid var(--rule);
    pointer-events: none;
}

.sigpad.is-signed .sigpad__hint { display: none; }

.sigpad__bar {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    margin-top: 0.5rem;
}

.sigpad__when {
    font-family: var(--mono);
    font-size: 0.66rem;
    color: var(--graphite-light);
}

.btn--sm { padding: 0.45rem 0.8rem; font-size: 0.8rem; }

.sig-preview {
    max-height: 90px;
    border-bottom: 1px solid var(--rule);
    padding-bottom: 0.3rem;
}

.sigpad__label {
    display: block;
    font-family: var(--mono);
    font-size: 0.62rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--graphite);
    margin-bottom: 0.45rem;
}

/* --------------------------------------------------------- attachments */

.bol--attach { margin-top: 1.2rem; }

.attach__form { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; margin-bottom: 1rem; }

.attach__pick { position: relative; overflow: hidden; display: inline-block; }
.attach__pick input { position: absolute; inset: 0; opacity: 0; width: 100%; cursor: pointer; }
.attach__pick span {
    display: inline-flex;
    align-items: center;
    padding: 0.45rem 0.8rem;
    font-size: 0.8rem;
    font-weight: 600;
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--paper-raised);
    box-shadow: var(--shadow-sm);
}
.attach__pick:hover span { border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }

.attach__hint { font-family: var(--mono); font-size: 0.66rem; color: var(--graphite-light); }

.thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.thumb {
    width: 118px;
    border: 1px solid var(--rule);
    border-radius: 10px;
    overflow: hidden;
    background: var(--paper-raised);
    box-shadow: var(--shadow-sm);
}

.thumb a { display: block; }
.thumb img { width: 100%; height: 86px; object-fit: cover; display: block; }

.thumb__doc {
    display: grid;
    place-items: center;
    height: 86px;
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    color: var(--graphite-light);
    background: var(--paper-sunk);
}

.thumb__name {
    display: block;
    padding: 0.35rem 0.45rem 0.15rem;
    font-family: var(--mono);
    font-size: 0.6rem;
    line-height: 1.25;
    color: var(--graphite);
    /* Long names break anywhere rather than pushing the tile wide — the
       middle of the name is already elided in PHP, so what is left is meant
       to be read whole. */
    overflow-wrap: anywhere;
}

.thumb__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.3rem;
    padding: 0.25rem 0.45rem;
    border-top: 1px solid var(--rule-soft);
    font-family: var(--mono);
    font-size: 0.6rem;
    color: var(--graphite-light);
}

.thumb__foot button {
    background: none;
    border: 0;
    color: var(--graphite-light);
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    padding: 0 0.15rem;
}
.thumb__foot form button:hover { color: var(--danger); }

/* The share button lives in the same footer as the delete one, so it must
   not borrow its hover: red on an icon next to a red X reads as "this also
   destroys something". */
.thumb__foot [data-share] { display: inline-flex; }
.thumb__foot [data-share] svg { width: 13px; height: 13px; }
.thumb__foot [data-share]:hover { color: var(--signal); }
.thumb__foot [data-share]:disabled { opacity: 0.4; cursor: default; }

/* How long a link lasts, and what it means. Sits above the thumbnails
   because it applies to all of them. */
.attach__share {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
}

.attach__share label {
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--graphite-light);
}

.attach__share select {
    width: auto;
    padding: 0.3rem 1.6rem 0.3rem 0.55rem;
    font-size: 0.8rem;
}

/* What just happened, said next to the control rather than in an alert box
   that has to be dismissed before the next file can be shared. */
.attach__said {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--signal);
}

/* --------------------------------------------------------- share links */

/* A link sits on the history line that recorded it being made, under the
   sentence rather than beside it: the history's three columns are When, What
   and Who, and the controls belong to the What. */
.share-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.4rem;
}

.share-line__state,
.share-line__opened {
    font-family: var(--mono);
    font-size: 0.64rem;
    color: var(--graphite-light);
}

.share-line__state.is-live { color: var(--signal); font-weight: 600; }

/* The link, visible to whoever sent it. Quiet, and truncated by the field
   rather than by wrapping — a share link is long, and three lines of it would
   swamp the entry it belongs to. */
.share-line__url {
    flex: 1 1 18rem;
    min-width: 0;
    padding: 0.22rem 0.45rem;
    font-family: var(--mono);
    font-size: 0.66rem;
    color: var(--graphite);
    border: 1px solid var(--rule-soft);
    border-radius: 7px;
    text-overflow: ellipsis;
}

.share-line__url:focus { color: var(--ink); border-color: var(--signal); }

.share-line button {
    background: none;
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 0.22rem 0.5rem;
    font-family: var(--body);
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
}

.share-line button:hover { border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }
.share-line button:disabled { opacity: 0.4; cursor: default; }
.share-line button.is-done { color: var(--signal); border-color: var(--signal); }
.share-line__kill:hover { border-color: var(--danger); color: var(--danger); }

.share-line select { width: auto; padding: 0.2rem 1.4rem 0.2rem 0.45rem; font-size: 0.72rem; }

/* The link itself, for when the clipboard would not take it. Full width on
   its own line: a share link is long, and half of one is no use. */
.attach__link {
    flex-basis: 100%;
    font-family: var(--mono);
    font-size: 0.72rem;
    padding: 0.4rem 0.55rem;
}

.head-actions { margin-left: auto; display: flex; flex-wrap: wrap; gap: 0.45rem; }
.head-actions .btn { padding: 0.55rem 0.85rem; font-size: 0.84rem; }
.head-actions svg { width: 14px; height: 14px; }

.onward { display: flex; flex-wrap: wrap; gap: 0.5rem; padding-bottom: 1.1rem; }

/* ------------------------------------------------------- period figures */

.section-rule {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    margin: 1.8rem 0 0.9rem;
}
.section-rule::before, .section-rule::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--rule);
}

.figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
    gap: 0.9rem;
    margin-bottom: 0.9rem;
}

.figure {
    position: relative;
    overflow: hidden;
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1rem 1.1rem;
    box-shadow: var(--shadow-sm);
}

/* The coloured edge, as on the old cards — it is what makes a wall of
   numbers scannable rather than uniform. */
.figure::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--tone, var(--rule));
}

.figure--gross { --tone: var(--billing); }
.figure--payout { --tone: var(--danger); }
.figure--profit { --tone: var(--blueprint); }
.figure--percent { --tone: var(--signal); }

/* A watermark, not a label. Large, faint, behind the number. */
.figure__mark {
    position: absolute;
    right: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--display);
    font-size: 3.2rem;
    font-weight: 700;
    line-height: 1;
    color: var(--tone);
    opacity: 0.09;
    pointer-events: none;
}

.figure__label {
    display: block;
    /* The tone rather than plain grey: it is what ties the label to the
       coloured edge, and these sit on a raised panel where it holds up. */
    color: var(--tone);
    margin-bottom: 0.45rem;
}

.figure__value {
    display: block;
    font-family: var(--display);
    font-size: clamp(1.3rem, 2.4vw, 1.65rem);
    font-weight: 700;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.figure__delta {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    margin-top: 0.5rem;
    font-family: var(--mono);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}
.figure__delta em { font-style: normal; color: var(--graphite); }
.figure__delta.is-up { color: var(--billing); }
.figure__delta.is-down { color: var(--danger); }
.figure__delta.is-flat { color: var(--graphite-light); }

/* ---------------------------------------------------------------- trend */

.trend { padding: 1rem 1.1rem 0.4rem; }
.trend svg { width: 100%; height: auto; display: block; }

.trend__note {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--graphite);
    margin: 0.4rem 0 0.9rem;
}

.key {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 2px;
    margin: 0 0.2rem 0 0.6rem;
    vertical-align: baseline;
}
.key--payout { background: var(--graphite); opacity: 0.35; }
.key--profit { background: var(--signal); }
.key--line { background: var(--blueprint); height: 2px; border-radius: 0; width: 12px; }

/* -------------------------------------------------------------- welcome */

.welcome {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 0.9rem;
    margin-top: 1.4rem;
}

.welcome__photo { width: 100%; height: 200px; object-fit: cover; }

.welcome p { margin: 0 0 0.6rem; }

.work-list { list-style: none; margin: 0; padding: 0; }
.work-list li + li { border-top: 1px solid var(--rule-soft); }

.work-list a {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.7rem 0;
    color: inherit;
    text-decoration: none;
}
.work-list a:hover strong { color: var(--signal); }

.work-list__count {
    display: grid;
    place-items: center;
    min-width: 44px;
    padding: 0.3rem 0.5rem;
    border-radius: 9px;
    font-family: var(--display);
    font-size: 1.05rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.work-list__count--open { background: color-mix(in srgb, var(--open) 14%, transparent); color: var(--open); }
.work-list__count--pending { background: color-mix(in srgb, var(--pending) 16%, transparent); color: var(--pending); }
.work-list__count--billing { background: color-mix(in srgb, var(--billing) 16%, transparent); color: var(--billing); }

.work-list strong { display: block; font-size: 0.98rem; }
.work-list em { font-style: normal; font-size: 0.85rem; color: var(--graphite); }

/* ------------------------------------------------------- people, settings,
   reports — the screens added after the BOL itself. They reuse the panel and
   table styles above; what follows is only what they need on top. */

.form-panel .form-grid { padding: 1.1rem 1.1rem 0.2rem; }

.form-grid--2 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

.form-actions {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    padding: 1.1rem;
    border-top: 1px solid var(--rule);
    margin-top: 0.6rem;
}

.form-panel .section-rule { margin: 0.4rem 1.1rem 0; }

/* A hint under a field, and a hint under a page. Same voice, different
   scale — both are the sentence that stops somebody guessing. */
.field__hint {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--graphite-light);
}

.hint {
    max-width: 62ch;
    margin: 0.9rem 0.2rem 0;
    font-size: 0.82rem;
    line-height: 1.55;
    color: var(--graphite-light);
}

.check {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.3rem 0;
    font-size: 0.9rem;
    cursor: pointer;
}

.check input { width: 1rem; height: 1rem; accent-color: var(--signal); }
.check span { color: var(--ink); }

/* Deactivated people, deleted BOLs: still legible, plainly not current. */
.is-muted td { opacity: 0.58; }
.is-muted .row-link { text-decoration: line-through; }

.total-row td {
    border-top: 2px solid var(--rule);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    background: var(--paper-sunk, transparent);
}

/* The one destructive control on a screen, set apart from the save button so
   it cannot be hit on the way to it. */
.danger-zone {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 1.2rem;
    padding: 1rem 1.1rem;
    border: 1px solid color-mix(in srgb, var(--danger) 30%, var(--rule));
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--danger) 4%, transparent);
}

.danger-zone strong { display: block; font-size: 0.92rem; }
.danger-zone span { font-size: 0.8rem; color: var(--graphite-light); }
.danger-zone button { margin-left: auto; }

.btn--danger { background: var(--danger); color: #fff; border-color: transparent; }
.btn--danger:hover { filter: brightness(1.08); color: #fff; }

/* -------------------------------------------------------------- reports */

.report-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0.9rem;
}

.report-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 1.1rem 1.2rem;
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.report-card:hover {
    border-color: color-mix(in srgb, var(--signal) 40%, var(--rule));
    transform: translateY(-2px);
}

.report-card strong { font-family: var(--display); font-size: 1.05rem; letter-spacing: -0.02em; }
.report-card span { font-size: 0.83rem; line-height: 1.5; color: var(--graphite-light); }

.report-card__go {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: auto;
    padding-top: 0.5rem;
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--signal);
}

.report-card__go svg { width: 0.9rem; height: 0.9rem; }

/* Ranges people actually ask for, so "last month" is not a calendar
   lookup every time. */
.shortcuts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0 1.1rem 1.1rem;
}

.chip {
    padding: 0.32rem 0.7rem;
    border: 1px solid var(--rule);
    border-radius: 999px;
    font-size: 0.78rem;
    text-decoration: none;
    color: var(--graphite);
    transition: border-color 0.15s ease, color 0.15s ease;
}

.chip:hover { color: var(--ink); border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }

.chip.is-on {
    color: var(--signal);
    border-color: var(--signal);
    background: var(--signal-wash);
}

/* The signed-in person, at the foot of the rail, as a way in to their own
   account rather than a label. */
.rail__account {
    display: block;
    padding: 0.6rem 0.7rem;
    border-radius: var(--radius-sm, 8px);
    text-decoration: none;
    color: inherit;
}

.rail__account:hover { background: var(--signal-wash); }
.rail__account strong { display: block; font-size: 0.85rem; }
.rail__account span { font-size: 0.72rem; color: var(--graphite-light); }

/* In a report the addresses are context, not the subject — five hundred
   six-line rows is a document nobody scrolls. Clamped to three lines; the
   full text is still in the cell, so it copies and prints whole.

   The clamp goes on a span INSIDE the cell, never on the cell itself.
   `display: -webkit-box` on a <td> takes it out of the table layout: the
   row is left with one fewer cell, everything after it shifts a column
   left, and the last column — the margin, on the cash report — renders
   empty. The DOM still reports the right number of cells, so this is only
   visible by looking at the page. */
.data--report td.addr { max-width: 13rem; }

.clamp-3 {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    line-clamp: 3;
    overflow: hidden;
}

/* On a phone the danger zone's text and its button stop fitting side by
   side, and a button squeezed to two characters is one nobody means to
   press. */
@media (max-width: 620px) {
    .danger-zone { flex-direction: column; align-items: stretch; }
    .danger-zone button { margin-left: 0; }

    /* A filter row on a narrow screen is one control per line — two
       half-width date boxes is worse than two full ones. */
    .filters .field { width: 100%; }
    .filters input, .filters select { width: 100%; min-width: 0; }

    .panel__head { flex-wrap: wrap; }
}

/* ------------------------------------------------- sortable, striped lists */

/* Every other row a shade darker, so the eye tracks across a wide table
   without losing the line. Deliberately faint: at 50 rows a stripe that
   reads as a highlight makes half the list look flagged.

   :nth-child, not a class, so it stays right when a filter changes which
   rows are on the page. */
.data--zebra tbody tr:nth-child(even) { background: var(--stripe); }

/* Hover still has to win over the stripe, or half the rows stop responding
   to the pointer. */
.data--zebra tbody tr:hover,
.data--zebra tbody tr:nth-child(even):hover {
    background: var(--signal-wash);
}

table.data th.is-sortable { padding: 0; }

table.data th.is-sortable a {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.6rem 0.9rem;
    color: inherit;
    text-decoration: none;
    /* The whole heading is the target, not the four small-caps words in it. */
    white-space: nowrap;
}

table.data th.is-sortable a:hover { color: var(--signal); background: var(--signal-wash); }
table.data th.num.is-sortable a { justify-content: flex-end; }

table.data th.is-sorted { color: var(--signal); }

.sort-arrow { font-size: 0.85em; line-height: 1; }

/* The address book, under each of the three address boxes.

   Deliberately quieter than the box it fills: it is a shortcut, and a
   second full-size control under every address would read as another
   thing to fill in rather than a way of filling the one above it. */
.field__pick {
    margin-top: 0.4rem;
    font-size: 0.8rem;
    padding: 0.4rem 0.6rem;
    color: var(--graphite);
    background: var(--paper-sunk);
    border: 1px dashed var(--rule);
}

.field__pick:hover {
    color: var(--ink);
    border-color: color-mix(in srgb, var(--signal) 45%, var(--rule));
    border-style: solid;
}

/* --------------------------------------------------------------- profile */

.profile {
    display: grid;
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    gap: 0.9rem;
    align-items: start;
}

@media (max-width: 860px) {
    .profile { grid-template-columns: minmax(0, 1fr); }
}

.avatar-pick { display: grid; gap: 1rem; justify-items: center; }

.avatar-pick__current {
    width: 148px;
    height: 148px;
    border-radius: 50%;
    background: var(--paper-sunk);
    border: 1px solid var(--rule);
}

/* Sixteen faces as a grid rather than the old dropdown. A select that says
   "Avatar 6" makes you pick one, look, and pick again — the whole point of
   choosing a picture is seeing it. */
.avatar-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(52px, 1fr));
    gap: 0.5rem;
    width: 100%;
}

.avatar-grid__one { cursor: pointer; display: block; }

/* The radio itself is hidden but still focusable, so the keyboard works. */
.avatar-grid__one input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.avatar-grid__one img {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--paper-sunk);
    border: 2px solid transparent;
    transition: border-color var(--step), transform var(--step);
}

.avatar-grid__one:hover img { transform: scale(1.06); }
.avatar-grid__one.is-on img { border-color: var(--signal); }
.avatar-grid__one input:focus-visible + img { outline: 2px solid var(--signal); outline-offset: 2px; }

/* ---------------------------------------------------------------- themes */

.theme-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 0.7rem;
}

.theme-card {
    display: grid;
    gap: 0.35rem;
    padding: 0.8rem 0.9rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--paper);
    cursor: pointer;
    transition: border-color var(--step), transform var(--step);
}

.theme-card:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--signal) 40%, var(--rule)); }
.theme-card.is-on { border-color: var(--signal); box-shadow: 0 0 0 1px var(--signal); }

.theme-card input { position: absolute; opacity: 0; width: 0; height: 0; }
.theme-card input:focus-visible ~ .theme-card__swatch { outline: 2px solid var(--signal); outline-offset: 2px; }

/* Ground, panel, accent, ink — enough to recognise a palette without
   rendering the whole page in it. Drawn from the same values the page
   uses, so a swatch cannot lie. */
.theme-card__swatch {
    display: flex;
    height: 34px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--rule);
}

.theme-card__swatch span { flex: 1; }

/* Half light, half dark — the only honest picture of "follow my device". */
.theme-card__swatch--auto span:nth-child(1),
.theme-card__swatch--auto span:nth-child(2) { flex: 1.2; }

.theme-card strong { font-size: 0.92rem; display: flex; align-items: baseline; gap: 0.45rem; }
.theme-card em { font-style: normal; font-size: 0.8rem; line-height: 1.45; color: var(--graphite); }

.theme-card__group {
    font-family: var(--mono);
    font-size: 0.6rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--graphite-light);
}

/* What each role is for, beside the picker that assigns it. The one
   currently chosen is lit, so the list reads as an explanation of the
   selection rather than a wall of options. */
.role-notes { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.3rem; }

.role-notes li {
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--graphite-light);
    padding-left: 0.6rem;
    border-left: 2px solid transparent;
}

.role-notes li.is-on { color: var(--graphite); border-left-color: var(--signal); }
.role-notes strong { color: var(--ink); font-weight: 600; }

/* ---------------------------------------------------- company branding */

.branding {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.2rem;
    padding: 0 1.1rem 0.4rem;
}

.branding__one { display: grid; gap: 0.7rem; }

/* A checkerboard, because a logo is usually transparent and a white one on
   a white card looks like nothing uploaded. */
.branding__preview {
    display: grid;
    place-items: center;
    min-height: 110px;
    padding: 0.8rem;
    border: 1px dashed var(--rule);
    border-radius: var(--radius);
    background-color: var(--paper-sunk);
    background-image:
        linear-gradient(45deg, var(--rule-soft) 25%, transparent 25%),
        linear-gradient(-45deg, var(--rule-soft) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, var(--rule-soft) 75%),
        linear-gradient(-45deg, transparent 75%, var(--rule-soft) 75%);
    background-size: 16px 16px;
    background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}

.branding__preview img { max-height: 96px; max-width: 100%; object-fit: contain; }

/* The background is a photograph, so show it as one rather than floating
   it on the checkerboard. */
.branding__preview--login_background { padding: 0; overflow: hidden; }
.branding__preview--login_background img { max-height: none; width: 100%; height: 110px; object-fit: cover; }

.branding__preview span {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--graphite-light);
}

.field input[type="file"] {
    width: 100%;
    font-size: 0.85rem;
    padding: 0.5rem;
    background: var(--paper-sunk);
    border: 1px dashed var(--rule);
    border-radius: 10px;
}

/* ------------------------------------------- a branded sign-in screen */

/* With a photograph behind it the card has to hold its own against
   whatever the operator uploaded — which, judging by the one this
   replaces, may be a full-bleed flag. */
.signin--branded {
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/* The app's own gradient wash is the wrong thing over somebody's
   photograph; a plain scrim is what keeps the card readable. */
.signin--branded::before {
    background: linear-gradient(
        to bottom,
        color-mix(in srgb, var(--paper) 30%, transparent),
        color-mix(in srgb, var(--paper) 62%, transparent)
    );
    inset: 0;
    height: auto;
    filter: none;
}

.signin--branded .signin__card {
    box-shadow: var(--shadow-lg);
    /* Slightly opaque rather than solid, so the photograph is still
       present behind the card instead of being cut a hole in. */
    background: color-mix(in srgb, var(--paper-raised) 94%, transparent);
    backdrop-filter: blur(8px);
}

/* An uploaded logo sets its own proportions — the app's mark is a fixed
   square, a customer's is whatever their sign-writer drew. */
.brand--logo { display: block; }

.brand--logo img {
    display: block;
    max-height: 56px;
    max-width: 15rem;
    object-fit: contain;
}

/* -------------------------------------------------- the sign-in screen

   A centred card on a blue field. It has been through a flag behind the
   card and a flag beside it; both fought the form. A gradient is the one
   thing that can be strong without competing with anything, because there
   is nothing in it to look at. */

/* The wordmark in the corner of the sign-in screen.

   aria-hidden, and deliberately: the card already names the product to a
   screen reader, and hearing "Lowboy" twice on a two-field form is worse
   than not hearing it in the corner. This is decoration that happens to
   be type. */
.signin__mark {
    position: absolute;
    left: 0;
    bottom: 0;
    padding: clamp(1.5rem, 4vw, 3rem);
    max-width: 26rem;
    pointer-events: none;
    color: #fff;
}

.signin__mark img {
    /* Wide and short, so it is sized by width and left to find its own
       height. Capped in vw as well, or on a laptop it runs into the card. */
    width: clamp(12rem, 26vw, 21rem);
    height: auto;
    margin-bottom: 0.6rem;
}

.signin__mark span {
    font-size: clamp(0.85rem, 1.3vw, 1rem);
    line-height: 1.5;
    /* Support, not a second headline. */
    color: rgba(255, 255, 255, 0.72);
}

/* On a phone the card fills the screen and the corner is where the
   keyboard goes. */
@media (max-width: 860px) {
    .signin__mark { display: none; }
}

/* Somebody's own role, on their profile, when they may not change it.
   A disabled select would say "you could have changed this"; a plain
   statement says what they are. */
.role-badge {
    display: grid;
    gap: 0.25rem;
    margin: 0 1.1rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--rule);
    border-left: 3px solid var(--signal);
    border-radius: var(--radius);
    background: var(--paper-sunk);
}

.role-badge strong { font-size: 0.98rem; }
.role-badge span { font-size: 0.83rem; line-height: 1.5; color: var(--graphite); }

/* The offer to file an address that is not in the book yet. Quieter than
   the field it belongs to — it is a convenience, not a question the form
   is asking. */
/* A sentence, not a field label. `.field label` sets the small-caps mono
   treatment for every label inside a field, and this is a label — so it
   inherited it and shouted a whole sentence in tracked-out capitals. */
/* `.field label` is 0,0,1,1 and a bare class is 0,0,1,0 — so the class
   alone lost, and the sentence stayed in capitals. Qualified to win. */
.field label.check--save {
    margin-top: 0.45rem;
    font-family: var(--body);
    font-size: 0.82rem;
    letter-spacing: 0;
    text-transform: none;
    line-height: 1.4;
    color: var(--graphite);
}

.field label.check--save em { font-style: normal; font-weight: 600; color: var(--ink); }

/* A driver's dashboard has one tile, not four. Left at its natural width
   rather than stretched across the row — a single card the width of the
   screen reads as a banner, not as a number somebody should act on. */
.stats--one { grid-template-columns: minmax(0, 22rem); }

.work-list__count--all { background: var(--paper-sunk); color: var(--graphite); }

/* The links under a dashboard figure.

   The card used to be one big anchor, which is tidy until it needs links
   of its own — and a whole card being clickable never says what a click
   will do. The number is now just a number; these say where to go. */
.stat__links {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.15rem 0.9rem;
    margin-top: 0.85rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--rule-soft);
}

.stat__links a {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.22rem 0;
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    /* The card's own state colour, so the links belong to the figure above
       them rather than looking bolted on. */
    color: var(--accent, var(--signal));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.stat__links a:hover { text-decoration: underline; }
.stat__links svg { width: 0.85rem; height: 0.85rem; flex: none; }

/* Four month links want two columns, not four thin ones. */
.stat--closed .stat__links { grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }

/* The range in force, beside the count on a filtered list. */
.count-range {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    color: var(--graphite);
    font-weight: 400;
}

/* ------------------------------------------------------------- the viewer */

/* A photograph, opened in place for a quick look.
   A native <dialog>, so the backdrop, the focus trap and Escape are the
   browser's job rather than three more things to get wrong here. */
.viewer {
    padding: 0;
    border: 0;
    background: transparent;
    max-width: min(94vw, 1400px);
    max-height: 94vh;
    overflow: visible;
}

.viewer::backdrop {
    background: rgba(8, 11, 18, 0.82);
}

.viewer img {
    display: block;
    max-width: 100%;
    max-height: 86vh;
    width: auto;
    margin-inline: auto;
    border-radius: 10px;
    box-shadow: var(--shadow-lg, 0 24px 64px rgba(0, 0, 0, 0.45));
    background: var(--paper-raised);
}

/* Which file this is. A wall of thumbnails of the same trailer from four
   angles is why the name matters on the grid, and it matters here too. */
.viewer__name {
    margin: 0.6rem 0 0;
    text-align: center;
    font-family: var(--mono);
    font-size: 0.72rem;
    color: #fff;
    opacity: 0.85;
    word-break: break-all;
}

.viewer__close {
    position: absolute;
    top: -14px;
    right: -14px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--rule);
    background: var(--paper-raised);
    color: var(--ink);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--shadow);
}

.viewer__close:hover { background: var(--paper); }

/* At this width those offsets hang the button off the screen. */
@media (max-width: 560px) {
    .viewer__close { top: 8px; right: 8px; }
}

/* The thumbnail is now a button in all but name. */
.thumb a[data-view] { cursor: zoom-in; }


/* ------------------------------------------------------- the sign-in */

/*
     * Night haul.
     *
     * Deliberately single-theme: this is the six-in-the-morning screen,
     * and a driver squinting at a tablet in a cab before it is light is
     * the person it is for. Every colour here is written out rather than
     * taken from a palette token, because the palette is the thing the
     * application behind this wears and this screen does not follow it.
     */
    .night {
        position: fixed;
        inset: 0;
        display: grid;
        place-items: center;
        padding: 1.5rem;
        overflow: hidden;
        /* The current sign-in's blue, layer for layer, so the two
           screens are the same colour rather than nearly. */
        background:
            radial-gradient(70rem 48rem at 20% 8%, #2a4c8f 0%, transparent 62%),
            radial-gradient(60rem 44rem at 82% 92%, #123063 0%, transparent 58%),
            linear-gradient(160deg, #1b3767 0%, #0b1730 100%);
        color: #eef3fb;
        font-family: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }

    /* The road ahead: a wash off the bottom edge and one bright line
       across it. Blue on blue, so it carries more opacity than the red it
       replaced — at red's strength it vanished into the ground. */
    .night__horizon {
        position: absolute;
        left: 0; right: 0; bottom: 0;
        height: 42%;
        background: linear-gradient(to top, rgba(47, 124, 255, 0.22), transparent 72%);
        pointer-events: none;
    }

    .night__line {
        position: absolute;
        left: 0; right: 0; bottom: 21%;
        height: 1px;
        background: linear-gradient(to right, transparent, rgba(90, 160, 255, 0.6), transparent);
        pointer-events: none;
    }

    .night__inner {
        position: relative;
        width: min(400px, 100%);
        text-align: center;
    }

    /* Inside the panel, centred and given room — it is the first thing
       on the screen worth looking at. */
    .night__mark {
        display: block;
        width: 250px;
        max-width: 86%;
        height: auto;
        margin: 0 auto;
    }

    /* The same line that runs across the horizon at the foot of the
       page — transparent at both ends, brightest in the middle — so the
       divider inside the panel and the one behind it are the same idea
       rather than two different rules.

       A background rather than a border, because a border cannot hold a
       gradient. */
    .night__head {
        text-align: center;
        padding-bottom: 1.15rem;
        margin-bottom: 1.25rem;
        background-image: linear-gradient(to right, transparent, rgba(90, 160, 255, 0.6), transparent);
        background-repeat: no-repeat;
        background-size: 100% 1px;
        background-position: bottom center;
    }

    .night__panel {
        text-align: left;
        padding: 1.2rem 1.15rem 1.3rem;
        border-radius: 14px;
        border: 1px solid rgba(255, 255, 255, 0.12);
        background: rgba(255, 255, 255, 0.055);
        box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5);
    }

    /* Progressive: without backdrop-filter the panel is simply a darker
       card, which is fine. */
    @supports (backdrop-filter: blur(9px)) {
        .night__panel { backdrop-filter: blur(9px); }
    }

    .night__field { display: block; margin-bottom: 0.9rem; }

    .night__field > span {
        display: block;
        font-family: "DM Mono", ui-monospace, Menlo, monospace;
        font-size: 0.62rem;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: rgba(238, 243, 251, 0.5);
        margin-bottom: 0.35rem;
    }

    .night__field input {
        width: 100%;
        height: 42px;
        padding: 0 0.75rem;
        border-radius: 9px;
        border: 1px solid rgba(255, 255, 255, 0.14);
        background: rgba(255, 255, 255, 0.07);
        color: #eef3fb;
        font: inherit;
        font-size: 0.95rem;
    }

    .night__field input:focus {
        outline: none;
        border-color: rgba(15, 111, 255, 0.8);
        box-shadow: 0 0 0 3px rgba(15, 111, 255, 0.22);
    }

    /* The app's signal blue — the same one .btn--primary wears on every
       other screen, so the button here and the button there are the same
       button. */
    .night__go {
        width: 100%;
        height: 44px;
        margin-top: 0.3rem;
        border: 0;
        border-radius: 10px;
        background: #0f6fff;
        color: #fff;
        font: inherit;
        font-weight: 700;
        font-size: 0.95rem;
        letter-spacing: -0.01em;
        cursor: pointer;
        transition: filter 0.2s ease, transform 0.2s ease;
    }

    .night__go:hover { filter: brightness(1.08); }
    .night__go:active { transform: translateY(1px); }

    .night__go:focus-visible,
    .night__theme:focus-visible {
        outline: 2px solid #fff;
        outline-offset: 2px;
    }

    /* The one thing still red, and deliberately: this is a failed
       sign-in, not an accent. An error in the page's accent colour reads
       as information, which is the opposite of what it is. */
    .night__alert {
        margin: 0 0 0.95rem;
        padding: 0.6rem 0.75rem;
        border-radius: 9px;
        font-size: 0.85rem;
        color: #ffd9db;
        background: rgba(216, 31, 38, 0.18);
        border: 1px solid rgba(216, 31, 38, 0.4);
    }

    /* Still a theme switch, because what it sets is the palette the
       application behind this will wear — this screen just does not
       follow it. Kept out of the way, at the top corner. */
    .night__theme {
        position: absolute;
        top: 1rem; right: 1rem;
        width: 34px; height: 34px;
        display: grid;
        place-items: center;
        border-radius: 50%;
        border: 1px solid rgba(255, 255, 255, 0.14);
        background: rgba(255, 255, 255, 0.06);
        color: rgba(238, 243, 251, 0.75);
        cursor: pointer;
    }

    .night__theme:hover { background: rgba(255, 255, 255, 0.12); }

    /* The mark in the corner, as the current sign-in has it.
       Same sizing rules as .signin__mark so the two screens agree about
       how big it is; written out here because this page takes none of its
       colours from the palette. */
    .night__corner {
        position: absolute;
        left: 0;
        bottom: 0;
        padding: clamp(1.5rem, 4vw, 3rem);
        max-width: 26rem;
        pointer-events: none;
        color: #fff;
    }

    .night__corner img {
        /* Wide and short, so it is sized by width and left to find its
           own height. Capped in vw as well, or on a laptop it runs into
           the panel. */
        width: clamp(12rem, 26vw, 21rem);
        height: auto;
        margin-bottom: 0.6rem;
    }

    .night__corner span {
        display: block;
        font-size: clamp(0.85rem, 1.3vw, 1rem);
        line-height: 1.5;
        /* Support, not a second headline. */
        color: rgba(255, 255, 255, 0.72);
    }

    /* On a phone the panel fills the screen and the corner is where the
       keyboard goes. */
    @media (max-width: 860px) {
        .night__corner { display: none; }
    }

    /* A phone in a cab: the mark gets smaller, nothing else changes. */
    @media (max-width: 420px) {
        .night__mark { width: 195px; }
        .night__panel { padding: 1rem 0.9rem 1.1rem; }
    }

    @media (prefers-reduced-motion: reduce) {
        .night__go { transition: none; }
    }

/* The chooser: one more screen on the same design, reached only when an
   address opens two operators' accounts. */
.night__ask {
    margin: 0 0 1.1rem;
    font-size: 0.88rem;
    line-height: 1.5;
    color: rgba(238, 243, 251, 0.66);
}

/* Matched to the inputs rather than left as the browser's, or the one
   control on the screen is the one that looks borrowed. */
.night__field select {
    width: 100%;
    height: 42px;
    padding: 0 2rem 0 0.75rem;
    border-radius: 9px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background-color: rgba(255, 255, 255, 0.07);
    color: #eef3fb;
    font: inherit;
    font-size: 0.95rem;
    appearance: none;
    /* The chevron, drawn rather than fetched. */
    background-image:
        linear-gradient(45deg, transparent 50%, rgba(238, 243, 251, 0.55) 50%),
        linear-gradient(135deg, rgba(238, 243, 251, 0.55) 50%, transparent 50%);
    background-position: right 1rem center, right 0.7rem center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}

.night__field select:focus {
    outline: none;
    border-color: rgba(15, 111, 255, 0.8);
    box-shadow: 0 0 0 3px rgba(15, 111, 255, 0.22);
}

/* A dark control's options are drawn by the operating system, which needs
   telling what ground they are on. */
.night__field select option { background: #0e1424; color: #eef3fb; }

.night__other {
    margin: 1rem 0 0;
    text-align: center;
    font-size: 0.83rem;
}

.night__other a { color: rgba(238, 243, 251, 0.6); }
.night__other a:hover { color: #eef3fb; }

/* --------------------------------------------------------- two-factor */

/* The square and the box beside it. On a narrow screen the square goes
   above, because a QR code somebody has to point a phone at should not be
   the thing that shrinks. */
.tf {
    display: flex;
    flex-wrap: wrap;
    gap: 1.4rem;
    align-items: flex-start;
}

.tf__qr {
    flex: none;
    padding: 0.6rem;
    border-radius: 10px;
    /* White whatever the palette: it is a black-on-white code, and a dark
       ground under it is a code no camera reads. */
    background: #fff;
    border: 1px solid var(--rule);
}

.tf__qr svg { display: block; width: 200px; height: 200px; }

.tf__rest { flex: 1; min-width: 15rem; }

/* The recovery codes, shown once. Laid out to be read off a screen and
   written down, which is what they are for. */
.codes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: 0.4rem 1rem;
    margin: 0.9rem 0 1.1rem;
    padding: 0.9rem 1rem;
    list-style: none;
    border: 1px dashed var(--rule);
    border-radius: 10px;
    background: var(--paper-sunk);
}

.codes li {
    font-size: 0.95rem;
    letter-spacing: 0.04em;
    /* Digits and letters that cannot be mistaken for each other matter more
       here than anywhere else on the site. */
    font-variant-ligatures: none;
}
