/* =========================================================================
   Design tokens — the look comes from Loqui-Note (LoquiNote.UI/tokens.css):
   calm flat surfaces, hairline borders, one accent. New CSS uses the
   --color-* / --space-* / --radius-* names only.
   ========================================================================= */

@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("/fonts/inter-400.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("/fonts/inter-500.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("/fonts/inter-600.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("/fonts/inter-700.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("/fonts/jetbrains-mono-400.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("/fonts/jetbrains-mono-500.woff2") format("woff2"); }

/* Roboto stays for what ends up on the screens (display components, previews):
   changing the operator UI must not change what the congregation sees. */
@font-face { font-family: Roboto; font-weight: 400; src: url(/fonts/Roboto-Regular.ttf); }
@font-face { font-family: Roboto; font-weight: 500; src: url(/fonts/Roboto-Medium.ttf); }
@font-face { font-family: Roboto; font-weight: 700; src: url(/fonts/Roboto-Bold.ttf); }

:root {
    /* Surfaces — no lines anywhere: what sits higher is lighter and casts a
       shadow, what gets filled in (fields, empty states) lies sunken. */
    --color-bg: #070b10;
    --color-well: #090f15;
    --color-surface: #0e161f;
    --color-surface-raised: #152029;
    --color-surface-overlay: #1b2733;
    --color-text: #eaf2f8;
    --color-text-muted: #8593a2;
    /* Kept only so leftover rules stay invisible; separation comes from the
       elevation tokens below, never from a border. */
    --color-border: transparent;

    /* The one accent, taken from Loqui-Note's logo gradient (#6CFFFF → #00BFFF). */
    --color-primary: #00bfff;
    --color-primary-hover: #6cffff;
    --color-primary-rgb: 0, 191, 255;
    /* Text and icons on an accent fill are dark — white on cyan is unreadable. */
    --color-on-primary: #042333;

    --color-success: #34d399;
    --color-success-rgb: 52, 211, 153;
    --color-warning: #f0b354;
    --color-warning-rgb: 240, 179, 84;
    --color-danger: #f0656b;
    --color-danger-rgb: 240, 101, 107;
    /* Same rule as on-primary: text on a filled danger button stays dark. */
    --color-on-danger: #2a0709;
    --color-info: #6cffff;

    /* Sheet music stays black on white like the scans and the printout — the
       one light surface in the dark UI. Ink is what abcjs draws with
       (currentColor); the selection colour marks the note being edited. */
    --color-paper: #fbfaf6;
    --color-ink: #101418;
    --color-ink-selected: #0077b6;

    /* Former glass gradient; raised surfaces are solid now. */
    --surface-glass: var(--color-surface-raised);
    --surface-hover: rgba(255, 255, 255, .045);
    /* Dims the page behind a modal; a stacked modal dims less. */
    --color-scrim: rgba(0, 0, 0, .55);
    --color-scrim-light: rgba(0, 0, 0, .35);
    --accent-tint: rgba(var(--color-primary-rgb), .11);
    --accent-tint-strong: rgba(var(--color-primary-rgb), .18);

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;

    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 18px;
    --radius-full: 999px;

    /* Elevation. A faint top highlight gives a raised edge some light; it is
       part of every elevation-* step. */
    --highlight: inset 0 1px 0 rgba(255, 255, 255, .045);
    --shadow-e1: 0 1px 2px rgba(0, 0, 0, .55), 0 4px 14px rgba(0, 0, 0, .32);
    --shadow-e2: 0 2px 4px rgba(0, 0, 0, .55), 0 12px 30px rgba(0, 0, 0, .45);
    --shadow-e3: 0 6px 14px rgba(0, 0, 0, .5), 0 28px 64px rgba(0, 0, 0, .6);
    /* Raised (cards, tiles, buttons), lifted (hover), floating (menus, modals). */
    --elevation-1: var(--shadow-e1), var(--highlight);
    --elevation-2: var(--shadow-e2), var(--highlight);
    --elevation-3: var(--shadow-e3), var(--highlight);
    /* Sunken: inputs, segment wells, empty states, drop zones. */
    --shadow-inset: inset 0 2px 5px rgba(0, 0, 0, .6);
    /* Navigation and side panel cast this onto the content between them. */
    --shadow-side: 0 0 28px rgba(0, 0, 0, .55);
    --shadow-bar: 0 6px 20px rgba(0, 0, 0, .45);
    /* On the screen right now: the element glows instead of getting a frame. */
    --shadow-glow: 0 0 26px rgba(var(--color-primary-rgb), .34), 0 2px 6px rgba(0, 0, 0, .5), var(--highlight);
    /* Coloured lift under filled buttons. */
    --shadow-primary: 0 4px 14px rgba(var(--color-primary-rgb), .30), 0 1px 2px rgba(0, 0, 0, .5);
    --shadow-danger: 0 4px 16px rgba(var(--color-danger-rgb), .18), 0 1px 2px rgba(0, 0, 0, .5), var(--highlight);
    /* Keyboard/field focus on sunken elements: a soft accent ring of light. */
    --shadow-focus: 0 0 0 3px rgba(var(--color-primary-rgb), .40), 0 0 18px rgba(var(--color-primary-rgb), .25);
    /* Older names, kept for existing rules. */
    --shadow-sm: var(--shadow-e1);
    --shadow-md: var(--shadow-e2);
    --shadow-lg: var(--shadow-e3);

    --font-family: "Inter", "Segoe UI", system-ui, sans-serif;
    --font-mono: "JetBrains Mono", "Cascadia Mono", Consolas, ui-monospace, monospace;
    --font-size-xs: 12px;
    --font-size-sm: 14px;
    --font-size-md: 16px;
    --font-size-lg: 20px;
    --font-size-xl: 30px;

    --transition-fast: .12s ease;
    --transition-base: .2s ease;
    /* Things that travel: the side panel opening, the marker of the rail. */
    --transition-slide: .28s cubic-bezier(.2, .8, .2, 1);

    /* Shell geometry: every column header (nav search, content bar, side panel)
       is this tall, so they form one line. */
    --shell-header-h: 48px;
    --NavWidth: 280px;
    --RailWidth: 56px;

    /* --- Legacy names, mapped onto the tokens above. Existing CSS keeps working;
           new CSS should not use them. --- */
    --AppColor: var(--color-primary);
    --AppColorRgb: var(--color-primary-rgb);
    --RedColor: var(--color-danger);
    --RedColorRgb: var(--color-danger-rgb);
    --GreenColor: var(--color-success);
    --GreenColorRgb: var(--color-success-rgb);
    --YellowColor: var(--color-warning);
    --YellowColorRgb: var(--color-warning-rgb);
    --BorderColor: var(--color-text-muted);
    --Darker: var(--color-surface-raised);
    --BorderRadius: var(--radius-md);
    --RadiusS: var(--radius-sm);
    --RadiusM: var(--radius-md);
    --RadiusL: var(--radius-lg);
    --RadiusPill: var(--radius-full);
    --LayoutPadTop: var(--space-5);
}

/* TinyMCE frame — shared by every editor instance (see wwwroot/js/tinymceConfig.js,
   which pins all of them to the dark skin). Individual editors only add their height. */
.tox.tox-tinymce {
    border-radius: var(--radius-md);
    border: none !important;
    height: 100% !important;
    box-shadow: var(--elevation-1);
}


html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
    background: var(--color-bg);
    font-family: var(--font-family);
    color: var(--color-text);
    -webkit-font-smoothing: antialiased;
}

body {
    font-size: var(--font-size-sm);
}

/* Form controls do not inherit the font by default. */
button, input, select, textarea {
    font-family: inherit;
}

/* Facts (dates, times, counters, verse references) are set in mono. */
.mono {
    font-family: var(--font-mono);
}

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .15) transparent;
}

