/*
 * Collie:Auction — base stylesheet.
 *
 * Every colour, radius, spacing step and other "magic number" is a CSS
 * variable on :root so the app can be re-themed in one place. Dark mode
 * follows the OS unless the user picks a theme (html[data-theme]).
 */

/* ---------- Design tokens ---------- */

:root {
    color-scheme: light;

    /* Colour */
    --color-bg: #f6f7f9;
    --color-surface: #ffffff;
    --color-surface-muted: #eef0f3;
    --color-border: #d9dde3;
    --color-text: #1b1f24;
    --color-text-muted: #5b6470;
    --color-primary: #1f5fbf;
    --color-primary-hover: #194d9b;
    --color-on-primary: #ffffff;
    --color-danger: #b42318;
    --color-danger-hover: #912018;
    --color-on-danger: #ffffff;
    --color-success-bg: #e7f6ec;
    --color-success-text: #146c2e;
    --color-warning-bg: #fdf3e1;
    --color-warning-text: #8a5300;
    --color-highlight-bg: #fff3a3;
    --color-highlight-text: #3d3300;
    --color-error-bg: #fdecea;
    --color-error-text: #b42318;
    --color-focus: #4d90fe;
    /* Charts: the series colour (validated against the surface for each mode) and a lighter step of it for tracks. */
    --chart-series: #1f5fbf;
    --chart-track: #dce7f8;

    /* Typography */
    --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-size-sm: 0.875rem;
    --font-size-base: 1rem;
    --font-size-lg: 1.25rem;
    --font-size-xl: 1.75rem;
    --font-size-kpi: 2.25rem;
    --font-size-dashboard-kpi: clamp(1.5rem, 17cqi, 4.5rem);
    --line-height: 1.5;
    --font-weight-medium: 500;
    --font-weight-bold: 650;

    /* Spacing */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;

    /* Shape & depth */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-pill: 999px;
    --border-width: 1px;
    --focus-ring-width: 3px;
    --shadow-card: 0 1px 2px rgb(0 0 0 / 0.06), 0 1px 3px rgb(0 0 0 / 0.08);

    /* Layout */
    --content-max-width: 72rem;
    --narrow-max-width: 28rem;
    --page-gutter: 16px;
    --header-height: 3.5rem;
    --logo-max-height: 2.25rem;
    --guest-logo-max-height: 8rem;
    --logo-preview-max-height: 4rem;
    --kpi-min-width: 12rem;
    --chart-height: 8.5rem;
    --form-row-min-width: 14rem;
    --checkbox-grid-min-width: 12rem;
    --permission-grid-column-width: 5.5rem;
    --checkbox-size: 1.125rem;
    --dialog-max-width: 36rem;
    --dialog-form-max-width: 40rem;
    --dialog-form-max-height: 90vh;
    --dialog-form-wide-max-width: 56rem;
    --compact-control-width: 7rem;
    --table-wrap-min-width: 10rem;
    --invoice-logo-max-height: 4rem;
    --paper-bg: #ffffff;
    --paper-text: #000000;
    --paper-text-muted: #444444;
    --paper-border: #c9ccd1;
    --paper-danger: #b42318;
    --report-logo-max-height: 5rem;
    --report-rule-width: 4px;
    --report-group-rule-width: 2px;
    --report-summary-table-min-width: 28rem;
    --program-font-size: var(--font-size-lg);
    --program-photo-width: 1.5in;
    --program-photo-height: 1.125in;
    --program-grid-font-size: var(--font-size-base);
    --program-grid-photo-width: 1in;
    --program-grid-photo-height: 0.75in;
    --program-grid-gutter: 0.375in;
    --program-text-font-size: 12pt;
    --invoice-void-border-width: 4px;
    --invoice-void-font-size: 3.5rem;
    --invoice-void-opacity: 0.6;
    --tab-indicator-width: 2px;
    --run-thumb-size: 4rem;
    /* Matches a two-line table cell: a base-size line plus a small-size line. */
    --table-thumb-height: calc(var(--line-height) * (var(--font-size-base) + var(--font-size-sm)));
    /* A 4:3 box. */
    --table-thumb-width: calc(var(--table-thumb-height) * 4 / 3);
    /* Item Sort mode's starting-lot box: room for six digits and the spinner. */
    --lot-sort-start-width: 8rem;
    --live-max-width: 90rem;
    --live-photo-height: 60vh;
    --font-size-live-lot: clamp(1.25rem, 2.5vw, 2rem);
    --font-size-live-name: clamp(1.5rem, 3.75vw, 3.375rem);
    --live-logo-max-height: calc(var(--logo-max-height) * 2);
    --photo-thumb-min-width: 10rem;
    --import-column-width: 10rem;
    --import-cell-max-width: 16rem;
    --import-count-min-width: 8rem;
    --import-heading-row-opacity: 0.55;
    --font-family-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    --shadow-dialog: 0 10px 30px rgb(0 0 0 / 0.2);
    --color-backdrop: rgb(0 0 0 / 0.45);

    /* Motion */
    --transition-fast: 120ms ease;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --chart-series: #5594ea;
        --chart-track: #24344d;
        --color-bg: #0f1216;
        --color-surface: #181c22;
        --color-surface-muted: #222831;
        --color-border: #323a45;
        --color-text: #e8ebef;
        --color-text-muted: #9aa4b1;
        --color-primary: #5b9bf0;
        --color-primary-hover: #7cb0f4;
        --color-on-primary: #0b1420;
        --color-danger: #f0776c;
        --color-danger-hover: #f4958c;
        --color-on-danger: #1f0907;
        --color-success-bg: #12301d;
        --color-success-text: #7fd69c;
        --color-warning-bg: #36270b;
        --color-warning-text: #f2c46d;
        --color-highlight-bg: #5c4d00;
        --color-highlight-text: #fff6c2;
        --color-error-bg: #3a1512;
        --color-error-text: #f59c93;
        --color-focus: #7cb0f4;
        --shadow-card: 0 1px 2px rgb(0 0 0 / 0.4);
    }
}

