/* Wayside Files: site styles. Hand-written, no framework. Usable from 360px.
   The look follows Wayside Nexus (Docket360): the dark title bar, the canvas, white cards, green primary
   buttons and blue links. Colours, radii and shadows are the custom properties below; change them there,
   not in the rules. Every text colour here is WCAG AA on the ground it sits on. */

:root {
    /* Grounds and ink (Nexus --canvas, --surface, --ink, --muted, --line). */
    --color-bg: #eef1f4;
    --color-bg-soft: #f6f8fa;
    --color-surface: #ffffff;
    --color-text: #161c22;
    --color-muted: #5c6873;          /* 5.0:1 on --color-bg, 5.7:1 on white */
    --color-border: #e0e5ea;         /* card and table lines: decoration only */
    --color-field-border: #858f99;   /* a form field's edge identifies it, so it needs 3:1 on white */

    /* Links and the secondary blue (Nexus --blue, --blue-deep). #1f6fa8 is 5.4:1 on white, 4.75:1 on the canvas. */
    --color-accent: #1f6fa8;
    --color-accent-strong: #17587f;
    --color-accent-contrast: #ffffff;
    --color-accent-wash: #e9f1f8;
    --color-accent-wash-border: #c3d9ea;

    /* Primary buttons (Nexus --green-deep: white on it is 5.1:1). */
    --color-primary: #0a7f36;

    /* Focus (Nexus --aqua): an edge colour, 3.6:1 on white. Never used for text. */
    --color-focus: #2f8ecb;
    --color-focus-halo: rgba(47, 142, 203, 0.14);

    --color-danger: #b3261e;
    --color-danger-text: #8a1c13;

    /* The title bar (Nexus sidebar chrome). */
    --color-topbar: #15191c;
    --color-topbar-2: #0d1013;
    --color-topbar-text: #ffffff;
    --color-nav: #9aa5ad;            /* 7:1 on the bar */
    --color-nav-hover: rgba(255, 255, 255, 0.06);
    --color-nav-line: rgba(255, 255, 255, 0.12);
    --color-nav-accent: #01d340;     /* the logo green: only ever a bar on the dark ground */

    --font-body: "Helvetica Neue", Helvetica, Arial, "Segoe UI", system-ui, sans-serif;
    --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 1rem;
    --space-4: 1.5rem;
    --space-5: 2.5rem;

    --radius: 14px;      /* cards */
    --radius-sm: 9px;    /* buttons, fields, small boxes */
    --shadow: 0 1px 2px rgba(20, 38, 47, 0.06), 0 8px 24px rgba(20, 38, 47, 0.05);

    /* Lists and detail pages use the page width; forms stay at the form width so lines stay readable. */
    --page-width: 88rem;
    --form-width: 44rem;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

/* Scripts show and hide things with the hidden attribute (the CSP allows no style attributes), so it must
   beat any class that sets display, such as .button. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-body);
    font-size: 1rem;
    line-height: 1.55;
}

/* Form controls do not inherit the font on their own. */
button, input, select, textarea { font-family: inherit; }

h1, h2, h3 {
    line-height: 1.25;
    margin: 0 0 var(--space-3);
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.25rem; }

p { margin: 0 0 var(--space-3); }

a { color: var(--color-accent); }
a:hover { color: var(--color-accent-strong); }

:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

code {
    font-family: var(--font-mono);
    font-size: 0.95em;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    left: var(--space-2);
    top: -4rem;
    z-index: 20;
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
}

.skip-link:focus {
    top: var(--space-2);
}

/* Title bar: the Nexus dark gradient, the Wayside logo, the menu. */

.topbar {
    background: linear-gradient(180deg, var(--color-topbar), var(--color-topbar-2));
    color: var(--color-topbar-text);
}

.topbar-inner {
    max-width: var(--page-width);
    min-height: 3.5rem;
    margin: 0 auto;
    padding: 0 var(--space-3);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
}

.brand {
    display: flex;
    align-items: center;
    padding: 0.875rem 0;
    border-radius: var(--radius-sm);
}

.brand-logo {
    display: block;
    width: auto;
    height: 28px;
}

.nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    background: transparent;
    border: 1px solid var(--color-nav-line);
    border-radius: var(--radius-sm);
    color: var(--color-topbar-text);
    cursor: pointer;
}