h1:focus {
    outline: none;
}

/* Base focus style for everything that does not bring its own. Without it the app
   cannot be operated by keyboard in any traceable way. */
:focus-visible {
    outline: 2px solid var(--color-primary-hover);
    outline-offset: 2px;
}

/* The fade-in/stagger animations are decoration — anyone who opted out gets the
   content immediately and without motion. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* Validation without frames: a valid field stays quiet, an invalid one glows red.
   !important because every field brings its own (scoped, more specific) inset
   shadow — the error has to win over it. The sign-in pages style their light
   fields themselves (AuthLayout.razor.css). */
.invalid:not([type=checkbox]):not(.auth-layout *) {
    box-shadow: var(--shadow-inset), 0 0 14px rgba(var(--color-danger-rgb), .5) !important;
}

.validation-message {
    color: var(--color-danger);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "Es ist ein Fehler aufgetreten."
    }

/* =========================================================================
   Reconnect indicator (#components-reconnect-modal, markup in App.razor)
   A screen in a service must not be covered by an overlay because the
   connection hiccuped for a moment: the indicator stays completely invisible
   for the first 2 s, then fades in as a small red dot with a caption at the
   top centre, and only grows after 10 s — by then the outage is real and the
   operator should notice it from the back row.
   The timing is pure CSS (animation-delay on the state class), so it restarts
   by itself every time Blazor re-adds the class. The global
   prefers-reduced-motion rule above only collapses durations, not delays:
   with reduced motion the pill appears at 2 s and jumps to its larger size
   at 10 s, just without the movement.
   ========================================================================= */