:root[data-theme="dark"] {
    --chart-series: #5594ea;
    --chart-track: #24344d;
    color-scheme: dark;
    --color-bg: #0f1216;
    --color-surface: #181c22;
    --color-surface-muted: #222831;
    --color-border: #323a45;
    --color-text: #e8ebef;
    --color-text-muted: #9aa4b1;
    --color-primary: #5b9bf0;
    --color-primary-hover: #7cb0f4;
    --color-on-primary: #0b1420;
    --color-danger: #f0776c;
    --color-danger-hover: #f4958c;
    --color-on-danger: #1f0907;
    --color-success-bg: #12301d;
    --color-success-text: #7fd69c;
    --color-warning-bg: #36270b;
    --color-warning-text: #f2c46d;
    --color-highlight-bg: #5c4d00;
    --color-highlight-text: #fff6c2;
    --color-error-bg: #3a1512;
    --color-error-text: #f59c93;
    --color-focus: #7cb0f4;
    --shadow-card: 0 1px 2px rgb(0 0 0 / 0.4);
}

/* ---------- Base ---------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    line-height: var(--line-height);
}

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

/* Keep the hidden attribute authoritative over any component display rules. */
[hidden] {
    display: none !important;
}

a {
    color: var(--color-primary);
}

h1,
h2,
h3 {
    margin: 0;
    line-height: 1.2;
}

p {
    margin: 0 0 var(--space-3);
}

:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-focus);
    outline-offset: 2px;
}

/* ---------- Layout ---------- */

/* Pinned to the top while the page scrolls (below toasts; modal dialogs sit above everything). */
.site-header {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
    min-height: var(--header-height);
    padding: var(--space-2) var(--page-gutter);
    background: var(--color-surface);
    border-bottom: var(--border-width) solid var(--color-border);
}

.brand {
    display: inline-flex;
    align-items: center;
    color: var(--color-text);
    text-decoration: none;
}

.brand__logo {
    display: block;
    max-height: var(--logo-max-height);
    width: auto;
}

.brand__name {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.site-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    flex: 1;
}

.site-nav__link {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    text-decoration: none;
    font-weight: var(--font-weight-medium);
}

.site-nav__link:hover,
.site-nav__link.is-active {
    background: var(--color-surface-muted);
    color: var(--color-text);
}

.user-menu {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-left: auto;
}