.nav-toggle:hover { background: var(--color-nav-hover); }

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
    display: block;
    width: 1.25rem;
    height: 2px;
    background: currentColor;
    content: "";
}

.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before { position: absolute; top: -6px; }
.nav-toggle-bars::after { position: absolute; top: 6px; }

/* On a phone the menu opens below the bar as a list; the current page has a green bar at its side. */
.site-nav {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    padding-bottom: var(--space-3);
}

.site-nav.is-open { display: flex; }

.site-nav a {
    padding: var(--space-2) 0.75rem;
    border-radius: var(--radius-sm);
    color: var(--color-nav);
    font-weight: 600;
    text-decoration: none;
}

.site-nav a:hover {
    background: var(--color-nav-hover);
    color: var(--color-topbar-text);
}

.site-nav a[aria-current="page"] {
    color: var(--color-topbar-text);
    box-shadow: inset 3px 0 0 var(--color-nav-accent);
}

/* Inside the link, so the ring is not clipped by the bar's edge. */
.site-nav a:focus-visible { outline-offset: -2px; }

.signout {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin: var(--space-2) 0 0;
    padding: var(--space-2) 0.75rem 0;
    border-top: 1px solid var(--color-nav-line);
}

.signed-in-as {
    color: var(--color-nav);
    font-size: 0.9rem;
    overflow-wrap: anywhere;
}

/* Sign out, in the title bar: coloured like the nav links. */
.link-button {
    padding: var(--space-1) 0;
    background: none;
    border: 0;
    color: var(--color-nav);
    font: inherit;
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
}

.link-button:hover { color: var(--color-topbar-text); }

/* Page */

.page {
    flex: 1 0 auto;
    width: 100%;
    max-width: var(--page-width);
    margin: 0 auto;
    padding: var(--space-4) var(--space-3);
}

.lead {
    color: var(--color-muted);
    font-size: 1.1rem;
}

.message {
    max-width: 38rem;
    margin: var(--space-4) auto;
    padding: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.reference {
    padding: 0.1rem 0.4rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 6px;
    user-select: all;
}

/* Buttons. .button is the green primary; .button-secondary the white "ghost"; .button-danger red. */

.button {
    display: inline-block;
    padding: 0.6rem 1.1rem;
    background: var(--color-primary);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--color-accent-contrast);
    font: inherit;
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    transition: filter 0.15s, border-color 0.15s, color 0.15s;
}

.button:hover {
    color: var(--color-accent-contrast);
    filter: brightness(1.08);
}

/* Sending (uploader.js): busy, not disabled, so it keeps focus and its colour; repeat clicks are ignored in code. */
.button[aria-busy="true"] { cursor: progress; }

.button[aria-busy="true"]::before {
    content: "";
    display: inline-block;
    width: 0.9em;
    height: 0.9em;
    margin-right: 0.45em;
    vertical-align: -0.1em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .button[aria-busy="true"]::before { animation: none; border-right-color: currentColor; opacity: 0.6; }
}

/* Touch screens: small text controls get a 44px target (ui-patterns H4); the look stays the same. */
@media (pointer: coarse) {
    .link-button-light,
    .pager a,
    .transfers th a,
    .log-table th a,
    .cell-actions a,
    .bug-close {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        min-width: 44px;
        padding-inline: var(--space-2);
    }

    .button { min-height: 44px; }
}

.button:disabled,
.button:disabled:hover {
    background: var(--color-muted);
    cursor: not-allowed;
    filter: none;
    opacity: 0.6;
}

/* Download landing page, and the two send forms: a card at the form width. */

.transfer {
    max-width: var(--form-width);
    margin: var(--space-4) auto;
    padding: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.details {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-1) var(--space-3);
    margin: 0 0 var(--space-4);
}

.details dt {
    color: var(--color-muted);
    font-weight: 600;
}