#components-reconnect-modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    justify-content: center;
    z-index: 20000;
    /* Never swallow clicks — only the reload button re-enables them. */
    pointer-events: none;
    font-size: 14px;
}

/* Reconnecting (and the paused circuit of .NET 10): quiet for 2 s, then fade in. */
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-paused {
    display: flex;
    animation: reconnect-fade-in 0.6s ease-out 2s both;
}

/* Retries exhausted or circuit gone: nothing reconnects on its own any more,
   so show up immediately and offer the reload. */
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected,
#components-reconnect-modal.components-reconnect-resume-failed {
    display: flex;
}

/* Same material as the toasts: floating surface with a shadow, no frame. The red
   dot alone says "trouble". */
.reconnect-pill {
    display: flex;
    align-items: center;
    gap: 0.7em;
    margin-top: 0.6em;
    min-height: 2.55em;
    box-sizing: border-box;
    padding: 0.3em 1em;
    border-radius: var(--radius-full);
    background: var(--color-surface-overlay);
    box-shadow: var(--elevation-2);
    color: var(--color-text);
    font-family: var(--font-family);
    line-height: 1.2;
    white-space: nowrap;
    /* Grows downwards out of the top edge instead of pushing sideways. */
    transform-origin: top center;
}

/* The second step: after 10 s of outage the same pill, just bigger. */
#components-reconnect-modal.components-reconnect-show .reconnect-pill,
#components-reconnect-modal.components-reconnect-retrying .reconnect-pill,
#components-reconnect-modal.components-reconnect-paused .reconnect-pill {
    animation: reconnect-grow 0.8s ease-out 10s both;
}

#components-reconnect-modal.components-reconnect-failed .reconnect-pill,
#components-reconnect-modal.components-reconnect-rejected .reconnect-pill,
#components-reconnect-modal.components-reconnect-resume-failed .reconnect-pill {
    transform: scale(1.4);
    pointer-events: auto;
    /* The reload button sits close to the right edge. */
    padding-right: 0.4em;
}

.reconnect-dot {
    flex: none;
    width: 0.65em;
    height: 0.65em;
    border-radius: 50%;
    background: var(--color-danger);
    box-shadow: 0 0 0 3px rgba(var(--color-danger-rgb), .25);
    animation: reconnect-pulse 2s ease-in-out infinite;
}

.reconnect-text {
    font-weight: 500;
}

/* Small raised button. */
.reconnect-reload {
    display: none;
    padding: 0.35em 0.8em;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-raised);
    box-shadow: var(--elevation-1);
    color: var(--color-text);
    font: inherit;
    font-size: 0.85em;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--transition-fast);
}

    .reconnect-reload:hover {
        box-shadow: var(--elevation-2);
    }

#components-reconnect-modal.components-reconnect-failed .reconnect-reload,
#components-reconnect-modal.components-reconnect-rejected .reconnect-reload,
#components-reconnect-modal.components-reconnect-resume-failed .reconnect-reload {
    display: inline-block;
}

@keyframes reconnect-fade-in {
    from {
        opacity: 0;
        transform: translateY(-0.5em);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes reconnect-grow {
    from {
        transform: scale(1);
    }

    to {
        transform: scale(1.4);
    }
}

/* Ends where it starts, so the reduced-motion rule above leaves the dot at rest. */
@keyframes reconnect-pulse {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }

    50% {
        opacity: 0.5;
        transform: scale(0.8);
    }
}
/* --- Printing (score printout, PrintLayout) ---
   A4 with the margins the preview shows (ScorePrint.razor.css). The shell's
   full-height html/body would cut the printout after the first page, and the dark
   page background has no business on paper. */
@page {
    size: A4;
    margin: 14mm;
}

@media print {
    html, body {
        height: auto;
        background: none;
        color: var(--color-ink);
    }

    #components-reconnect-modal {
        display: none !important;
    }
}