.user-menu__name {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.site-main {
    width: 100%;
    max-width: var(--content-max-width);
    margin: 0 auto;
    padding: var(--space-5) var(--page-gutter);
}

.layout-minimal {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.minimal-header {
    display: flex;
    justify-content: center;
    padding: var(--space-5) var(--page-gutter) var(--space-3);
}

.minimal-header .brand__logo {
    max-height: var(--guest-logo-max-height);
    max-width: 100%;
}

.minimal-main {
    flex: 1;
    width: 100%;
    padding: var(--space-4) var(--page-gutter);
}

.page-header {
    margin-bottom: var(--space-5);
}

.page-header--split {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
}

.page-title {
    font-size: var(--font-size-xl);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.page-subtitle {
    margin-top: var(--space-1);
    color: var(--color-text-muted);
}

.section-title {
    margin-bottom: var(--space-4);
    font-size: var(--font-size-lg);
}

.section-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.section-header .section-title {
    margin-bottom: 0;
}

/* The line under a section title, e.g. the auction page's "1 of 5 found". */
.section-subtitle {
    margin-top: var(--space-1);
    color: var(--color-text-muted);
}

/* A full-width search box between a section header and its table. */
.section-search {
    margin-bottom: var(--space-4);
}

/* A list of radio options with a title and a detail line, e.g. contact search results. */
.choice-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.choice-list__option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
}

.choice-list__option:has(input:checked) {
    border-color: var(--color-primary);
    background: var(--color-surface-muted);
}

.choice-list__option input {
    margin-top: var(--space-1);
}

/* Not selectable (e.g. already registered): the marker sits where the radio would be. */
.choice-list__option--registered {
    cursor: default;
    background: var(--color-surface-muted);
}

.choice-list__marker {
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}

/* Modal dialog (<dialog>), opened with [data-dialog-open] and closed with [data-dialog-close]. */
.dialog {
    width: min(var(--dialog-max-width), calc(100vw - 2 * var(--page-gutter)));
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-dialog);
}

.dialog::backdrop {
    background: var(--color-backdrop);
}

/*
 * Standard form layout (<x-dialog-form>): header, scrolling body, footer
 * (danger buttons left; regular and primary buttons right). In the dialog
 * the body scrolls so the footer stays visible; as a page it's a card.
 */
.dialog--form {
    width: min(var(--dialog-form-max-width), calc(100vw - 2 * var(--page-gutter)));
    max-height: var(--dialog-form-max-height);
    padding: 0;
    overflow: hidden;
}

.dialog--form[open] {
    display: flex;
    flex-direction: column;
}

/* Larger forms (<x-dialog-form wide>) get a wider dialog. */
.dialog--form:has(.dialog-form--wide) {
    width: min(var(--dialog-form-wide-max-width), calc(100vw - 2 * var(--page-gutter)));
}

.dialog-form {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.dialog--form .dialog-form {
    flex: 1;
}

.dialog-form__header {
    padding: var(--space-4) var(--space-5);
    border-bottom: var(--border-width) solid var(--color-border);
}

.dialog-form__title {
    font-size: var(--font-size-lg);
}

.dialog-form__header .page-subtitle {
    margin-bottom: 0;
}

.dialog-form__body {
    flex: 1;
    min-height: 0;
    padding: var(--space-5);
    overflow-y: auto;
}

.dialog-form__body > * + * {
    margin-top: var(--space-4);
}

.dialog-form__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-5);
    border-top: var(--border-width) solid var(--color-border);
    background: var(--color-surface);
}

.dialog-form__danger,
.dialog-form__start,
.dialog-form__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.dialog-form__actions {
    margin-left: auto;
    justify-content: flex-end;
}

/* As a full page: a card, with the header and footer inset like the dialog. */
.dialog-form--page {
    padding: 0;
}

.dialog-form--page .dialog-form__header {
    border-bottom: var(--border-width) solid var(--color-border);
}

/*
 * Tabs (<x-tabs> + <x-tab-panel>). In a dialog form's header the bar sits
 * on the header's bottom border, with the selected tab underlined.
 */
.tabs {
    display: flex;
    gap: var(--space-1);
    overflow-x: auto;
    border-bottom: var(--border-width) solid var(--color-border);
}

.dialog-form__header .tabs {
    margin: var(--space-3) 0 calc(-1 * (var(--space-4) + var(--border-width)));
    border-bottom: 0;
}

.tabs__tab {
    padding: var(--space-2) var(--space-3);
    border: 0;
    border-bottom: var(--tab-indicator-width) solid transparent;
    background: none;
    color: var(--color-text-muted);
    font: inherit;
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
    cursor: pointer;
}

.tabs__tab:hover {
    color: var(--color-text);
}

.tabs__tab[aria-selected="true"] {
    border-bottom-color: var(--color-primary);
    color: var(--color-primary);
}

.tabs__tab:focus-visible {
    outline-offset: calc(-1 * var(--focus-ring-width));
}

/* A tab bar at the top of a card (e.g. the auction page's Items / Bidders). */
.card > .tabs {
    margin-bottom: var(--space-4);
}

/* Only one panel shows, so it needs no gap from the hidden ones before it. */
.dialog-form__body > .tabs__panel {
    margin-top: 0;
}

.tabs__panel > * + * {
    margin-top: var(--space-4);
}

/* Compact controls for table rows and toolbars (e.g. the add-bid row). */
.field__control--compact {
    width: var(--compact-control-width);
    padding: var(--space-1) var(--space-2);
}

.button--icon {
    padding: var(--space-1) var(--space-2);
    line-height: 1;
}

/* Run Auction dialog. */
.run-auction__header {
    display: flex;
    align-items: center;
    gap: var(--space-4);
}