.details dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.description {
    margin-bottom: var(--space-4);
    overflow-wrap: anywhere;
}

.file-list {
    margin: 0 0 var(--space-4);
    padding: 0;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.file-list li {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-2) var(--space-3);
}

.file-list li + li { border-top: 1px solid var(--color-border); }

.file-name { overflow-wrap: anywhere; }

.file-size {
    color: var(--color-muted);
    white-space: nowrap;
}

.aside {
    margin: var(--space-3) 0 0;
    font-size: 0.95rem;
}

.footer {
    flex-shrink: 0;
    border-top: 1px solid var(--color-border);
    color: var(--color-muted);
    font-size: 0.9rem;
}

.footer-inner {
    max-width: var(--page-width);
    margin: 0 auto;
    padding: var(--space-3);
}

/* Wider screens: the menu is always open and runs along the bar. The links fill the bar's height, so the
   current page's green bar sits on the bar's bottom edge. */

@media (min-width: 48rem) {
    .nav-toggle { display: none; }

    /* The bar never wraps: the links and Sign out keep their width, and a long signed-in address gives way,
       cut with an ellipsis (its title holds the whole address). */
    .topbar-inner { flex-wrap: nowrap; }

    .brand { flex-shrink: 0; }

    .site-nav {
        display: flex;
        flex-basis: auto;
        flex-direction: row;
        align-items: stretch;
        align-self: stretch;
        min-width: 0;
        margin-left: var(--space-3);
        gap: var(--space-1);
        padding-bottom: 0;
    }

    .site-nav a {
        display: flex;
        flex-shrink: 0;
        align-items: center;
        padding: 0 0.85rem;
        border-radius: 0;
        white-space: nowrap;
    }

    .site-nav a[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--color-nav-accent); }

    .signout {
        min-width: 0;
        margin: 0 0 0 var(--space-2);
        padding: 0 0 0 var(--space-3);
        border-top: 0;
        border-left: 1px solid var(--color-nav-line);
        flex-wrap: nowrap;
    }

    .signed-in-as {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow-wrap: normal;
    }

    .signout .link-button {
        flex-shrink: 0;
        white-space: nowrap;
    }

    .page { padding-top: var(--space-5); }
}

/* Sign-in: the home page for anyone not signed in, and /signin. A centred card modelled on the Pathways
   login page. */

.signin {
    max-width: 27rem;
    margin: 0 auto;
}

.signin-card {
    padding: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

@media (min-width: 30rem) {
    .signin-card { padding: var(--space-5) var(--space-5) var(--space-4); }
}

.signin-head {
    margin-bottom: var(--space-4);
    text-align: center;
}

.signin-logo {
    display: block;
    width: auto;
    height: 2.5rem;
    margin: 0 auto var(--space-3);
}

.signin-head h1 {
    margin: 0;
    font-size: 1.35rem;
}

.form.signin-form { align-items: stretch; }

.signin-form .field:not(.code-field) { max-width: none; }

.signin-form .button { text-align: center; }

.signin-divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) 0;
    color: var(--color-muted);
    font-size: 0.9rem;
}

.signin-divider::before,
.signin-divider::after {
    flex: 1;
    border-top: 1px solid var(--color-border);
    content: "";
}

.button-microsoft {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0.6rem 1.1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-muted);
    font-weight: 600;
    text-align: center;
    text-decoration: none;
}

.button-microsoft:hover {
    border-color: var(--color-focus);
    color: var(--color-accent);
}

.microsoft-logo {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
}

.signin-send {
    margin: var(--space-4) 0 0;
    color: var(--color-muted);
    text-align: center;
}

.form {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
}

.form label { font-weight: 600; }

.field {
    width: 100%;
    max-width: 24rem;
    padding: 0.6rem 0.75rem;
    background: var(--color-surface);
    border: 1px solid var(--color-field-border);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font: inherit;
}

.field:focus,
.field:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 0;
    border-color: var(--color-focus);
    box-shadow: 0 0 0 3px var(--color-focus-halo);
}

