/*
  The app-wide sheet: the few base rules no single component owns.

  The nocturne tokens these consume are declared once, in ClientCommon's nocturne.css, which
  App.razor links before this sheet so every client is painted from the same palette.
*/

html,
body {
    background: var(--nocturne-ground);
    color: var(--nocturne-text);
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
}

body {
    margin: 0;
}

/* FocusOnNavigate moves focus to the page's heading on every navigation; it is not a control. */
h1:focus {
    outline: none;
}

.invalid {
    outline: 1px solid var(--nocturne-accent-edge);
}

.validation-message {
    color: var(--nocturne-accent-bright);
}

/* The template's error boundary as Nocturne draws an error: neutral grey, a 2px left edge, never red. */
.blazor-error-boundary {
    padding: 1rem 1.25rem;
    border: 1px solid var(--nocturne-line);
    border-left: 2px solid var(--nocturne-text-muted);
    border-radius: 8px;
    background: var(--nocturne-raised);
    color: var(--nocturne-text);
}

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

/*
  Print (#224): the browser's Save as PDF is the PDF export (specification-v2 §10), so a page prints as
  ink on paper. A browser drops backgrounds when printing, so the tokens are redeclared here for paper
  rather than left to print Nocturne's light text on white. Every component consumes the tokens, so none
  needs a print palette of its own; each hides only its own chrome. The selector matches nocturne.css's
  themed blocks (:root[data-theme="…"]) in specificity and comes after them, so paper wins in every theme
  (#328) — a bare :root would lose to the light theme's own values.
*/
@page {
    margin: 16mm 15mm;
}

@media print {
    :root,
    :root[data-theme] {
        --nocturne-ground: #fff;
        --nocturne-rail: #fff;
        --nocturne-surface: #fff;
        --nocturne-raised: #fff;
        --nocturne-raised-alt: #fff;
        --nocturne-line: #9a9aa3;
        --nocturne-line-soft: #c9c9d0;
        --nocturne-line-mid: #9a9aa3;
        --nocturne-line-strong: #6b6b75;
        --nocturne-accent: #4b3f8f;
        --nocturne-accent-bright: #3b307a;
        --nocturne-accent-text: #3b307a;
        --nocturne-accent-pale: #3b307a;
        --nocturne-accent-edge: #6b6b75;
        --nocturne-accent-deep: #fff;
        --nocturne-accent-faded: #9a9aa3;
        --nocturne-accent-wash: transparent;
        --nocturne-accent-wash-strong: transparent;
        --nocturne-hover-wash: transparent;
        --nocturne-text: #111;
        --nocturne-text-bright: #111;
        --nocturne-text-dim: #2b2b31;
        --nocturne-text-muted: #45454d;
        --nocturne-text-faint: #55555d;
        --nocturne-text-faintest: #66666e;
        --nocturne-shadow: none;
        color-scheme: light;
    }

    html,
    body {
        background: #fff;
        color: #111;
    }

    /* Nothing on paper can be clicked: the app's notices and the first-run tour stay on screen. */
    #blazor-error-ui,
    #components-reconnect-modal,
    .driver-overlay,
    .driver-popover {
        display: none !important;
    }
}

/* A button whose form has been sent (forms.js) — a spinner before its label until the next page
   arrives. In a flex button the gap spaces it; inline, the margin does. */
button.is-busy::before {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 8px;
    vertical-align: -1px;
    border: 1.5px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    flex: none;
    animation: busy-spin .7s linear infinite;
}

.auth-submit.is-busy::before,
.auth-alt.is-busy::before {
    margin-right: 0;
}

button.is-busy:disabled {
    cursor: progress;
}

@keyframes busy-spin {
    to {
        transform: rotate(360deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    button.is-busy::before {
        animation-duration: 2.4s;
    }
}