.run-auction__thumb {
    flex-shrink: 0;
    width: var(--run-thumb-size);
    height: var(--run-thumb-size);
    object-fit: contain;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-muted);
}

.run-auction__jump {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.run-bids__totals th,
.run-bids__totals td {
    font-weight: var(--font-weight-bold);
}

.run-bids__add td {
    vertical-align: middle;
}

/*
 * Live screen (projector / TV): large type and the current lot's photos,
 * cycled by app.js. Uses the page's theme colours.
 */
.layout-live .minimal-header {
    align-items: center;
    gap: var(--space-5);
}

.layout-live .brand__logo {
    max-height: var(--live-logo-max-height);
}

.minimal-header__title {
    font-size: var(--font-size-live-lot);
    font-weight: var(--font-weight-bold);
}

.layout-live .minimal-main {
    display: flex;
    align-items: center;
    justify-content: center;
}

.live-current {
    width: 100%;
    max-width: var(--live-max-width);
    text-align: center;
}

.live-current__lot {
    margin: 0 0 var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--font-size-live-lot);
    font-weight: var(--font-weight-medium);
}

.live-current__name {
    margin-bottom: var(--space-5);
    font-size: var(--font-size-live-name);
    line-height: 1.15;
}

.live-photos {
    position: relative;
    height: var(--live-photo-height);
}

.live-photos__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    opacity: 0;
    transition: opacity 600ms ease;
}

.live-photos__image.is-active {
    opacity: 1;
}

.live-current__closing {
    padding: var(--space-6) 0;
}

/* Toasts (app:toast): brief messages at the top of the page, or of the open dialog. */
.toast-region {
    position: fixed;
    top: var(--space-4);
    left: 50%;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    width: max-content;
    max-width: calc(100vw - 2 * var(--page-gutter));
    transform: translateX(-50%);
    pointer-events: none;
}

.toast {
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-dialog);
    font-weight: var(--font-weight-medium);
    transition: opacity 300ms ease;
}

.toast--success {
    background: var(--color-success-bg);
    color: var(--color-success-text);
}

.toast--error {
    background: var(--color-error-bg);
    color: var(--color-error-text);
}

.toast--leaving {
    opacity: 0;
}

/* Item photos: thumbnails in display order with move/delete controls. */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--photo-thumb-min-width), 1fr));
    gap: var(--space-4);
    margin: 0 0 var(--space-5);
    padding: 0;
    list-style: none;
}

.photo-grid__item {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.photo-grid__image {
    width: 100%;
    aspect-ratio: 4 / 3;
    /* contain, not cover: show the whole photo (letterboxed) rather than clipping odd shapes. */
    object-fit: contain;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-muted);
}

/* Area that accepts dropped image files; highlights while a file is dragged over it. */
.dropzone {
    padding: var(--space-3);
    border: var(--border-width) dashed var(--color-border);
    border-radius: var(--radius-md);
}

.dropzone.is-dragover {
    border-color: var(--color-primary);
    background: var(--color-surface-muted);
}

.dropzone > :last-child {
    margin-bottom: 0;
}

/* Photos chosen but not yet uploaded. */
.photo-grid--pending {
    margin: var(--space-3) 0 0;
}

.photo-grid--pending .photo-grid__image {
    border-style: dashed;
}

.photo-grid__item[draggable="true"] {
    cursor: grab;
}

.photo-grid__item.is-dragging {
    opacity: 0.4;
}

.photo-grid__actions {
    display: flex;
    justify-content: center;
    gap: var(--space-1);
}

/* A collapsible section built on <details>/<summary>. */
.disclosure__summary {
    color: var(--color-primary);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
}

.disclosure__body {
    margin-top: var(--space-3);
}

.choice-list__title {
    display: block;
    font-weight: var(--font-weight-medium);
}

.choice-list__detail {
    display: block;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.stack > * + * {
    margin-top: var(--space-5);
}

.cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* ---------- Card ---------- */

.card {
    padding: var(--space-5);
    background: var(--color-surface);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

.card--narrow {
    max-width: var(--narrow-max-width);
    margin: 0 auto;
}

/* ---------- KPI ---------- */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--kpi-min-width), 1fr));
    gap: var(--space-4);
}