.code-field {
    max-width: 12rem;
    font-family: var(--font-mono);
    font-size: 1.5rem;
    letter-spacing: 0.3em;
    text-align: center;
}

.hint {
    margin: 0;
    color: var(--color-muted);
    font-size: 0.9rem;
}

.notice,
.error {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
}

.notice {
    background: var(--color-accent-wash);
    border: 1px solid var(--color-accent-wash-border);
}

.error {
    background: #fdecea;
    border: 1px solid #f1b5af;
    color: var(--color-danger-text);
}

.form.again {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

.link-button-light {
    padding: var(--space-1) 0;
    background: none;
    border: 0;
    color: var(--color-accent);
    font: inherit;
    text-decoration: underline;
    cursor: pointer;
}

.link-button-light:hover { color: var(--color-accent-strong); }

/* Upload widget (uploader.js). State comes from classes and the hidden attribute, never style attributes. */
.drop-zone {
    padding: var(--space-4);
    border: 2px dashed var(--color-field-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-soft);
    text-align: center;
}

.drop-zone.is-dragover {
    border-color: var(--color-focus);
    background: var(--color-accent-wash);
}

.upload-row progress {
    flex: 1 1 8rem;
    min-width: 6rem;
    height: 0.75rem;
    accent-color: var(--color-primary);
}

.upload-status {
    color: var(--color-muted);
    white-space: nowrap;
}

/* /staff/send: the addresses again beside Send files (staff-send.js). */
.recipient-summary {
    margin: var(--space-2) 0 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.upload-row.is-done .upload-status { color: var(--color-primary); }
.upload-row.is-error .upload-status { color: var(--color-danger-text); white-space: normal; }

/* Send files (/send, /staff/send) */

.send h2 { margin-top: var(--space-4); }

.send-form { margin-bottom: var(--space-3); }

.send-form textarea.field {
    max-width: 100%;
    resize: vertical;
}

.optional {
    color: var(--color-muted);
    font-weight: 400;
}

/* The recipient look-up on /staff/send (staff-send.js): suggestions drop down under the name field. Without
   the script the wrapper is just the field. */
.combobox {
    position: relative;
    width: 100%;
    max-width: 24rem;
}

.combobox .field { max-width: none; }

.combobox-list {
    position: absolute;
    z-index: 10;
    top: calc(100% + 0.25rem);
    left: 0;
    right: 0;
    max-height: 20rem;
    margin: 0;
    padding: 0.25rem 0;
    overflow-y: auto;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-field-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
}

.combobox-list[hidden] { display: none; }

.combobox-option {
    padding: 0.45rem 0.75rem;
    cursor: pointer;
}

.combobox-option:hover,
.combobox-option.is-active { background: var(--color-accent-wash); }

.combobox-option.is-active {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

.combobox-name,
.combobox-emails {
    display: block;
    overflow-wrap: anywhere;
}

.combobox-name { font-weight: 600; }

.combobox-emails {
    color: var(--color-muted);
    font-size: 0.85rem;
}

.field[readonly] {
    background: var(--color-bg);
    color: var(--color-muted);
}

.uploader .file-list { margin-top: var(--space-3); }

.uploader .file-list:empty { display: none; }

.upload-message { margin: var(--space-3) 0; }

.actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}

/* My files. Each transfer is a card: details on top, actions below on a phone, beside them on wider screens. */

.my-files { margin: var(--space-4) 0; }

.transfer-section { margin-bottom: var(--space-5); }

.empty { color: var(--color-muted); }

/* A flex column with a gap rather than "row + row" margins, so rows the search hides leave no gap behind. */
.transfer-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.transfer-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.transfer-main {
    min-width: 0;
    overflow-wrap: anywhere;
}

.transfer-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
}

.transfer-date,
.transfer-size,
.transfer-label { color: var(--color-muted); }

.transfer-description { margin-top: var(--space-1); }

/* The tracking number opens the transfer's page. */
.transfer-link {
    border-radius: 6px;
    text-decoration: none;
}

.transfer-link .reference {
    border-color: var(--color-accent-wash-border);
    color: var(--color-accent);
    user-select: auto;
}

.transfer-link:hover .reference {
    border-color: var(--color-accent);
    color: var(--color-accent-strong);
    text-decoration: underline;
}

/* The search box above the lists (my-files.js shows it; Admin > Users submits it). */
.list-search {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    max-width: var(--form-width);
    margin-bottom: var(--space-4);
}

.list-search label { font-weight: 600; }

.list-search .field {
    flex: 1 1 16rem;
    max-width: none;
}

.list-search .hint {
    flex-basis: 100%;
    min-height: 1.2em;
}

.transfer-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.transfer-actions form { margin: 0; }

@media (min-width: 40rem) {
    .transfer-row {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
    }

    .transfer-actions { flex-shrink: 0; }
}

/* Staff dashboard (/staff), transfer detail (/staff/transfers/{id}) and the admin tables. On a wide screen a
   table is a card that uses the page's width: short values (dates, numbers, types) never wrap, and long text
   is cut to one line with an ellipsis, its full text in the cell's title. On a phone each row becomes a
   stacked card, each cell labelled from its data-label attribute, and nothing is cut. */

.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-3);
}

