/* ---------- Blazor error UI ---------- */
/* Blazor sets display:block on unhandled errors; restyled as a site-themed bottom banner. */
#blazor-error-ui {
    background: var(--masthead-bg);
    color: var(--masthead-fg);
    border-top: 3px solid var(--masthead-rule);
    bottom: 0;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.25);
    display: none;
    left: 0;
    padding: 0.75rem 3rem calc(0.75rem + env(safe-area-inset-bottom, 0px)) 1.25rem;
    position: fixed;
    width: 100%;
    z-index: var(--z-float);
    text-align: center;
}

#blazor-error-ui .blazor-error-ui__mark {
    margin-right: 0.5rem;
}

#blazor-error-ui .reload {
    margin-left: 0.75rem;
    color: var(--masthead-fg);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: 0;
    color: var(--masthead-fg-soft);
    font-size: 1.5rem;
    line-height: 1;
    padding: 0.25rem 0.5rem;
}

#blazor-error-ui .dismiss:hover,
#blazor-error-ui .dismiss:focus-visible {
    color: var(--masthead-fg);
}

/* Static crawler copy written into each route entry page; hidden when JS runs (Blazor renders the real page). */
html.js .static-entry {
    display: none;
}

/* Without JS the app never boots, so show the content instead of an endless spinner. */
html:not(.js) .app-loading {
    display: none;
}

.app-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 22vh auto 1rem auto;
    padding: 0 1rem;
    text-align: center;
    color: var(--ink);
}

.app-loading__mark {
    width: 5rem;
    height: 5rem;
    animation: app-loading-pulse 1.8s ease-in-out infinite;
}

.app-loading__book {
    fill: var(--paper);
    stroke: var(--ink);
    stroke-width: 2;
    stroke-linejoin: round;
}

.app-loading__spine,
.app-loading__lines {
    stroke: var(--ink-soft);
    stroke-width: 1.5;
    stroke-linecap: round;
    fill: none;
}

.app-loading__plume {
    fill: var(--rule);
    stroke: var(--ink-soft);
    stroke-width: 1.2;
    stroke-linejoin: round;
}

.app-loading__rachis {
    fill: none;
    stroke: var(--ink-soft);
    stroke-width: 1;
    stroke-linecap: round;
}

.app-loading__nib {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2;
    stroke-linecap: round;
}

.app-loading__caption {
    margin-top: 0.75rem;
    font-family: 'Cinzel', serif;
    font-size: 0.9rem;
    letter-spacing: 0.35em;
    text-transform: uppercase;
    color: var(--ink-soft);
    /* Cinzel is small-caps by nature; nudge the tracking so the wordmark reads calmly. */
    padding-left: 0.35em;
}

.app-loading__bar {
    position: relative;
    width: 8rem;
    height: 2px;
    margin-top: 1.25rem;
    background: var(--rule);
    overflow: hidden;
}

/* Phase 1 (download): a real progress fill driven by --blazor-load-percentage, which the Blazor
   bootstrapper updates as the framework/assemblies download. */
.app-loading__fill {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: var(--blazor-load-percentage, 0%);
    background: var(--accent);
    transition: width 0.1s ease-in-out;
}

/* Phase 2 (startup): once download reaches 100% the runtime still has to boot and render, which the
   download percentage can't measure. Rather than reset the bar, we hold it full and pulse it so it
   keeps reading as "still working" without the jump-to-empty a sweep would cause. */
.app-loading__bar.is-starting .app-loading__fill {
    left: 0;
    width: 100%;
    transition: none;
    animation: app-loading-pulse 1.1s ease-in-out infinite;
}

@keyframes app-loading-pulse {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: 0.35;
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-loading__mark {
        animation: none;
    }

    .app-loading__fill {
        transition: none;
    }

    /* Keep phase 2 static for reduced motion: a dimmed full bar instead of the looping pulse. */
    .app-loading__bar.is-starting .app-loading__fill {
        animation: none;
        left: 0;
        width: 100%;
        opacity: 0.4;
    }
}