.kpi {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.kpi__label {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.kpi__value {
    font-size: var(--font-size-kpi);
    font-weight: var(--font-weight-bold);
    line-height: 1.1;
}

/*
 * The dashboard: one card per auction (header with name and dates, then its
 * KPIs in two rows of three: the figures, then the charts, with the cumulative
 * chart two columns wide). One column on a phone.
 */
.dashboard-auction__header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.dashboard-auction__header .section-title {
    margin-bottom: 0;
}

.dashboard-kpis {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
}

/*
 * Twice the standard KPI figure, scaled to the KPI box's own width (cqi), not
 * the viewport's, so "$123,456.00" still fits however wide the window is.
 */
.dashboard-kpis .kpi__value {
    font-size: var(--font-size-dashboard-kpi);
}

.dashboard-kpis .kpi {
    container-type: inline-size;
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
}

.kpi--wide {
    grid-column: span 2;
}

@media (max-width: 40rem) {
    .dashboard-kpis {
        grid-template-columns: minmax(0, 1fr);
    }

    .kpi--wide {
        grid-column: auto;
    }
}

/* A chart container (app.js draws into it); its height includes the axis labels. */
.chart {
    width: 100%;
    height: var(--chart-height);
}

/* ---------- Buttons ---------- */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    font: inherit;
    font-weight: var(--font-weight-medium);
    text-decoration: none;
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.button:hover {
    background: var(--color-surface-muted);
}

.button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

.button--primary {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
}

.button--primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.button--danger {
    background: var(--color-danger);
    border-color: var(--color-danger);
    color: var(--color-on-danger);
}

.button--danger:hover {
    background: var(--color-danger-hover);
    border-color: var(--color-danger-hover);
}

.button--ghost {
    background: transparent;
    border-color: transparent;
}

/* ---------- Forms ---------- */

.form > * + * {
    margin-top: var(--space-4);
}

.form__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--form-row-min-width), 1fr));
    gap: var(--space-4);
}

.form__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: flex-end;
}

.form__actions--split {
    align-items: center;
    justify-content: space-between;
}

.auth-title {
    margin-bottom: var(--space-4);
}

.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.field__label {
    font-weight: var(--font-weight-medium);
}

.field__label--secondary {
    margin-top: var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.field__control {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    font: inherit;
}

.field__control[type="file"] {
    padding: var(--space-2);
}

.field--invalid .field__control {
    border-color: var(--color-error-text);
}

.field__hint {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.field__error {
    margin: 0;
    color: var(--color-error-text);
    font-size: var(--font-size-sm);
}

.fieldset {
    margin: 0;
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
}

.fieldset > * + * {
    margin-top: var(--space-3);
}

/* Groups fields without visual chrome; used to disable a whole form for read-only users. */
.fieldset-plain {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.fieldset-plain > * + * {
    margin-top: var(--space-4);
}

.fieldset-plain:disabled .field__control {
    background: var(--color-surface-muted);
    color: var(--color-text-muted);
}

.permission-grid th[scope="row"] {
    color: var(--color-text);
    font-size: var(--font-size-base);
}

.permission-grid .permission-grid__action {
    width: var(--permission-grid-column-width);
    text-align: center;
}

.permission-grid input[type="checkbox"] {
    width: var(--checkbox-size);
    height: var(--checkbox-size);
}

.permission-grid__unavailable {
    color: var(--color-text-muted);
}

.fieldset__legend {
    padding: 0 var(--space-2);
    font-weight: var(--font-weight-medium);
}

.checkbox {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.checkbox-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--checkbox-grid-min-width), 1fr));
    gap: var(--space-2) var(--space-4);
}

.logo-preview {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
}

.logo-preview__image {
    max-height: var(--logo-preview-max-height);
    width: auto;
}

/* ---------- Alerts & badges ---------- */

.alert {
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
}

.alert--success {
    background: var(--color-success-bg);
    color: var(--color-success-text);
}

.alert--error {
    background: var(--color-error-bg);
    color: var(--color-error-text);
}

/* Guidance for a mode or task (e.g. item Sort mode). */
.alert--info {
    border: var(--border-width) solid var(--color-border);
    background: var(--color-surface-muted);
    color: var(--color-text);
}

a.badge {
    text-decoration: none;
}

.badge {
    display: inline-block;
    padding: 0 var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--color-surface-muted);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.badge--success {
    background: var(--color-success-bg);
    color: var(--color-success-text);
}

.badge--warning {
    background: var(--color-warning-bg);
    color: var(--color-warning-text);
}

.badge--danger {
    background: var(--color-error-bg);
    color: var(--color-error-text);
}

/* ---------- Tables ---------- */

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

.table {
    width: 100%;
    border-collapse: collapse;
}

.table th,
.table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-width) solid var(--color-border);
    text-align: left;
    white-space: nowrap;
}