.page-head h1 { margin: 0; }

/* The line under the tabs is an inset shadow, not a border, so the current tab (painted above it) hides it
   even though the strip scrolls sideways on a phone where the tabs do not fit. */
.tabs {
    display: flex;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
    overflow-x: auto;
    box-shadow: inset 0 -1px 0 var(--color-border);
}

.tabs a {
    flex-shrink: 0;
    padding: var(--space-2) var(--space-3);
    border: 1px solid transparent;
    border-bottom: 0;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    color: var(--color-muted);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.tabs a:hover { color: var(--color-accent); }

.tabs a[aria-current="page"] {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}

.filters {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2) var(--space-3);
    align-items: end;
    margin-bottom: var(--space-3);
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.filter {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.filter label { font-weight: 600; }

.filter .field { max-width: none; }

/* A select draws shorter than a text field at the same padding; match them so the filter labels line up. */
select.field { min-height: 2.875rem; }

.filter-text,
.filter-actions { grid-column: 1 / -1; }

.filter-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

.result-count { color: var(--color-muted); }

/* The phone-only sort form on /staff and Admin > Users; wider screens sort from the column headers. */
.sort-form { display: none; }

.transfers,
.log-table {
    width: 100%;
    margin: 0;
    border-collapse: collapse;
    background: var(--color-surface);
    font-size: 0.95rem;
}

.transfers th,
.transfers td,
.log-table th,
.log-table td {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    vertical-align: top;
    overflow-wrap: anywhere;
}

.transfers th,
.log-table th {
    background: var(--color-bg-soft);
    color: var(--color-muted);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow-wrap: normal;
}

.transfers tbody tr:last-child td,
.log-table tbody tr:last-child td { border-bottom: 0; }

/* Sortable headers (/staff, Admin > Users): each is a link that sorts by it; the sorted one (aria-sort) is darker and shows
   ▲ or ▼. The arrow is aria-hidden: aria-sort already says which way. */
.transfers th a,
.log-table th a {
    color: inherit;
    text-decoration: none;
}

.transfers th a:hover,
.log-table th a:hover {
    color: var(--color-accent-strong);
    text-decoration: underline;
}

.transfers th[aria-sort],
.log-table th[aria-sort] { color: var(--color-text); }

.sort-indicator {
    margin-left: 0.15rem;
    font-size: 0.75em;
}

/* Short values never break, and their columns shrink to fit (width: 1%), so the spare width goes to the
   text columns. */
.cell-number,
.cell-nowrap,
.cell-actions {
    width: 1%;
    white-space: nowrap;
    overflow-wrap: normal;
}

/* Numbers line up by place value (ui-patterns T1, T2); right-aligned only where they form a column. */
.cell-number { font-variant-numeric: tabular-nums; }

@media (min-width: 48rem) {
    .transfers .cell-number,
    .log-table .cell-number { text-align: right; }
}

/* A second, quieter line in a cell (Downloads: when the first one was). */
.cell-sub {
    display: block;
    color: var(--color-muted);
    font-size: 0.85rem;
}

/* Long text: one line, cut with an ellipsis; the cell's title holds the full text. max-width: 0 stops the
   text's length setting the column's width, so these columns share what the short columns leave, in the
   proportions below, and never push the table wider than its card. */
.cell-truncate {
    width: 22%;
    max-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow-wrap: normal;
}

.cell-description.cell-truncate { width: 32%; }

/* The people and description columns keep a readable width however many short columns there are. */
.cell-party { min-width: 8rem; }

.cell-description { min-width: 10rem; }

/* A table that cannot fit (a narrow tablet) scrolls inside its card rather than widening the page. */
.table-scroll {
    max-width: 100%;
    margin-bottom: var(--space-4);
    overflow-x: auto;
}

.transfers { min-width: 52rem; }

.log-table .is-failed .cell-status { color: var(--color-danger-text); }

/* A failure reason is what someone reads the log for, so a failed row's status wraps rather than being cut. */
.log-table .is-failed .cell-status.cell-truncate {
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
}

.cell-actions form { margin: 0; }

.cc {
    display: block;
    color: var(--color-muted);
    font-size: 0.85rem;
}

.pager {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-3) 0;
}

@media (min-width: 48rem) {
    .table-scroll {
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        box-shadow: var(--shadow);
    }

    /* /staff scrolls sideways on a narrow tablet, so its identity column (Tracking number, the 2nd column)
       stays in view with a solid background and an edge line (ui-patterns T6). */
    .transfers th:nth-child(2),
    .transfers td:nth-child(2) {
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--color-surface);
        /* With collapsed borders a sticky cell leaves its row line behind, so it draws its own; the edge line is
           the 3:1 colour so it shows over the columns scrolling under it. */
        box-shadow: inset 0 -1px 0 var(--color-border), 1px 0 0 var(--color-field-border);
    }

    .transfers th:nth-child(2) { background: var(--color-bg-soft); }
}

@media (max-width: 47.99rem) {
    /* The header row (and its sort links) is hidden below, so the sort form takes over. */
    .sort-form {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
        gap: var(--space-2);
        align-items: end;
        margin-bottom: var(--space-3);
    }

    .sort-form .filter-actions { grid-column: auto; }

    /* Gone, not just clipped: its sort links would still take keyboard focus while invisible. Each cell's
       data-label names it instead. */
    .transfers thead,
    .log-table thead { display: none; }

    .transfers,
    .transfers tbody,
    .transfers tr,
    .transfers td,
    .log-table,
    .log-table tbody,
    .log-table tr,
    .log-table td {
        display: block;
        width: 100%;
    }

    .transfers,
    .log-table {
        min-width: 0;
        background: transparent;
    }

    .transfers tr,
    .log-table tr {
        margin-bottom: var(--space-3);
        padding: var(--space-2) var(--space-3);
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        box-shadow: var(--shadow);
    }

    .transfers td,
    .log-table td,
    .transfers tbody tr:last-child td,
    .log-table tbody tr:last-child td {
        display: grid;
        grid-template-columns: minmax(6rem, 8.5rem) minmax(0, 1fr);
        gap: var(--space-2);
        padding: var(--space-1) 0;
        border-bottom: 0;
        overflow-wrap: anywhere;
    }

    .transfers td::before,
    .log-table td::before {
        content: attr(data-label);
        color: var(--color-muted);
        font-weight: 600;
    }

    /* Nothing is cut on a phone: the stacked card has room for the whole text. */
    .transfers td.cell-truncate,
    .log-table td.cell-truncate,
    .transfers td.cell-party,
    .transfers td.cell-description,
    .log-table td.cell-party {
        width: 100%;
        min-width: 0;
        max-width: none;
        overflow: visible;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* The short-value columns wrap too: a stacked card's value column is narrow. */
    .transfers td.cell-nowrap,
    .transfers td.cell-number,
    .log-table td.cell-nowrap,
    .log-table td.cell-number,
    .log-table td.cell-actions {
        white-space: normal;
    }

    .log-table td.is-empty,
    .log-table tbody tr:last-child td.is-empty { display: none; }
}

/* The transfer pages (/staff/transfers/{id}, /my-files/{id}): a header card, then one card per section, in two
   columns from 60rem (the files, message and logs on the left, the details and the forms on the right) and one
   column below. Each card's title is a real h2 drawn small, like a table header. */

.back { margin-bottom: var(--space-2); }

.detail-card {
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.detail-card > :last-child { margin-bottom: 0; }

.detail-card-danger { border-left: 4px solid var(--color-danger); }

.card-title {
    margin: 0 0 var(--space-2);
    color: var(--color-muted);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.detail-head-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    min-width: 0;
}

.detail-head-title h1 {
    margin: 0;
    overflow-wrap: anywhere;
}

.detail-head-title .hint { flex-basis: 100%; }

.detail-head .actions,
.detail-head .actions form { margin: 0; }

.detail-columns,
.detail-main,
.detail-side {
    display: grid;
    gap: var(--space-3);
    align-content: start;
    min-width: 0;
}

/* A client page whose zip is gone and has no message has nothing for the left column. */
.detail-main:not(:has(*)) { display: none; }

@media (min-width: 60rem) {
    .detail-columns { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}

.detail-card .details,
.detail-card .description { margin: 0; }

.description > :last-child { margin-bottom: 0; }

/* Inside a card, the file list and the tables drop their own box: the card is the box. */
.detail-card .file-list {
    margin: 0;
    background: none;
    border: 0;
    border-radius: 0;
}

.detail-card .file-list li { padding: var(--space-2) 0; }

.file-total {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    font-weight: 600;
}

.detail-card .table-scroll {
    margin: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* On a phone each row is a stacked box inside the card: an edge is enough, no second shadow. */
.detail-card .log-table tr { box-shadow: none; }

.detail-card .log-table tr:last-child { margin-bottom: 0; }

.badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
}

.badge {
    padding: 0.1rem 0.6rem;
    background: var(--color-accent-wash);
    border: 1px solid var(--color-accent-wash-border);
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 600;
}

.badge-muted {
    background: var(--color-bg);
    border-color: var(--color-border);
    color: var(--color-muted);
}

/* The Additional details card: its title is the summary, so the card opens from it. */
.additional summary { cursor: pointer; }

.additional summary .card-title {
    display: inline;
    margin: 0;
}

.additional .details { margin-top: var(--space-2); }

.preserve-lines { white-space: pre-line; }

.stored-listing {
    max-width: 100%;
    overflow-x: auto;
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
}

.inline-form { max-width: var(--form-width); }

.inline-fields {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    width: 100%;
}

.inline-fields .field { flex: 1 1 14rem; }

.button-danger { background: var(--color-danger); }

/* The Nexus "ghost" button: white, grey text, a blue edge on hover. */
.button-secondary {
    background: var(--color-surface);
    /* The edge is what makes it read as a button, so it needs 3:1 (WCAG 1.4.11), like a field's. */
    border-color: var(--color-field-border);
    color: var(--color-muted);
}

.button-secondary:hover {
    border-color: var(--color-focus);
    color: var(--color-accent);
    filter: none;
}

.dialog {
    width: min(30rem, calc(100vw - 2rem));
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    color: var(--color-text);
}

.dialog::backdrop { background: rgba(13, 16, 19, 0.5); }

.dialog h2 { margin-top: 0; }

.dialog-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
}

@media (min-width: 40rem) {
    .filters { grid-template-columns: 2fr 1fr 1fr 1fr; }

    .filter-text { grid-column: auto; }
}

/* Wide enough for one row: Search (and Clear) end the row of filters instead of taking a row of their own. */
@media (min-width: 60rem) {
    .filters { grid-template-columns: 2fr 1fr 1fr 1fr auto; }

    .filters .filter-actions { grid-column: auto; flex-wrap: nowrap; }
}

/* Admin pages (/staff/admin): the tables use the page width, the edit forms the form width. */

.admin h2 { margin-top: var(--space-4); }

.admin .form { max-width: var(--form-width); }

.form .check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 400;
}

.form .check input { margin: 0; }

.field-wide { max-width: 36rem; }

.field-error {
    color: var(--color-danger-text);
    font-size: 0.9rem;
}

.field-error:empty { display: none; }

.error-list {
    margin: 0;
    padding-left: var(--space-3);
}

.log-table .is-inactive { color: var(--color-muted); }

/* Catch a Bug (_BugReport.cshtml, bugreport.js): the floating button and its dialog, for signed-in staff and
   clients. Ported from Nexus. No style attributes anywhere: bugreport.js shows and hides with the hidden
   attribute and the classes below. */

.bug-button {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 30;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.6rem 1rem;
    background: var(--color-accent);
    border: 0;
    border-radius: 999px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.22);
    color: var(--color-accent-contrast);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
}