.table th {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* Scoped under .table so it outranks the default left alignment for both th and td. */
.table .table__number {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/*
 * A column whose text may wrap (cells don't by default), e.g. a long item name in
 * a narrow dialog, so the columns after it stay in view instead of scrolling.
 */
.table .table__wrap {
    min-width: var(--table-wrap-min-width);
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Keep the cell a real table cell (display: flex here breaks column alignment); lay out buttons in an inner group. */
.table .table__actions {
    width: 1%;
    text-align: right;
}

.table__actions-group {
    display: inline-flex;
    gap: var(--space-2);
    vertical-align: middle;
}

/*
 * An amount coloured by payment status (e.g. a bidder's total bids): paid in
 * full, not paid, or partly paid. The cell's title says which, for when colour
 * isn't enough.
 */
.table .amount--paid {
    color: var(--color-success-text);
    font-weight: var(--font-weight-medium);
}

.table .amount--unpaid {
    color: var(--color-danger);
    font-weight: var(--font-weight-medium);
}

.table .amount--partial {
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
}

/*
 * Auction page items table: Lot | thumbnail | name over seller | Qty | $.
 * The item cell takes the leftover width (width: 100% with max-width: 0) and cuts
 * long text off with an ellipsis, so the table fits without scrolling sideways.
 */
.table--items td {
    vertical-align: middle;
}

.table .table__thumb-cell {
    width: 1%;
    padding-right: 0;
}

/*
 * max-width: none overrides the global img { max-width: 100% }: in a table cell that
 * makes the image shrinkable, so its shrink-to-fit column collapsed when no row had
 * the (non-image) placeholder to hold it open.
 */
.table__thumb {
    display: block;
    width: var(--table-thumb-width);
    max-width: none;
    height: var(--table-thumb-height);
    object-fit: contain;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface-muted);
}

.table .table__item {
    width: 100%;
    max-width: 0;
    min-width: var(--table-wrap-min-width);
}

.table__item-line {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.table__item-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: var(--font-weight-bold);
}

.table__item-line .badge {
    flex-shrink: 0;
}

.table__item-detail {
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* The lot currently up for bid (auction page items table). */
.table .table__row--live td {
    background: var(--color-highlight-bg);
    color: var(--color-highlight-text);
}

.table__empty {
    color: var(--color-text-muted);
    text-align: center;
}

/*
 * Item Sort mode (items/sort): handle | New | Was | thumbnail | item | ↑ ↓.
 * Rows are dragged by the handle only, so the rest of the row still scrolls on touch.
 */
.lot-sort__guide > p {
    margin: 0;
}

.lot-sort__guide > p + p {
    margin-top: var(--space-2);
}

.lot-sort__start {
    display: inline-block;
    width: var(--lot-sort-start-width);
    padding-top: var(--space-1);
    padding-bottom: var(--space-1);
    text-align: right;
}

.lot-sort__warning {
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
}

.table .lot-sort__handle-cell {
    width: 1%;
    padding-right: 0;
}

.lot-sort__handle {
    display: inline-block;
    padding: var(--space-1) var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--font-size-lg);
    line-height: 1;
    cursor: grab;
    touch-action: none;
    user-select: none;
}

.lot-sort__handle:active {
    cursor: grabbing;
}

.table .lot-sort__new {
    font-weight: var(--font-weight-bold);
}

.table .lot-sort__was {
    color: var(--color-text-muted);
}

.table .lot-sort__row--changed .lot-sort__new {
    color: var(--color-primary);
}

/* The drop placeholder while dragging, and the row being dragged. */
.table .lot-sort__row--ghost td {
    background: var(--color-surface-muted);
    opacity: 0.5;
}

.table .lot-sort__row--chosen td {
    background: var(--color-surface-muted);
}

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.pagination [aria-disabled="true"] {
    opacity: 0.55;
    pointer-events: none;
}

.pagination__status {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* ---------- Small screens ---------- */

@media (max-width: 40rem) {
    .card {
        padding: var(--space-4);
    }

    .page-title {
        font-size: var(--font-size-lg);
    }

    .form__actions .button {
        width: 100%;
    }
}

/*
 * Checkout (checkout.show): the bidder # box, the invoice preview, and a
 * button per payment type in the footer.
 */
.checkout__lookup {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

.checkout__lookup .field__label {
    margin: 0;
}

.checkout__payments {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* The hidden frame that [data-print-url] buttons print from (app.js). */
.print-frame {
    position: fixed;
    right: 0;
    bottom: 0;
    width: 0;
    height: 0;
    border: 0;
}

/*
 * A wrapper around a footer button that's swapped out-of-band (e.g. the bidder
 * dialog's Checkout): takes no space of its own, so an empty one adds no gap.
 */
.dialog-form__inline-action {
    display: contents;
}

/*
 * Paper: a printable document (invoice, report) always shown black on white,
 * even in dark mode, so the screen matches the printout. It redefines the
 * colour tokens for everything inside it.
 */
.paper {
    --color-surface: var(--paper-bg);
    --color-surface-muted: var(--paper-bg);
    --color-border: var(--paper-border);
    --color-text: var(--paper-text);
    --color-text-muted: var(--paper-text-muted);
    --color-danger: var(--paper-danger);

    padding: var(--space-5);
    border: var(--border-width) solid var(--paper-border);
    border-radius: var(--radius-md);
    background: var(--paper-bg);
    color: var(--paper-text);
    color-scheme: light;
}

/*
 * An invoice (invoices.partials.document, on .paper): company and invoice
 * details side by side, the bidder info, then the lines and total.
 */
.invoice {
    position: relative;
}

.invoice p {
    margin: 0;
}

.invoice__header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-5);
    margin-bottom: var(--space-5);
}

.invoice__logo {
    display: block;
    max-height: var(--invoice-logo-max-height);
    margin-bottom: var(--space-2);
}

.invoice__company-name {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.invoice__meta {
    text-align: right;
}

.invoice__title {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
}

.invoice__details {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: end;
    gap: var(--space-1) var(--space-3);
    margin: var(--space-2) 0 0;
}

.invoice__details dt {
    color: var(--color-text-muted);
}

.invoice__details dd {
    margin: 0;
}

.invoice__bill-to {
    margin-bottom: var(--space-4);
}

.invoice__label {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.invoice__bill-to-name {
    font-weight: var(--font-weight-bold);
}

.table .invoice__total th,
.table .invoice__total td {
    border-bottom: 0;
    color: var(--color-text);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
}

/* A voided invoice: a rotated stamp across it. */
.invoice__void-stamp {
    position: absolute;
    top: 45%;
    left: 50%;
    padding: var(--space-1) var(--space-4);
    border: var(--invoice-void-border-width) solid var(--color-danger);
    border-radius: var(--radius-md);
    color: var(--color-danger);
    font-size: var(--invoice-void-font-size);
    font-weight: var(--font-weight-bold);
    text-transform: uppercase;
    opacity: var(--invoice-void-opacity);
    transform: translate(-50%, -50%) rotate(-15deg);
    pointer-events: none;
}

/* The auction page's Reports tab: one row per report, with View and Download. */
.report-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.report-list__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: var(--border-width) solid var(--color-border);
}

.report-list__title {
    margin: 0;
    font-weight: var(--font-weight-bold);
}

/*
 * Reports (reports.*, on .paper), after the layout of the organizer's existing
 * reports: logo left, auction name and report title centred, a double rule,
 * summary figures, then grouped tables. Outstanding amounts are red (accounting
 * style, and it prints clearly); everything else is black.
 */
.report-toolbar {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.report p {
    margin: 0;
}

.report__header {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-4);
}

.report__logo {
    display: block;
    max-height: var(--report-logo-max-height);
}

.report__company {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.report__titles {
    text-align: center;
}

.report__auction {
    font-size: var(--font-size-xl);
}

.report__title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.report__run-date {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-align: right;
}

.report__rule {
    margin: var(--space-3) 0;
    border: 0;
    border-top: var(--report-rule-width) double var(--color-text);
}

.report__summary {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: start;
    gap: var(--space-1) var(--space-4);
    margin: 0 0 var(--space-5);
}

.report__summary dt {
    font-weight: var(--font-weight-bold);
}

.report__summary dd {
    margin: 0;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.report__table {
    width: 100%;
    border-collapse: collapse;
}

.report__table th,
.report__table td {
    padding: var(--space-1) var(--space-2);
    text-align: left;
    vertical-align: top;
}

.report__table thead th {
    font-weight: var(--font-weight-bold);
}

.report__table .report__number {
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* A bidder: their name line, a heavy rule, then their lots' column headings. */
.report__group-header th,
.report__group-header td {
    padding-top: var(--space-5);
    border-bottom: var(--report-group-rule-width) solid var(--color-text);
}

.report__group-header th {
    font-weight: var(--font-weight-medium);
}

.report__contact {
    display: block;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: normal;
}

.report__columns th {
    font-weight: var(--font-weight-bold);
}

.report__table--lots tbody td {
    border-bottom: var(--border-width) solid var(--color-border);
}

/* A short summary table (e.g. Payment Summary) needn't stretch across the page. */
.report__table--summary {
    width: auto;
    min-width: min(100%, var(--report-summary-table-min-width));
}

.report__totals th,
.report__totals td {
    border-top: var(--report-group-rule-width) solid var(--color-text);
    font-weight: var(--font-weight-bold);
}

.report__outstanding {
    color: var(--color-danger);
}

.report__empty {
    color: var(--color-text-muted);
}

/*
 * The Auction Program (reports.program): an attendee handout of Lot | photo |
 * full name over donor, in larger type than the other reports.
 */
/* The report header, as the first <thead> row so it repeats on every printed page. */
.report__table .report__masthead {
    padding: 0 0 var(--space-4);
}

.report__table--program {
    font-size: var(--program-font-size);
}

.report__table--program td {
    vertical-align: middle;
}

.report__table--program .report__program-lot {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.report__table--program .report__program-photo-cell {
    width: 1%;
}

/* max-width: none overrides the global img { max-width: 100% } (see .table__thumb). */
.report__program-photo {
    display: block;
    width: var(--program-photo-width);
    max-width: none;
    height: var(--program-photo-height);
    object-fit: contain;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface-muted);
}

.report__program-name {
    font-weight: var(--font-weight-bold);
}

.report__program-donor {
    color: var(--color-text-muted);
    font-size: var(--font-size-base);
}

/*
 * Two columns (reports.program-two-column): each cell is photo | "Lot # - name"
 * over donor, with a gutter between the left and right lots.
 */
.report__table--program-grid {
    table-layout: fixed;
    font-size: var(--program-grid-font-size);
}

.report__table--program-grid tbody td {
    width: 50%;
    padding: var(--space-2) calc(var(--program-grid-gutter) / 2);
    border-bottom: var(--border-width) solid var(--color-border);
}

.report__table--program-grid tbody td:first-child {
    padding-left: 0;
}

.report__table--program-grid tbody td:last-child {
    padding-right: 0;
}

.report__table--program-grid .report__program-photo {
    width: var(--program-grid-photo-width);
    height: var(--program-grid-photo-height);
}

.report__table--program-grid .report__program-donor {
    font-size: var(--font-size-sm);
}

/* The grid is on an inner div so the td stays a table cell. */
.report__lot-card {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    gap: var(--space-2);
}

/*
 * Text only (reports.program-text-only): the original program's plain
 * Lot # | Description | Donor table, every cell in the same small type.
 */
.report__table--program-text {
    font-size: var(--program-text-font-size);
}

.report__table--program-text th,
.report__table--program-text .report__program-lot {
    white-space: nowrap;
}

/*
 * Printing (e.g. an invoice's print page): just the content, black on white
 * whatever the screen theme. Kept last so these tokens win over the dark ones.
 */
/*
 * Item import wizard (in the wide dialog). The paste box keeps tabs readable;
 * the mapping grid scrolls sideways inside the dialog body, with a select
 * over each column and the heading row greyed while it isn't imported.
 */
.import-paste {
    font-family: var(--font-family-mono);
    font-size: var(--font-size-sm);
    tab-size: 4;
    white-space: pre;
    overflow-x: auto;
}

.import-grid th,
.import-grid td {
    max-width: var(--import-cell-max-width);
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: top;
}

.import-grid thead th {
    min-width: var(--import-column-width);
}

.import-grid thead .import-grid__row-number,
.import-grid__row-number {
    min-width: 0;
    width: 1%;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.import-grid__letter {
    display: block;
    margin-bottom: var(--space-1);
}

.import-grid select {
    width: 100%;
}

.import-grid--has-headings tbody tr:first-child td {
    opacity: var(--import-heading-row-opacity);
    font-style: italic;
}

.import-summary__counts {
    grid-template-columns: repeat(auto-fill, minmax(var(--import-count-min-width), 1fr));
}

.import-summary__group > * + * {
    margin-top: var(--space-2);
}

.import-summary__group .section-subtitle {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

@media print {
    /* As specific as the dark-mode selectors (:root:not([data-theme="light"]), :root[data-theme="dark"]); later, so these win. */
    :root:not([data-theme="print"]),
    :root[data-theme] {
        --color-bg: #ffffff;
        --color-surface: #ffffff;
        --color-surface-muted: #ffffff;
        --color-border: #999999;
        --color-text: #000000;
        --color-text-muted: #444444;
        --color-danger: #b42318;
        color-scheme: light;
    }

    .site-header,
    .alert,
    .toast-region,
    #app-dialog,
    .dialog-form__header,
    .dialog-form__footer {
        display: none !important;
    }

    .site-main {
        max-width: none;
        padding: 0;
    }

    .dialog-form--page.card {
        padding: 0;
        border: 0;
        box-shadow: none;
    }

    .dialog-form--page .dialog-form__body {
        padding: 0;
        overflow: visible;
    }

    .paper {
        padding: 0;
        border: 0;
    }

    .report-toolbar {
        display: none !important;
    }

    .report__group {
        break-inside: avoid;
    }

    .report--program {
        page: program;
    }

    .report__table--program tr,
    .report__table--program-grid tr,
    .report__table--program-text tr {
        break-inside: avoid;
    }

    .invoice .table tr {
        break-inside: avoid;
    }

    .table-wrap {
        overflow: visible;
    }
}

/* The Auction Program prints on US Letter paper. (Literal margin: @page descriptors don't take var().) */
@page program {
    size: letter;
    margin: 0.5in;
}