.bug-button:hover { background: var(--color-accent-strong); }

.bug-button:focus-visible { outline-offset: 3px; }

.bug-icon { flex: none; }

/* The last thing on a page (the footer, or a form's buttons above it) can always be scrolled clear of the
   button. */
.footer:has(~ .bug-button) .footer-inner { padding-bottom: 4.5rem; }

/* Phones: a compact round button. Its name stays (aria-label and title). */
@media (max-width: 47.99rem) {
    .bug-button {
        width: 3rem;
        height: 3rem;
        padding: 0;
        justify-content: center;
    }

    .bug-button-label { display: none; }
}

.bug-dialog {
    width: min(32.5rem, calc(100vw - 2rem));
    max-height: calc(100dvh - 2rem);
    padding: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    color: var(--color-text);
}

.bug-dialog::backdrop { background: rgba(13, 16, 19, 0.5); }

.bug-card { margin: 0; }

.bug-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 0.9rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
}

.bug-head h2 {
    margin: 0;
    font-size: 1.1rem;
}

.bug-close {
    padding: 0 var(--space-2);
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    color: var(--color-muted);
    font: inherit;
    font-size: 1.6rem;
    line-height: 1.2;
    cursor: pointer;
}

.bug-close:hover { color: var(--color-text); }

.bug-content {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: 0.5rem 1.25rem 1rem;
}

.bug-content label {
    margin-top: var(--space-2);
    font-weight: 600;
    font-size: 0.9rem;
}

.bug-content .field { max-width: none; }

.bug-content textarea.field { resize: vertical; }

.bug-content input[type="file"].field {
    padding: 0.45rem 0.6rem;
    font-size: 0.9rem;
}

.bug-content .bug-check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    font-weight: 400;
    font-size: 1rem;
}

.bug-check input {
    width: 1.1rem;
    height: 1.1rem;
    margin: 0;
}

/* Beside a chosen image the automatic screenshot stands down, visibly. */
.bug-content .bug-check.is-disabled { opacity: 0.5; }

.bug-preview {
    align-self: flex-start;
    max-width: 100%;
    max-height: 12rem;
    margin-top: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

/* An image dragged over the dialog: the whole card is the target. */
.bug-card.bug-dragging {
    outline: 2px dashed var(--color-focus);
    outline-offset: -6px;
    background: var(--color-accent-wash);
}

.bug-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: 0.9rem 1.25rem;
    background: var(--color-bg-soft);
    border-top: 1px solid var(--color-border);
}

.bug-status {
    flex: 1 1 100%;
    margin: 0;
    color: var(--color-muted);
    font-size: 0.9rem;
}

@media (min-width: 40rem) {
    .bug-status { flex-basis: 0; }
}

@media print {
    .bug-button,
    .bug-dialog { display: none !important; }
}

/* Admin → Bug reports (BugReports.cshtml): the whole title wraps; the Retry button sits under the status. */

.bug-reports { min-width: 56rem; }

.bug-reports .cell-title { min-width: 14rem; }

.bug-reports .cell-status form { margin: var(--space-2) 0 0; }

.bug-reports .cell-status .button {
    padding: 0.25rem 0.75rem;
    font-size: 0.85rem;
}
