/* /Components/AsyncButtonContent/AsyncButtonContent.razor.rz.scp.css */
.async-button-check[b-7tww2axghg] {
    margin-right: 0.3rem;
}
/* /Components/AvatarUploadDialog/AvatarUploadDialog.razor.rz.scp.css */
.avatar-upload-dialog-overlay[b-q46gqgfxpi] {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-3);
    background-color: rgba(0, 0, 0, 0.5);
}

.avatar-upload-dialog[b-q46gqgfxpi] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: 100%;
    max-width: 24rem;
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg, var(--radius));
    background-color: var(--color-bg-card);
    box-shadow: var(--shadow-card-hover, var(--shadow-card));
}

.avatar-upload-dialog:focus[b-q46gqgfxpi] {
    outline: none;
}

.avatar-upload-dialog h2[b-q46gqgfxpi] {
    margin: 0;
}

.avatar-upload-dialog-preview[b-q46gqgfxpi] {
    width: 8rem;
    height: 8rem;
    border-radius: 50%;
    object-fit: cover;
    pointer-events: none;
}

.avatar-upload-dialog-actions[b-q46gqgfxpi] {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}
/* /Components/BibleAtmosphere/BibleAtmosphere.razor.rz.scp.css */
/*
  Dark Academia theme (issue #143) -- the immersive full-viewport background
  layer. Fixed and z-indexed behind Bible.razor's own content, which stays a
  normal, independently-scrolling document on top of it (this is NOT a
  scroll-hijacking or full-page-canvas design -- much simpler, much cheaper,
  and it's what "the background moves slightly slower than the page" (a
  parallax effect) actually requires: a fixed layer the real content just
  scrolls over).

  z-index (issue #143 v2, live-verification): NOT -1. That was the original
  value and it silently lost to the app shell's own paint layer in the real
  browser -- confirmed directly (elementFromPoint at a point over this layer
  returned an ancestor div, and forcing z-index to a high value made the
  background instantly visible where it had been fully invisible before,
  with every other CSS property already correct). z-index:0 here plus
  .bible-page--dark-academia's own explicit z-index:1 (Bible.razor.css)
  replaces the implicit "negative z-index always loses" assumption with an
  explicit, verified stacking order.
*/

.ba-curtain[b-xea7b6d8g3] {
    position: fixed;
    inset: 0;
    z-index: 50;
    background: #050302;
    opacity: 0;
    pointer-events: none;
}

.bible-atmosphere[b-xea7b6d8g3] {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
    background: #0c0908;
}

.ba-ignite[b-xea7b6d8g3] {
    position: absolute;
    top: 36%;
    left: 50%;
    width: 240px;
    height: 240px;
    margin: -120px 0 0 -120px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 214, 130, 0.95) 0%, rgba(230, 180, 90, 0.45) 38%, rgba(230, 180, 90, 0) 70%);
    filter: blur(2px);
    opacity: 0;
}

.bible-atmosphere-background[b-xea7b6d8g3] {
    position: absolute;
    inset: -60px -20px -20px -20px; /* overshoot so the parallax offset never reveals an edge */
    background-image: url("images/bible-hero.jpg");
    background-size: cover;
    background-position: center 30%;
    filter: brightness(0.52) saturate(0.9) sepia(0.12);
    transform: translateY(var(--ba-parallax-y, 0px));
    will-change: transform;
}

.bible-atmosphere-vignette[b-xea7b6d8g3] {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse at center, transparent 40%, rgba(6, 4, 3, 0.45) 100%),
        linear-gradient(180deg, rgba(8, 5, 4, 0.65) 0%, rgba(8, 5, 4, 0.15) 24%, rgba(8, 5, 4, 0.25) 70%, rgba(4, 2, 2, 0.82) 100%);
}

/* Two soft, slowly-pulsing warm blobs standing in for candlelight -- pure
   CSS (opacity/transform only, GPU-composited), no canvas/particle engine. */
.bible-atmosphere-glow[b-xea7b6d8g3] {
    position: absolute;
    width: 42vw;
    height: 42vw;
    max-width: 620px;
    max-height: 620px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(211, 165, 92, 0.16) 0%, rgba(211, 165, 92, 0) 70%);
    animation: ba-glow-pulse-b-xea7b6d8g3 9s ease-in-out infinite;
}

.bible-atmosphere-glow--1[b-xea7b6d8g3] {
    top: 8%;
    left: 12%;
    animation-delay: 0s;
}

.bible-atmosphere-glow--2[b-xea7b6d8g3] {
    bottom: 5%;
    right: 8%;
    animation-delay: -4.5s;
}

@keyframes ba-glow-pulse-b-xea7b6d8g3 {
    0%, 100% { opacity: 0.55; transform: scale(1); }
    50% { opacity: 0.9; transform: scale(1.08); }
}

/* Dust motes drifting in the candlelight -- a fixed small count of plain
   spans, each given a random-ish drift path via nth-child offsets rather
   than inline styles (keeps this component free of per-render style
   computation; the pattern doesn't need true randomness to read as
   atmospheric). */
.bible-atmosphere-dust[b-xea7b6d8g3] {
    position: absolute;
    inset: 0;
}

.bible-atmosphere-mote[b-xea7b6d8g3] {
    position: absolute;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: rgba(230, 201, 118, 0.55);
    box-shadow: 0 0 4px 1px rgba(230, 201, 118, 0.3);
    opacity: 0;
    animation: ba-dust-drift-b-xea7b6d8g3 16s linear infinite;
}

@keyframes ba-dust-drift-b-xea7b6d8g3 {
    0% { opacity: 0; transform: translate(0, 100vh) scale(0.6); }
    8% { opacity: 0.8; }
    92% { opacity: 0.5; }
    100% { opacity: 0; transform: translate(28px, -8vh) scale(1); }
}

/* 14 motes (see BibleAtmosphere.razor's DustMoteCount), each offset in
   start position/timing purely via nth-child math -- no JS, no inline
   style attribute per element. */
.bible-atmosphere-mote:nth-child(1)[b-xea7b6d8g3] { left: 6%; animation-duration: 14s; animation-delay: -1s; }
.bible-atmosphere-mote:nth-child(2)[b-xea7b6d8g3] { left: 14%; animation-duration: 19s; animation-delay: -6s; }
.bible-atmosphere-mote:nth-child(3)[b-xea7b6d8g3] { left: 21%; animation-duration: 15s; animation-delay: -11s; }
.bible-atmosphere-mote:nth-child(4)[b-xea7b6d8g3] { left: 29%; animation-duration: 21s; animation-delay: -3s; }
.bible-atmosphere-mote:nth-child(5)[b-xea7b6d8g3] { left: 37%; animation-duration: 17s; animation-delay: -9s; }
.bible-atmosphere-mote:nth-child(6)[b-xea7b6d8g3] { left: 44%; animation-duration: 13s; animation-delay: -14s; }
.bible-atmosphere-mote:nth-child(7)[b-xea7b6d8g3] { left: 52%; animation-duration: 20s; animation-delay: -2s; }
.bible-atmosphere-mote:nth-child(8)[b-xea7b6d8g3] { left: 59%; animation-duration: 16s; animation-delay: -8s; }
.bible-atmosphere-mote:nth-child(9)[b-xea7b6d8g3] { left: 67%; animation-duration: 22s; animation-delay: -13s; }
.bible-atmosphere-mote:nth-child(10)[b-xea7b6d8g3] { left: 74%; animation-duration: 14.5s; animation-delay: -5s; }
.bible-atmosphere-mote:nth-child(11)[b-xea7b6d8g3] { left: 81%; animation-duration: 18s; animation-delay: -10s; }
.bible-atmosphere-mote:nth-child(12)[b-xea7b6d8g3] { left: 88%; animation-duration: 15.5s; animation-delay: -7s; }
.bible-atmosphere-mote:nth-child(13)[b-xea7b6d8g3] { left: 93%; animation-duration: 19.5s; animation-delay: -12s; }
.bible-atmosphere-mote:nth-child(14)[b-xea7b6d8g3] { left: 97%; animation-duration: 13.5s; animation-delay: -4s; }

.bible-atmosphere-credit[b-xea7b6d8g3] {
    position: fixed;
    right: var(--space-2);
    bottom: var(--space-1);
    z-index: 1;
    margin: 0;
    font-size: var(--font-size-caption);
    color: rgba(230, 220, 200, 0.65);
}

.bible-atmosphere-credit a[b-xea7b6d8g3] {
    color: rgba(211, 165, 92, 0.9);
}

@media (prefers-reduced-motion: reduce) {
    .bible-atmosphere-background[b-xea7b6d8g3] {
        transform: none;
    }

    .bible-atmosphere-glow[b-xea7b6d8g3],
    .bible-atmosphere-mote[b-xea7b6d8g3] {
        animation: none;
    }

    .bible-atmosphere-glow[b-xea7b6d8g3] {
        opacity: 0.6;
    }

    .bible-atmosphere-mote[b-xea7b6d8g3] {
        opacity: 0;
    }
}

/* Mobile: bibleAtmosphere.js never wires up the parallax scroll listener
   below this width (see PARALLAX_MAX_WIDTH), so --ba-parallax-y simply
   never changes -- this media query only needs to drop the dust layer,
   the one purely-decorative effect still animating continuously
   regardless of scroll, to save a little paint/composite work on weaker
   hardware. Glow keeps animating; it's two elements, negligible cost. */
@media (max-width: 640px) {
    .bible-atmosphere-dust[b-xea7b6d8g3] {
        display: none;
    }
}
/* /Components/BookCard/BookCard.razor.rz.scp.css */
.book-card[b-i92ge6dvx7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    text-decoration: none;
    color: var(--color-text-primary);
}

.book-card-cover[b-i92ge6dvx7] {
    position: relative;
    aspect-ratio: 2 / 3;
    border-radius: var(--radius, 4px);
    overflow: hidden;
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-card);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.book-card-favorite[b-i92ge6dvx7] {
    position: absolute;
    top: var(--space-1);
    right: var(--space-1);
    width: 1.75rem;
    height: 1.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: none;
    background-color: rgba(0, 0, 0, 0.45);
    color: var(--color-text-on-dark, #fff);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}

.book-card-favorite.is-favorite[b-i92ge6dvx7] {
    color: var(--color-gold-accent);
}

.book-card-borrowed-badge[b-i92ge6dvx7] {
    position: absolute;
    left: var(--space-1);
    bottom: var(--space-1);
    max-width: calc(100% - 2 * var(--space-1));
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius, 4px);
    background-color: rgba(0, 0, 0, 0.55);
    color: var(--color-text-on-dark, #fff);
    font-size: 0.7rem;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.book-card:hover .book-card-cover[b-i92ge6dvx7] {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-2px);
}

.book-card-cover img[b-i92ge6dvx7] {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.book-card-cover-placeholder[b-i92ge6dvx7] {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-disabled);
}

.book-card-cover-placeholder svg[b-i92ge6dvx7] {
    width: 40%;
    height: 40%;
}

.book-card-title[b-i92ge6dvx7] {
    font-family: var(--font-family-display);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.book-card-author[b-i92ge6dvx7] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.book-card-progress[b-i92ge6dvx7] {
    height: 4px;
    border-radius: 2px;
    background-color: var(--color-border);
    overflow: hidden;
}

.book-card-progress-bar[b-i92ge6dvx7] {
    height: 100%;
    background-color: var(--color-secondary);
}

.book-card-small[b-i92ge6dvx7] {
    width: 6rem;
}

.book-card-normal[b-i92ge6dvx7] {
    width: 10rem;
}

.book-card-large[b-i92ge6dvx7] {
    width: 14rem;
}

.book-card-large .book-card-title[b-i92ge6dvx7] {
    font-size: var(--font-size-h3);
}

/* Featured Weiterlesen card only (Dashboard Rework Phase 1) -- uses
   --color-accent-text, not --color-gold-accent: the plain gold accent
   fails WCAG's 3:1 non-text-contrast floor against the progress track
   background (see #341's identical reasoning for the rating-star/focus-ring
   fix in app.css). Small/Normal cards elsewhere (Library, Reader) are untouched. */
.book-card-large .book-card-progress[b-i92ge6dvx7] {
    height: 2px;
}

.book-card-large .book-card-progress-bar[b-i92ge6dvx7] {
    background-color: var(--color-accent-text);
}
/* /Components/CatalogCard/CatalogCard.razor.rz.scp.css */
.catalog-card[b-hino5uivrw] {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    text-decoration: none;
    color: var(--color-text-primary);
}

.catalog-card-cover[b-hino5uivrw] {
    position: relative;
    aspect-ratio: 2 / 3;
    border-radius: var(--radius, 4px);
    overflow: hidden;
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-card);
    outline: 1px solid transparent;
    outline-offset: 2px;
    transition: box-shadow var(--motion-standard) var(--ease-standard), transform var(--motion-standard) var(--ease-standard), outline-color var(--motion-standard) var(--ease-standard);
}

.catalog-card-cover-project[b-hino5uivrw] {
    aspect-ratio: 4 / 3;
}

/* "A book being pulled off the shelf" -- lift + a thin gold line, not a
   spring/glow/3D flourish (see issue #315's hover description). */
.catalog-card:hover .catalog-card-cover[b-hino5uivrw],
.catalog-card:focus-visible .catalog-card-cover[b-hino5uivrw] {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-3px);
    outline-color: var(--color-gold-accent);
}

.catalog-card-cover img[b-hino5uivrw] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--motion-reveal) var(--ease-standard);
}

.catalog-card:hover .catalog-card-cover img[b-hino5uivrw],
.catalog-card:focus-visible .catalog-card-cover img[b-hino5uivrw] {
    transform: scale(1.03);
}

.catalog-card-cover-placeholder[b-hino5uivrw] {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-disabled);
}

.catalog-card-placeholder-icon[b-hino5uivrw] {
    width: 40%;
    height: 40%;
}

.catalog-card-title[b-hino5uivrw] {
    font-family: var(--font-family-display);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.catalog-card-subtitle[b-hino5uivrw] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.catalog-card-owner[b-hino5uivrw] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.catalog-card-owner-link[b-hino5uivrw] {
    text-decoration: underline;
    text-decoration-color: var(--color-border);
    text-underline-offset: 2px;
    cursor: pointer;
}

.catalog-card-owner-link:hover[b-hino5uivrw] {
    color: var(--color-primary);
    text-decoration-color: var(--color-primary);
}

.catalog-card-rating[b-hino5uivrw] {
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
}

.catalog-card-rating-star[b-hino5uivrw] {
    /* --color-accent-text, not --color-gold-accent -- see app.css's
       focus-visible rule comment (issue #341 a11y audit). */
    color: var(--color-accent-text);
}

.catalog-card-type-tag[b-hino5uivrw] {
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
    .catalog-card-cover[b-hino5uivrw],
    .catalog-card-cover img[b-hino5uivrw] {
        transition: none;
    }
}
/* /Components/ConfirmDialog/ConfirmDialog.razor.rz.scp.css */
.confirm-dialog-overlay[b-ov9s6uphp5] {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-3);
    background-color: rgba(0, 0, 0, 0.5);
}

.confirm-dialog[b-ov9s6uphp5] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-width: 24rem;
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg, var(--radius));
    background-color: var(--color-bg-card);
    box-shadow: var(--shadow-card-hover, var(--shadow-card));
}

.confirm-dialog:focus[b-ov9s6uphp5] {
    outline: none;
}

.confirm-dialog-message[b-ov9s6uphp5] {
    margin: 0;
}

.confirm-dialog-actions[b-ov9s6uphp5] {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}
/* /Components/EmptyState/EmptyState.razor.rz.scp.css */
.empty-state[b-9sm0kgvmdv] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-5) var(--space-2);
    text-align: center;
}

.empty-state-message[b-9sm0kgvmdv] {
    color: var(--color-text-secondary);
    max-width: 32rem;
}
/* /Components/ErrorPage/ErrorPage.razor.rz.scp.css */
.error-state[b-nbgbzbc523] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-5) var(--space-2);
    text-align: center;
}

.error-state-message[b-nbgbzbc523] {
    color: var(--color-error);
    max-width: 32rem;
}
/* /Components/FollowListDialog/FollowListDialog.razor.rz.scp.css */
.follow-list-dialog-overlay[b-tzm1i3kli3] {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-3);
    background-color: rgba(0, 0, 0, 0.5);
}

.follow-list-dialog[b-tzm1i3kli3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: 100%;
    max-width: 24rem;
    max-height: 80vh;
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg, var(--radius));
    background-color: var(--color-bg-card);
    box-shadow: var(--shadow-card-hover, var(--shadow-card));
    overflow: hidden;
}

.follow-list-dialog:focus[b-tzm1i3kli3] {
    outline: none;
}

.follow-list-dialog h2[b-tzm1i3kli3] {
    margin: 0;
}

.follow-list-dialog-items[b-tzm1i3kli3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
    overflow-y: auto;
}

.follow-list-dialog-row[b-tzm1i3kli3] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) 0;
}

.follow-list-dialog-user[b-tzm1i3kli3] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--color-text-primary);
    text-decoration: none;
}

.follow-list-dialog-user:hover[b-tzm1i3kli3] {
    text-decoration: underline;
}

.follow-list-dialog-avatar[b-tzm1i3kli3] {
    flex-shrink: 0;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    object-fit: cover;
}

.follow-list-dialog-avatar-placeholder[b-tzm1i3kli3] {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-bg-paper);
    color: var(--color-text-disabled);
}

.follow-list-dialog-avatar-placeholder-icon[b-tzm1i3kli3] {
    width: 60%;
    height: 60%;
}

.follow-list-dialog-actions[b-tzm1i3kli3] {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}
/* /Components/LoadingIndicator/LoadingIndicator.razor.rz.scp.css */
/* Base + "section" mode (issue #349 Phase B) -- this is the pre-existing
   look, kept as the default so every current `<LoadingIndicator Text="..."/>`
   call site (page/detail views replacing their main content while loading)
   renders unchanged. */
.loading-indicator[b-bdjsaq1kkd] {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: var(--space-4);
}

.loading-indicator .loading-progress[b-bdjsaq1kkd] {
    width: 3rem;
    height: 3rem;
    margin: 0;
}

.loading-indicator .loading-progress-text[b-bdjsaq1kkd] {
    margin-top: var(--space-1);
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
}

/* Inline mode: sits next to text/a control, e.g. "Suche läuft…" beside a
   search field. Row layout, no padding -- the surrounding content controls
   spacing. */
.loading-indicator-inline[b-bdjsaq1kkd] {
    flex-direction: row;
    align-items: center;
    gap: var(--space-1);
    padding: 0;
    display: inline-flex;
}

.loading-indicator-inline .loading-progress[b-bdjsaq1kkd] {
    width: 1.25rem;
    height: 1.25rem;
}

.loading-indicator-inline .loading-progress-text[b-bdjsaq1kkd] {
    margin-top: 0;
}

/* Button mode: small enough to sit inside a button next to its label
   (wired up in a later Phase B slice covering button states). No text --
   the button keeps its own label. */
.loading-indicator-button[b-bdjsaq1kkd] {
    flex-direction: row;
    padding: 0;
    display: inline-flex;
    margin-right: 0.4rem;
}

.loading-indicator-button .loading-progress[b-bdjsaq1kkd] {
    width: 1rem;
    height: 1rem;
}

.loading-indicator-button .loading-progress-text[b-bdjsaq1kkd] {
    display: none;
}

/* Page mode: a dedicated loading area taking up real space on an otherwise
   empty page (e.g. a whole route still resolving), not just replacing one
   card's worth of content. */
.loading-indicator-page[b-bdjsaq1kkd] {
    padding: var(--space-6) var(--space-4);
    min-height: 40vh;
    justify-content: center;
}

.loading-indicator-page .loading-progress[b-bdjsaq1kkd] {
    width: 5rem;
    height: 5rem;
}

/* Fullscreen mode: a scrim over the whole viewport, for a blocking
   operation (e.g. a full-page transition). Not used by any call site yet --
   defined now so later slices don't need another CSS pass. */
.loading-indicator-fullscreen[b-bdjsaq1kkd] {
    position: fixed;
    inset: 0;
    justify-content: center;
    background: color-mix(in srgb, var(--color-bg-dark) 55%, transparent);
    z-index: 500;
}

.loading-indicator-fullscreen .loading-progress[b-bdjsaq1kkd] {
    width: 5rem;
    height: 5rem;
}

.loading-indicator-fullscreen .loading-progress-text[b-bdjsaq1kkd] {
    color: var(--color-text-on-dark);
}

/* Mascot illustration (issue #353/Phase D): replaces the ring in Page/
   Fullscreen mode for types that have a delivered asset. Sized relative to
   its container rather than fixed, since Page and Fullscreen use it at
   different viewport shares. */
.loading-illustration[b-bdjsaq1kkd] {
    width: min(200px, 50%);
    height: auto;
    margin-bottom: var(--space-2);
    animation: loading-illustration-fade-in-b-bdjsaq1kkd var(--motion-reveal) var(--ease-standard);
}

@keyframes loading-illustration-fade-in-b-bdjsaq1kkd {
    from {
        opacity: 0;
        transform: translateY(6px);
    }

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

@media (prefers-reduced-motion: reduce) {
    .loading-illustration[b-bdjsaq1kkd] {
        animation: none;
    }
}

/* Dark Library's illustrations are lit for a bright parchment background;
   on the near-black paper (#1c1510) they'd otherwise read as a glowing
   rectangle. Pull brightness/contrast down slightly to sit on dark paper
   instead of re-authoring per-theme art. */
[data-theme="dark-library"] .loading-illustration[b-bdjsaq1kkd] {
    filter: brightness(0.82) contrast(1.05);
}
/* /Components/MultiSelectDropdown/MultiSelectDropdown.razor.rz.scp.css */
.multiselect-dropdown[b-qswx5y3j09] {
    position: relative;
    display: inline-block;
}

.multiselect-popover[b-qswx5y3j09] {
    position: absolute;
    top: calc(100% + var(--space-1));
    left: 0;
    z-index: 20;
    min-width: 18rem;
    max-width: 26rem;
    padding: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg, var(--radius));
    background-color: var(--color-bg-card);
    box-shadow: var(--shadow-card-hover, var(--shadow-card));
}

.multiselect-pill-grid[b-qswx5y3j09] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    max-height: 14rem;
    overflow-y: auto;
}

.multiselect-pill[b-qswx5y3j09] {
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background-color: var(--color-bg-light);
    color: var(--color-text-primary);
    padding: calc(var(--space-1) / 2) var(--space-1);
    font-size: var(--font-size-small);
    cursor: pointer;
}

.multiselect-pill.is-selected[b-qswx5y3j09] {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-bg-light);
}

.multiselect-done[b-qswx5y3j09] {
    margin-top: var(--space-2);
    width: 100%;
}
/* /Components/NotificationBell/NotificationBell.razor.rz.scp.css */
.notification-bell[b-32uz4uddgc] {
    position: relative;
    display: inline-block;
}

.notification-bell-toggle[b-32uz4uddgc] {
    position: relative;
    background: none;
    border: none;
    /* Matches .app-profile: MainLayout's header sets no color of its own,
       every child sets its own for the dark background. The icon swap
       (was an emoji, colored regardless of CSS) made this load-bearing. */
    color: var(--color-text-on-dark);
    opacity: 0.85;
    font-size: 1.25rem;
    cursor: pointer;
    padding: var(--space-1);
    line-height: 1;
}

.notification-bell-toggle:hover[b-32uz4uddgc] {
    opacity: 1;
}

.notification-bell-toggle .icon[b-32uz4uddgc] {
    width: 1.05em;
    height: 1.05em;
}

.notification-badge[b-32uz4uddgc] {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 1.1rem;
    padding: 0 0.25rem;
    border-radius: 999px;
    background-color: var(--color-danger, #c0392b);
    color: #fff;
    font-size: 0.65rem;
    line-height: 1.1rem;
    text-align: center;
}

.notification-popover[b-32uz4uddgc] {
    position: absolute;
    top: calc(100% + var(--space-1));
    right: 0;
    z-index: 20;
    width: 22rem;
    max-width: 90vw;
    max-height: 28rem;
    overflow-y: auto;
    padding: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg, var(--radius));
    background-color: var(--color-bg-card);
    box-shadow: var(--shadow-card-hover, var(--shadow-card));
}

.notification-popover-header[b-32uz4uddgc] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}

.notification-filter-pills[b-32uz4uddgc] {
    display: flex;
    flex-wrap: wrap;
    gap: calc(var(--space-1) / 2);
}

.notification-pill[b-32uz4uddgc] {
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background-color: var(--color-bg-light);
    color: var(--color-text-primary);
    padding: calc(var(--space-1) / 2) var(--space-1);
    font-size: var(--font-size-small);
    cursor: pointer;
}

.notification-pill.is-selected[b-32uz4uddgc] {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-bg-light);
}

.notification-mark-all[b-32uz4uddgc] {
    align-self: flex-start;
    font-size: var(--font-size-small);
}

.notification-list[b-32uz4uddgc] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: calc(var(--space-1) / 2);
}

.notification-item.is-unread[b-32uz4uddgc] {
    background-color: var(--color-bg-light);
    border-radius: var(--radius);
}

.notification-link[b-32uz4uddgc] {
    display: flex;
    flex-direction: column;
    gap: calc(var(--space-1) / 4);
    padding: var(--space-1);
    text-decoration: none;
    color: inherit;
}

.notification-date[b-32uz4uddgc] {
    font-size: var(--font-size-small);
}
/* /Components/ProjectCard/ProjectCard.razor.rz.scp.css */
.project-card[b-0arn00zxs6] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    text-decoration: none;
    color: var(--color-text-primary);
    width: 10rem;
}

.project-card-cover[b-0arn00zxs6] {
    aspect-ratio: 4 / 3;
    border-radius: var(--radius, 4px);
    overflow: hidden;
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-card);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.project-card:hover .project-card-cover[b-0arn00zxs6] {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-2px);
}

.project-card-cover img[b-0arn00zxs6] {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.project-card-cover-placeholder[b-0arn00zxs6] {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-disabled);
}

.project-card-cover-placeholder svg[b-0arn00zxs6] {
    width: 40%;
    height: 40%;
}

.project-card-title[b-0arn00zxs6] {
    font-family: var(--font-family-display);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-card-type[b-0arn00zxs6] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
}
/* /Components/ShelfCard/ShelfCard.razor.rz.scp.css */
.shelf-card[b-lpuubr4fqs] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    text-decoration: none;
    color: var(--color-text-primary);
    width: 10rem;
}

.shelf-card-cover[b-lpuubr4fqs] {
    aspect-ratio: 4 / 3;
    border-radius: var(--radius, 4px);
    overflow: hidden;
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-card);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.shelf-card:hover .shelf-card-cover[b-lpuubr4fqs] {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-2px);
}

.shelf-card-cover img[b-lpuubr4fqs] {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shelf-card-cover-placeholder[b-lpuubr4fqs] {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-disabled);
}

.shelf-card-cover-placeholder svg[b-lpuubr4fqs] {
    width: 40%;
    height: 40%;
}

.shelf-card-name[b-lpuubr4fqs] {
    font-family: var(--font-family-display);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.shelf-card-count[b-lpuubr4fqs] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-small);
}
/* /Components/SkeletonCatalogCard/SkeletonCatalogCard.razor.rz.scp.css */
.skeleton-catalog-card[b-qijyk47msx] {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.skeleton-catalog-card-cover[b-qijyk47msx] {
    aspect-ratio: 2 / 3;
    border-radius: var(--radius, 4px);
}

.skeleton-catalog-card-cover-project[b-qijyk47msx] {
    aspect-ratio: 4 / 3;
}

.skeleton-catalog-card-title[b-qijyk47msx] {
    height: 0.9rem;
    width: 85%;
}

.skeleton-catalog-card-subtitle[b-qijyk47msx] {
    height: 0.75rem;
    width: 55%;
}
/* /Components/StatusWidget/StatusWidget.razor.rz.scp.css */
.status-ok[b-bw3gqspwhw] {
    color: var(--color-success);
}

.status-error[b-bw3gqspwhw] {
    color: var(--color-error);
}
/* /Components/ToastHost/ToastHost.razor.rz.scp.css */
.toast-host[b-3nizm1ujna] {
    position: fixed;
    bottom: var(--space-3);
    right: var(--space-3);
    z-index: 900;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    max-width: 22rem;
}

/* Dark antique card + thin gold edge, not a bright modern SaaS toast
   (issue #349 Phase B, section 22). Same --color-bg-dark surface the
   header already uses, so it reads as part of this app's material
   language rather than a bolted-on UI-kit component. */
.toast[b-3nizm1ujna] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    background: var(--color-bg-dark);
    color: var(--color-bg-light);
    border: 1px solid var(--color-gold-accent);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card-hover);
    padding: var(--space-1) var(--space-2);
    animation: toast-enter-b-3nizm1ujna var(--motion-reveal) var(--ease-standard);
}

.toast-icon[b-3nizm1ujna] {
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
}

.toast-success .toast-icon[b-3nizm1ujna] {
    color: var(--color-success);
}

.toast-error .toast-icon[b-3nizm1ujna] {
    color: var(--color-error);
}

.toast-info .toast-icon[b-3nizm1ujna] {
    color: var(--color-info);
}

.toast-text[b-3nizm1ujna] {
    font-size: var(--font-size-small);
    flex: 1;
}

.toast-dismiss[b-3nizm1ujna] {
    background: none;
    border: none;
    color: var(--color-bg-light);
    opacity: 0.6;
    cursor: pointer;
    padding: 0;
    font-size: var(--font-size-caption);
    line-height: 1;
}

.toast-dismiss:hover[b-3nizm1ujna] {
    opacity: 1;
}

@keyframes toast-enter-b-3nizm1ujna {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .toast[b-3nizm1ujna] {
        animation: none;
    }
}

@media (max-width: 40rem) {
    .toast-host[b-3nizm1ujna] {
        left: var(--space-2);
        right: var(--space-2);
        bottom: var(--space-2);
        max-width: none;
    }
}
/* /Layouts/MainLayout.razor.rz.scp.css */
.app-shell[b-g6z2j7ru2y] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Sticky so the scroll-compaction below (issue #341) is ever visible --
   a deliberate, app-wide layout change: the header now stays on screen
   during scroll everywhere, not just on Profile. Harmless on short pages
   (nothing to compact if there's nothing to scroll past). */
.app-header[b-g6z2j7ru2y] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-bg-dark);
    border-bottom: 1px solid var(--color-gold-accent);
    position: sticky;
    top: 0;
    z-index: 10;
    transition: padding var(--motion-standard) var(--ease-standard);
}

/* Toggled by motion.js's initHeaderCompact once .scroll-sentinel (right
   below the header) scrolls out of view. Subtle on purpose -- smaller
   logo mark and less vertical padding, not a size/layout jump. */
.app-header.is-compact[b-g6z2j7ru2y] {
    padding-top: calc(var(--space-2) * 0.5);
    padding-bottom: calc(var(--space-2) * 0.5);
}

.app-header.is-compact .app-logo-mark[b-g6z2j7ru2y] {
    width: 1.5em;
    height: 1.5em;
}

.scroll-sentinel[b-g6z2j7ru2y] {
    height: 1px;
}

.app-logo[b-g6z2j7ru2y] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-family-display);
    font-weight: 600;
    font-size: var(--font-size-h3);
    letter-spacing: 0.01em;
    color: var(--color-text-on-dark);
    text-decoration: none;
}

.app-logo-mark[b-g6z2j7ru2y] {
    width: 1.9em;
    height: 1.9em;
    flex-shrink: 0;
    transition: width var(--motion-standard) var(--ease-standard), height var(--motion-standard) var(--ease-standard);
}

.app-header-actions[b-g6z2j7ru2y] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

.app-profile[b-g6z2j7ru2y] {
    margin-left: auto;
    text-decoration: none;
    font-size: var(--font-size-small);
    color: var(--color-text-on-dark);
    opacity: 0.8;
}

.app-profile:hover[b-g6z2j7ru2y] {
    opacity: 1;
    color: var(--color-text-on-dark);
}

.app-content[b-g6z2j7ru2y] {
    flex: 1;
    padding: var(--space-3);
    max-width: 88rem;
    width: 100%;
    margin: 0 auto;
}

/* Reader route only (see MainLayout.razor's ContentClass) -- lets the
   reader's own Seitenbreite width tiers (EpubReader/PdfReader's
   ViewportClass) actually govern instead of being invisibly clamped by the
   cap above regardless of which tier is selected. */
.app-content--reader[b-g6z2j7ru2y] {
    max-width: none;
}

.app-footer[b-g6z2j7ru2y] {
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--color-border);
    font-size: var(--font-size-small);
    text-align: center;
}

.app-footer-link[b-g6z2j7ru2y] {
    margin-left: var(--space-2);
    color: var(--color-text-muted);
}

.app-footer-link:hover[b-g6z2j7ru2y] {
    color: var(--color-primary);
}

/* Page-enter fade (issue #341) -- replayed on every client-side navigation
   via motion.js's replayPageEnter (MainLayout.razor's OnAfterRenderAsync).
   Short and opacity-led on purpose: enough to feel like the page changed,
   not a slide/showcase transition (see the issue's "kein Motion-Design
   Showcase" note). */
.page-enter[b-g6z2j7ru2y] {
    animation: page-enter-b-g6z2j7ru2y var(--motion-reveal) var(--ease-standard);
}

@keyframes page-enter-b-g6z2j7ru2y {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-header[b-g6z2j7ru2y],
    .app-header.is-compact .app-logo-mark[b-g6z2j7ru2y],
    .app-logo-mark[b-g6z2j7ru2y] {
        transition: none;
    }

    .page-enter[b-g6z2j7ru2y] {
        animation: none;
    }
}
/* /Layouts/NavMenu.razor.rz.scp.css */
.nav-menu[b-hed32j26bz] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.nav-menu[b-hed32j26bz]  a {
    text-decoration: none;
    color: var(--color-text-on-dark);
    opacity: 0.72;
    font-size: var(--font-size-small);
    padding: var(--space-1) var(--space-1);
    border-radius: var(--radius);
    border-bottom: 2px solid transparent;
    transition: opacity 0.15s ease, border-color 0.15s ease;
}

.nav-menu[b-hed32j26bz]  a:hover {
    opacity: 1;
    color: var(--color-text-on-dark);
}

.nav-menu[b-hed32j26bz]  a.active {
    opacity: 1;
    font-weight: 600;
    border-bottom-color: var(--color-gold-accent);
}
/* /Pages/Bible.razor.rz.scp.css */
/*
  Deliberate one-page exception to the app's brass/oxblood classic-library
  identity -- baroque, dark-academia, "you get shivers" per the user's own
  brief. Page-scoped only (Blazor CSS isolation), never touches app.css or
  the shared theme tokens' meaning elsewhere. Supports both light and dark
  app themes with the same base design (see the [data-theme="dark-library"]
  / prefers-color-scheme block at the bottom), same convention as the app's
  own theme CSS files.

  Verse/section markup (span.v, .s1, .q1-.q3, <p>) comes from api.bible's
  content-type=html response, injected via @((MarkupString)...) -- Blazor's
  CSS scoping does not reach dynamically-injected markup, hence ::deep.
*/

.bible-page[b-9madblp5k4] {
    --bible-gold: #c9a24a;
    --bible-gold-bright: #e6c976;
    --bible-ink: #2a1c14;
    --bible-parchment: #f3e6c8;
    --bible-parchment-panel: #faf3e0;
    --bible-burgundy: #4a1620;

    max-width: 68rem;
    margin: 0 auto;
    padding-bottom: var(--space-6);
    color: var(--bible-ink);
}

/* Hero */

.bible-hero[b-9madblp5k4] {
    position: relative;
    height: 46vh;
    min-height: 320px;
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-4);
    box-shadow: 0 0 0 1px var(--bible-gold), 0 20px 50px rgba(20, 10, 5, 0.45);
}

.bible-hero-image[b-9madblp5k4] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.bible-hero-scrim[b-9madblp5k4] {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 8, 8, 0.55) 0%, rgba(30, 10, 10, 0.35) 40%, rgba(15, 6, 6, 0.85) 100%);
}

.bible-hero-content[b-9madblp5k4] {
    position: relative;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--space-3);
}

.bible-hero-content h1[b-9madblp5k4] {
    font-family: var(--font-family-display);
    font-size: clamp(2.25rem, 5vw, 3.5rem);
    color: var(--bible-gold-bright);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    margin: 0 0 var(--space-2);
    letter-spacing: 0.02em;
}

.bible-hero-subtitle[b-9madblp5k4] {
    font-family: var(--font-family-reader);
    font-style: italic;
    font-size: var(--font-size-body-lg);
    color: var(--bible-parchment);
    max-width: 40rem;
    margin: 0;
}

.bible-hero-credit[b-9madblp5k4] {
    position: absolute;
    right: var(--space-2);
    bottom: var(--space-1);
    margin: 0;
    font-size: var(--font-size-caption);
    color: rgba(255, 255, 255, 0.75);
}

.bible-hero-credit a[b-9madblp5k4] {
    color: var(--bible-gold-bright);
}

/* Controls */

.bible-controls[b-9madblp5k4] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    background: var(--bible-parchment);
    border: 1px solid var(--bible-gold);
    border-radius: var(--radius-lg);
}

.bible-control[b-9madblp5k4] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--font-size-small);
    color: var(--bible-ink);
}

.bible-control select[b-9madblp5k4] {
    font-family: var(--font-family-ui);
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--bible-gold);
    border-radius: var(--radius);
    background: var(--bible-parchment-panel);
    color: var(--bible-ink);
    min-width: 12rem;
}

.bible-nav-buttons[b-9madblp5k4] {
    display: flex;
    gap: var(--space-2);
    margin-left: auto;
}

.bible-search[b-9madblp5k4] {
    display: flex;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.bible-search input[type="search"][b-9madblp5k4] {
    flex: 1;
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--bible-gold);
    border-radius: var(--radius);
    background: var(--bible-parchment-panel);
    color: var(--bible-ink);
    font-family: var(--font-family-reader);
}

.bible-search-results[b-9madblp5k4] {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.bible-search-result[b-9madblp5k4] {
    width: 100%;
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-2);
    border: 1px solid var(--bible-gold);
    border-radius: var(--radius);
    background: var(--bible-parchment-panel);
    color: var(--bible-ink);
    cursor: pointer;
    transition: background-color 0.15s ease, transform 0.15s ease;
}

.bible-search-result:hover[b-9madblp5k4] {
    background: var(--bible-parchment);
    transform: translateX(2px);
}

.bible-search-result strong[b-9madblp5k4] {
    font-family: var(--font-family-display);
    color: var(--bible-burgundy);
}

/* Chapter panel -- the "illuminated manuscript" frame */

.bible-chapter[b-9madblp5k4] {
    position: relative;
    background: var(--bible-parchment-panel);
    border: 3px double var(--bible-gold);
    border-radius: var(--radius-lg);
    padding: var(--space-5) var(--space-5);
    box-shadow: var(--shadow-card);
}

.bible-chapter h2[b-9madblp5k4] {
    font-family: var(--font-family-display);
    color: var(--bible-burgundy);
    text-align: center;
    margin-top: 0;
    border-bottom: 3px double var(--bible-gold);
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
    padding-bottom: var(--space-1);
}

.bible-chapter-content[b-9madblp5k4] {
    font-family: var(--font-family-reader);
    font-size: 1.15rem;
    line-height: 1.85;
    max-width: 62ch;
    margin: 0 auto;
    color: var(--bible-ink);
}

.bible-chapter-content[b-9madblp5k4]  p {
    margin: 0 0 var(--space-2);
}

.bible-chapter-content[b-9madblp5k4]  p.s1 {
    font-family: var(--font-family-display);
    font-style: italic;
    font-size: var(--font-size-h3);
    color: var(--bible-burgundy);
    text-align: center;
    margin: var(--space-4) 0 var(--space-2);
}

.bible-chapter-content[b-9madblp5k4]  p.q1 {
    margin-left: var(--space-3);
}

.bible-chapter-content[b-9madblp5k4]  p.q2 {
    margin-left: var(--space-4);
}

.bible-chapter-content[b-9madblp5k4]  p.q3 {
    margin-left: var(--space-5);
}

.bible-chapter-content[b-9madblp5k4]  span.v {
    font-family: var(--font-family-ui);
    font-weight: 700;
    font-size: 0.7em;
    color: var(--bible-gold);
    vertical-align: super;
    margin-right: 2px;
}

/* Drop cap on the chapter's first paragraph -- an illuminated-manuscript
   touch that reads as baroque/ornate without leaning gothic. */
.bible-chapter-content[b-9madblp5k4]  p:first-of-type::first-letter {
    font-family: var(--font-family-display);
    font-size: 3.4em;
    font-weight: 700;
    color: var(--bible-burgundy);
    float: left;
    line-height: 0.8;
    margin: 0.05em 0.08em 0 0;
}

.bible-chapter-content[b-9madblp5k4]  .bible-verse-highlight {
    background: rgba(201, 162, 74, 0.35);
    border-radius: 3px;
    transition: background-color 2s ease;
}

.bible-attribution[b-9madblp5k4] {
    max-width: 62ch;
    margin: var(--space-3) auto 0;
    font-size: var(--font-size-caption);
    color: var(--bible-ink);
    opacity: 0.75;
    text-align: center;
}

.bible-attribution a[b-9madblp5k4] {
    color: var(--bible-burgundy);
}

.bible-attribution-links[b-9madblp5k4] {
    margin-top: var(--space-1);
}

/* Dark mode -- Dark Library theme, or System theme resolving to a dark OS
   preference. Same structure, candlelit instead of daylit, mirroring the
   app's own Classic Library / Dark Library relationship. */

[data-theme="dark-library"] .bible-page[b-9madblp5k4] {
    --bible-ink: #ece0c4;
    --bible-parchment: #241a12;
    --bible-parchment-panel: #2c2015;
    --bible-burgundy: #d98a9a;
}

[data-theme="dark-library"] .bible-hero[b-9madblp5k4] {
    box-shadow: 0 0 0 1px var(--bible-gold), 0 20px 60px rgba(0, 0, 0, 0.7);
}

@media (prefers-color-scheme: dark) {
    [data-theme="system"] .bible-page[b-9madblp5k4] {
        --bible-ink: #ece0c4;
        --bible-parchment: #241a12;
        --bible-parchment-panel: #2c2015;
        --bible-burgundy: #d98a9a;
    }
}

/* ============================================================
   Dark Academia / Baroque immersive theme (issue #143)
   ============================================================
   Opt-in, page-scoped, additive only -- every rule below is gated behind
   .bible-page--dark-academia so the default theme above is completely
   unaffected. Independent of [data-theme="..."]/prefers-color-scheme: this
   theme looks the same regardless of the app's own light/dark setting,
   since it's meant to feel like its own place, not a reskinned app page.

   The immersive full-viewport background/glow/dust live in
   BibleAtmosphere.razor.css (a separate fixed-position component, sibling
   to .bible-page) -- this file only styles .bible-page's own content
   panels sitting on top of that background: translucent "glass" panels so
   the atmosphere reads through slightly, restyled typography, and the
   scroll-triggered fade-in utility.
   ============================================================ */

.bible-page--dark-academia[b-9madblp5k4] {
    --ba-ink: #ece1c4;
    --ba-ink-muted: #c9bda1;
    --ba-gold: #b8935a;
    --ba-gold-bright: #d9b978;
    --ba-burgundy: #8a2f42;
    --ba-panel: rgba(18, 13, 10, 0.62);
    --ba-panel-strong: rgba(15, 11, 9, 0.82);
    --ba-border: rgba(184, 147, 90, 0.35);

    position: relative;
    z-index: 1; /* explicit stacking above .bible-atmosphere (z-index:0) -- see BibleAtmosphere.razor.css's note on the z-index:-1 bug this replaced */
    color: var(--ba-ink);
}

/* Theme toggle -- top-right pill, visible/reachable in both themes so
   switching back is always one click away. */
.bible-theme-toggle[b-9madblp5k4] {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-1);
    padding: var(--space-2) 0 var(--space-1);
}

.bible-page--dark-academia .bible-theme-toggle .btn[b-9madblp5k4] {
    background: var(--ba-panel);
    border: 1px solid var(--ba-border);
    color: var(--ba-ink-muted);
}

.bible-page--dark-academia .bible-theme-toggle .btn.is-active[b-9madblp5k4] {
    color: var(--ba-gold-bright);
    border-color: var(--ba-gold);
}

.bible-title-immersive[b-9madblp5k4] {
    font-family: var(--font-family-display);
    font-size: clamp(2rem, 4.5vw, 3.25rem);
    text-align: center;
    letter-spacing: 0.04em;
    color: var(--ba-gold-bright);
    text-shadow: 0 2px 20px rgba(0, 0, 0, 0.7);
    margin: var(--space-2) 0 var(--space-1);
}

/* Draws itself in on entrance (bibleAtmosphere.js's playEntrance, GSAP
   scaleX 0 -> 1) -- default scaleX(1) here so the rule is simply already
   "drawn" if GSAP never loads/runs, never a stuck-undrawn sliver. */
.bible-title-rule[b-9madblp5k4] {
    display: block;
    width: 140px;
    height: 2px;
    margin: 0 auto var(--space-4);
    background: linear-gradient(90deg, transparent, var(--ba-gold-bright), transparent);
    transform-origin: center;
}

/* Controls / search -- translucent glass panels over the fixed background,
   same layout as the default theme, new material only. */
.bible-page--dark-academia .bible-controls[b-9madblp5k4] {
    background: var(--ba-panel);
    border-color: var(--ba-border);
    backdrop-filter: blur(6px);
}

.bible-page--dark-academia .bible-control[b-9madblp5k4] {
    color: var(--ba-ink-muted);
}

.bible-page--dark-academia .bible-control select[b-9madblp5k4],
.bible-page--dark-academia .bible-search input[type="search"][b-9madblp5k4] {
    background: var(--ba-panel-strong);
    border-color: var(--ba-border);
    color: var(--ba-ink);
}

.bible-page--dark-academia .bible-search-result[b-9madblp5k4] {
    background: var(--ba-panel);
    border-color: var(--ba-border);
    color: var(--ba-ink-muted);
}

.bible-page--dark-academia .bible-search-result:hover[b-9madblp5k4] {
    background: var(--ba-panel-strong);
}

.bible-page--dark-academia .bible-search-result strong[b-9madblp5k4] {
    color: var(--ba-gold-bright);
}

/* Chapter panel -- less transparent than the controls (long-form reading
   needs steadier contrast than a quick select/search glance does). */
.bible-page--dark-academia .bible-chapter[b-9madblp5k4] {
    background: var(--ba-panel-strong);
    border-color: var(--ba-gold);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
}

.bible-page--dark-academia .bible-chapter h2[b-9madblp5k4] {
    color: var(--ba-gold-bright);
    border-bottom-color: var(--ba-gold);
}

.bible-page--dark-academia .bible-chapter-content[b-9madblp5k4] {
    color: var(--ba-ink);
}

/* Verse markup comes from api.bible's injected MarkupString -- ::deep is
   required for Blazor's scoped CSS to reach it at all (see the module
   comment at the top of this file). Confirmed this exact shape --
   ancestor modifier class, then a scoped element, then ::deep -- compiles
   to a working selector before writing the rest of this block on top of it. */
.bible-page--dark-academia .bible-chapter-content[b-9madblp5k4]  p.s1 {
    color: var(--ba-gold-bright);
}

.bible-page--dark-academia .bible-chapter-content[b-9madblp5k4]  span.v {
    color: var(--ba-gold);
}

.bible-page--dark-academia .bible-chapter-content[b-9madblp5k4]  p:first-of-type::first-letter {
    color: var(--ba-gold-bright);
}

.bible-page--dark-academia .bible-chapter-content[b-9madblp5k4]  .bible-verse-highlight {
    background: rgba(184, 147, 90, 0.4);
}

.bible-page--dark-academia .bible-attribution[b-9madblp5k4] {
    color: var(--ba-ink-muted);
}

.bible-page--dark-academia .bible-attribution a[b-9madblp5k4] {
    color: var(--ba-gold-bright);
}

/* Chapter entrance -- plain CSS animation, not a JS/IntersectionObserver
   toggle: an earlier version drove this via bibleAtmosphere.js adding an
   .is-visible class, which left chapter text stuck at opacity:0 whenever
   the JS/Blazor render-order handshake raced (confirmed live). @key on the
   <article> in Bible.razor already gives every chapter navigation a fresh
   element, so a plain @keyframes animation replays on its own with nothing
   that can silently fail content invisible. */
.bible-page--dark-academia .bible-chapter[b-9madblp5k4] {
    animation: ba-chapter-rise-b-9madblp5k4 0.7s ease both;
}

@keyframes ba-chapter-rise-b-9madblp5k4 {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .bible-page--dark-academia .bible-chapter[b-9madblp5k4] {
        animation: none;
    }

    .bible-page--dark-academia .bible-theme-toggle .btn[b-9madblp5k4] {
        transition: none;
    }
}
/* /Pages/Discover.razor.rz.scp.css */
/* Discover -- "the Great Library Catalog" (issue #315/#340). Page-scoped
   since #339's <CatalogCard> already carries the shared card styling;
   what's left here is specific to this page's own chrome (search field,
   author-card results, the books toolbar). */

.discover-heading-caption[b-dy0ujm7o2a] {
    font-family: var(--font-family-display);
    font-style: italic;
    font-weight: 400;
    font-size: var(--font-size-h3);
    color: var(--color-text-muted);
}

.discover-section[b-dy0ujm7o2a] {
    margin-bottom: var(--space-6);
}

.discover-subheading[b-dy0ujm7o2a] {
    font-size: var(--font-size-h3);
    margin-bottom: var(--space-2);
}

/* "Antikpapier, dünner Goldrand, dezenter Schatten, Material Focus State" */
.discover-search-field[b-dy0ujm7o2a] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    max-width: 24rem;
    padding: 0.55rem var(--space-2);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    transition: border-color var(--motion-micro) var(--ease-standard), box-shadow var(--motion-micro) var(--ease-standard);
}

.discover-search-field:focus-within[b-dy0ujm7o2a] {
    border-color: var(--color-gold-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-gold-accent) 25%, transparent);
}

.discover-search-icon[b-dy0ujm7o2a] {
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.discover-search-field input[b-dy0ujm7o2a] {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    outline: none;
    font-family: var(--font-family-reader);
    font-style: italic;
    font-size: var(--font-size-body);
    color: var(--color-text-primary);
}

.discover-search-field input[b-dy0ujm7o2a]::placeholder {
    color: var(--color-text-muted);
}

/* Author-card search results -- a small, restrained "author card" per
   result, not a plain link list. */
.discover-author-results[b-dy0ujm7o2a] {
    list-style: none;
    margin: var(--space-2) 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    max-width: 24rem;
}

.discover-author-card[b-dy0ujm7o2a] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius);
    text-decoration: none;
    color: var(--color-text-primary);
    border-bottom: 1px solid transparent;
    transition: background-color var(--motion-micro) var(--ease-standard), border-color var(--motion-micro) var(--ease-standard);
}

.discover-author-card:hover[b-dy0ujm7o2a],
.discover-author-card:focus-visible[b-dy0ujm7o2a] {
    background: var(--color-bg-card);
    border-color: var(--color-gold-accent);
}

.discover-author-avatar[b-dy0ujm7o2a] {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--color-border);
    flex-shrink: 0;
    transition: transform var(--motion-micro) var(--ease-standard);
}

.discover-author-card:hover .discover-author-avatar[b-dy0ujm7o2a],
.discover-author-card:focus-visible .discover-author-avatar[b-dy0ujm7o2a] {
    transform: translateY(-1px);
}

.discover-author-avatar-placeholder[b-dy0ujm7o2a] {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-bg-paper);
    color: var(--color-text-disabled);
}

.discover-author-info[b-dy0ujm7o2a] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.discover-author-name[b-dy0ujm7o2a] {
    font-family: var(--font-family-display);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.discover-author-role[b-dy0ujm7o2a] {
    font-size: var(--font-size-caption);
    font-style: italic;
    color: var(--color-text-muted);
}

/* Books toolbar -- heading + the restyled sort control, "ein hochwertiger
   Bibliotheksfilter" rather than a plain <select>. */
.discover-books-toolbar[b-dy0ujm7o2a] {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}

.discover-sort-field[b-dy0ujm7o2a] {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
}

.discover-sort-label[b-dy0ujm7o2a] {
    font-size: var(--font-size-caption);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.discover-sort-field select[b-dy0ujm7o2a] {
    font-family: inherit;
    font-size: var(--font-size-small);
    color: var(--color-text-secondary);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.3rem 0.5rem;
    cursor: pointer;
    transition: border-color var(--motion-micro) var(--ease-standard);
}

.discover-sort-field select:hover[b-dy0ujm7o2a],
.discover-sort-field select:focus-visible[b-dy0ujm7o2a] {
    border-color: var(--color-gold-accent);
}

/* Skeleton loading grid -- now SkeletonCatalogCard (issue #349 Phase B),
   matching CatalogCard's real shape instead of a page-local approximation. */

@media (prefers-reduced-motion: reduce) {
    .discover-search-field[b-dy0ujm7o2a],
    .discover-author-card[b-dy0ujm7o2a],
    .discover-author-avatar[b-dy0ujm7o2a],
    .discover-sort-field select[b-dy0ujm7o2a] {
        transition: none;
    }
}

@media (max-width: 640px) {
    .discover-books-toolbar[b-dy0ujm7o2a] {
        flex-direction: column;
        align-items: center;
        gap: var(--space-1);
    }
}
/* /Pages/Home.razor.rz.scp.css */
.home-hero[b-lguslobjig] {
    position: relative;
    height: 38vh;
    min-height: 260px;
    border-radius: var(--radius-lg);
    /* overflow: clip, not hidden -- hidden makes this element a scroll
       container, which makes it the source of the layers' animation-timeline:
       view(), pinning progress near 0.5 instead of tracking page scroll. */
    overflow: clip;
    margin-bottom: var(--space-3);
    box-shadow: var(--shadow-card);
    background-color: var(--color-bg-dark);
    transition: height var(--motion-standard) var(--ease-standard);
}

/* Three depth layers (Dashboard Rework Phase 2) replace the old single
   .home-hero-image. Each layer is sized larger than its container
   (inset: -10% 0 -> 120% height) so Task 2's parallax translateY can move
   it without ever exposing empty space at the top/bottom edge. Note
   translateY(%) resolves against the layer's OWN height (120% of the
   container), not the container's — so layer-3's translateY(9%) is
   actually a 10.8%-of-container shift, slightly past this 10% overhang.
   No empty space is exposed in practice: layer-1 (the only fully opaque
   layer) only moves 2% (2.4% of container, well inside the margin), and
   layer-3 is ~70% transparent, so its edge crossing the container bound
   has no visible effect. Increasing layer-3's travel distance without
   re-checking this margin would not be safe. */
.home-hero-layer[b-lguslobjig] {
    position: absolute;
    inset: -10% 0;
    width: 100%;
    height: 120%;
    object-fit: cover;
}

.home-hero-layer-1[b-lguslobjig] {
    z-index: 1;
}

.home-hero-layer-2[b-lguslobjig] {
    z-index: 2;
}

.home-hero-layer-3[b-lguslobjig] {
    z-index: 3;
}

/* Scroll-driven parallax (Dashboard Rework Phase 2) — pure CSS, no JS
   scroll listener. animation-timeline: view() ties each layer's animation
   progress to the hero's own position crossing the viewport (not the
   page's total scroll distance), which is what makes this a "parallax
   while the hero is in view" effect rather than a drift across the whole
   page. Background moves least, foreground moves most — standard parallax
   depth ordering. All three keyframes start at the layer's own neutral
   transform (translateY(0), implicit "from"), so removing the animation
   entirely (the @supports/prefers-reduced-motion fallback below) leaves
   every layer in exactly the same resting position as the animated case's
   starting point — no separate "static" CSS branch needed.

   Browser support note: animation-timeline: view() shipped in Chromium
   115+ (2023) and Firefox 144+ (2026); Safari does not support it as of
   this writing. The @supports gate means unsupported browsers receive
   none of these rules at all and simply show the static layered hero —
   documented, accepted tradeoff for this personal-use app (see the design
   spec's Phase 2 section). */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .home-hero-layer-1[b-lguslobjig] {
            animation: hero-parallax-layer-1-b-lguslobjig linear both;
            animation-timeline: view();
            animation-range: cover;
        }

        .home-hero-layer-2[b-lguslobjig] {
            animation: hero-parallax-layer-2-b-lguslobjig linear both;
            animation-timeline: view();
            animation-range: cover;
        }

        .home-hero-layer-3[b-lguslobjig] {
            animation: hero-parallax-layer-3-b-lguslobjig linear both;
            animation-timeline: view();
            animation-range: cover;
        }
    }
}

@keyframes hero-parallax-layer-1-b-lguslobjig {
    to {
        transform: translateY(2%);
    }
}

@keyframes hero-parallax-layer-2-b-lguslobjig {
    to {
        transform: translateY(5%);
    }
}

@keyframes hero-parallax-layer-3-b-lguslobjig {
    to {
        transform: translateY(9%);
    }
}

.home-hero-scrim[b-lguslobjig] {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 12, 6, 0.35) 0%, rgba(20, 12, 6, 0.2) 45%, rgba(15, 9, 5, 0.75) 100%);
    z-index: 4;
}

.home-hero-content[b-lguslobjig] {
    position: relative;
    height: 100%;
    display: flex;
    align-items: flex-end;
    padding: var(--space-3);
    z-index: 5;
}

.home-hero-content h1[b-lguslobjig] {
    font-family: var(--font-family-display);
    color: var(--color-text-on-dark);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    margin: 0;
}

/* Sentinel for Task 3's motion.js initHeaderCompact call — same mechanism
   as MainLayout.razor.css's .scroll-sentinel, but placed BEFORE .home-hero
   in Home.razor rather than after it. MainLayout's sentinel goes after the
   header because the header is `position: sticky` and stays visible while
   compacting; .home-hero is a normal, non-sticky block, so a sentinel
   placed after it would only leave the viewport once the hero itself had
   already fully scrolled away — the compaction would apply to an element
   the user can no longer see. Placing the sentinel first means it clears
   the viewport (just below the app header) while the hero is still mostly
   on screen, so the height change is the thing the user actually watches. */
.home-hero-sentinel[b-lguslobjig] {
    height: 1px;
}

/* Toggled by motion.js's initHeaderCompact once .home-hero-sentinel
   scrolls out of view — same mechanism and transition tokens as
   MainLayout.razor.css's .app-header.is-compact. Subtle on purpose:
   less height, not a layout jump.
   .home-hero's base rule has min-height: 260px, which would otherwise
   clamp this compact state's height: 22vh on typical viewport heights —
   this second, more specific min-height overrides that floor for the
   compact state only. 160px is 260px scaled by the same 22vh/38vh ratio
   as the height values themselves (260 * 22/38 = 150.5px), rounded up. */
.home-hero.is-compact[b-lguslobjig] {
    height: 22vh;
    min-height: 160px;
}

@media (prefers-reduced-motion: reduce) {
    .home-hero[b-lguslobjig] {
        transition: none;
    }
}
/* /Pages/LoreEntryDetail.razor.rz.scp.css */
.lore-content[b-skjebsrcqw] {
    font-family: var(--font-family-reader);
    line-height: 1.7;
    max-width: 70ch;
}

/* MarkupString-injected HTML bypasses Blazor's scoped-CSS attribute (it's
   raw innerHTML, not elements Blazor itself created) -- ::deep is required
   here, not just for reaching child components. */
.lore-content[b-skjebsrcqw]  h1,
.lore-content[b-skjebsrcqw]  h2,
.lore-content[b-skjebsrcqw]  h3 {
    font-family: var(--font-family-display);
    margin-top: var(--space-3);
}

.lore-content[b-skjebsrcqw]  p {
    margin: var(--space-2) 0;
}

.lore-content[b-skjebsrcqw]  blockquote {
    border-left: 3px solid var(--color-gold-accent);
    margin: var(--space-2) 0;
    padding-left: var(--space-2);
    color: var(--color-text-secondary);
}
/* /Pages/OfflineLibrary.razor.rz.scp.css */
.offline-hero[b-v1sb2j7vdn] {
    position: relative;
    height: 150px;
    border-radius: var(--radius-lg);
    overflow: clip;
    margin-bottom: var(--space-2);
    box-shadow: var(--shadow-card);
    background-color: var(--color-bg-dark);
}

.offline-hero-image[b-v1sb2j7vdn] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.offline-hero-scrim[b-v1sb2j7vdn] {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 12, 6, 0.25) 0%, rgba(20, 12, 6, 0.15) 45%, rgba(15, 9, 5, 0.7) 100%);
}

.offline-hero-content[b-v1sb2j7vdn] {
    position: relative;
    height: 100%;
    display: flex;
    align-items: flex-end;
    padding: var(--space-2) var(--space-3);
}

.offline-hero-content h1[b-v1sb2j7vdn] {
    font-family: var(--font-family-display);
    font-size: var(--font-size-h2);
    color: var(--color-text-on-dark);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    margin: 0;
}

.offline-intro[b-v1sb2j7vdn] {
    margin-top: 0;
}

.offline-book-grid[b-v1sb2j7vdn] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-2);
    margin: var(--space-2) 0;
}

.offline-book-card[b-v1sb2j7vdn] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-2);
    border-radius: var(--radius-lg);
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
}

.offline-book-icon[b-v1sb2j7vdn] {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--color-text-disabled);
}

.offline-book-icon svg[b-v1sb2j7vdn] {
    width: 100%;
    height: 100%;
}

.offline-book-info strong[b-v1sb2j7vdn] {
    font-family: var(--font-family-display);
}

.offline-book-card .form-actions[b-v1sb2j7vdn] {
    margin-top: auto;
    padding-top: var(--space-1);
}

.offline-empty-icon[b-v1sb2j7vdn] {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--color-text-disabled);
    margin-bottom: var(--space-1);
    margin-inline: auto;
}

.offline-empty-icon svg[b-v1sb2j7vdn] {
    width: 100%;
    height: 100%;
}
/* /Pages/Profile.razor.rz.scp.css */
.profile-seal-header[b-x19wwr3slr] {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    margin-bottom: var(--space-3);
}

.profile-seal-image[b-x19wwr3slr] {
    width: 6rem;
    height: 6rem;
    margin-bottom: var(--space-1);
}

.profile-seal-header h1[b-x19wwr3slr] {
    margin: 0;
}

.profile-avatar-row[b-x19wwr3slr] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: var(--space-2) 0;
}

.profile-avatar-preview[b-x19wwr3slr] {
    flex-shrink: 0;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--color-bg-card);
    outline: 1px solid var(--color-gold-accent);
    outline-offset: 2px;
}

.profile-avatar-placeholder[b-x19wwr3slr] {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-bg-card);
    color: var(--color-text-disabled);
}

.profile-avatar-placeholder-icon[b-x19wwr3slr] {
    width: 40%;
    height: 40%;
}

.profile-password-reset[b-x19wwr3slr] {
    margin: 0.5rem 0 1.5rem;
}

.profile-danger-zone[b-x19wwr3slr] {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-error);
}

.btn-danger[b-x19wwr3slr] {
    background: transparent;
    border: 1px solid var(--color-error);
    color: var(--color-error);
}

.btn-danger:hover[b-x19wwr3slr] {
    background: var(--color-error);
    color: var(--color-bg-card);
}

.linked-accounts-list[b-x19wwr3slr] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

.linked-account-row[b-x19wwr3slr] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) 0;
}
/* /Pages/ProjectDetail.razor.rz.scp.css */
.map-wrapper[b-lcz5r8emgs] {
    position: relative;
    display: inline-block;
    max-width: 100%;
}

.map-image[b-lcz5r8emgs] {
    max-width: 100%;
    display: block;
    border-radius: var(--radius, 4px);
    border: 1px solid var(--color-border);
}

.map-pin[b-lcz5r8emgs] {
    position: absolute;
    transform: translate(-50%, -100%);
    font-size: 1.5rem;
    line-height: 1;
    text-decoration: none;
    color: var(--color-primary);
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
    cursor: pointer;
}

.map-pin:hover[b-lcz5r8emgs] {
    transform: translate(-50%, -100%) scale(1.15);
}

.timeline[b-lcz5r8emgs] {
    position: relative;
    list-style: none;
    margin: var(--space-4) 0 0 0;
    padding: 0 0 0 var(--space-4);
}

.timeline[b-lcz5r8emgs]::before {
    content: "";
    position: absolute;
    left: calc(var(--space-1) - 1px);
    top: 0.4rem;
    bottom: 0.4rem;
    width: 2px;
    background: linear-gradient(to bottom, var(--color-gold-accent), var(--color-border));
}

.timeline-event[b-lcz5r8emgs] {
    position: relative;
    padding: 0 0 var(--space-4) var(--space-3);
}

.timeline-event[b-lcz5r8emgs]::before {
    content: "";
    position: absolute;
    left: calc(var(--space-1) * -1 - 5px);
    top: 0.3rem;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--color-gold-accent);
    box-shadow: 0 0 0 3px var(--color-bg-card);
}

.timeline-event-card[b-lcz5r8emgs] {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius, 6px);
    box-shadow: var(--shadow-card);
    padding: var(--space-2) var(--space-3);
}

.timeline-event-date[b-lcz5r8emgs] {
    font-family: var(--font-family-display);
    font-weight: 600;
    color: var(--color-secondary);
    font-size: var(--font-size-small);
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.timeline-event-title[b-lcz5r8emgs] {
    font-family: var(--font-family-display);
    font-size: var(--font-size-h3);
    font-weight: 600;
    margin: var(--space-1) 0;
}

.timeline-event-controls[b-lcz5r8emgs] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-top: var(--space-2);
}

.timeline-move-buttons[b-lcz5r8emgs] {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.timeline-move-buttons button[b-lcz5r8emgs] {
    line-height: 1;
    padding: 2px 8px;
}
/* /Pages/PublicProfile.razor.rz.scp.css */
/* Public Profile -- "the title page of an author's public collection"
   (issue #315/#339). Page-scoped now that book/project cards moved into
   the real CatalogCard component: nothing else on the page reuses this
   markup, so there's no CSS-isolation risk in keeping it local instead of
   dumping it into the global app.css (the mistake PR #313 made). */

.profile-hero[b-e6147xtgll] {
    display: flex;
    gap: var(--space-4);
    align-items: flex-end;
    flex-wrap: wrap;
    padding-bottom: var(--space-4);
    margin-bottom: var(--space-5);
    border-bottom: 1px solid var(--color-border);
}

.profile-hero-portrait-wrap[b-e6147xtgll] {
    flex-shrink: 0;
}

.profile-hero-portrait[b-e6147xtgll] {
    width: 7rem;
    height: 7rem;
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid var(--color-bg-card);
    outline: 1px solid var(--color-gold-accent);
    outline-offset: 3px;
    box-shadow: var(--shadow-card);
}

.profile-hero-portrait-placeholder[b-e6147xtgll] {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-bg-card);
    color: var(--color-text-disabled);
}

.profile-hero-portrait-icon[b-e6147xtgll] {
    width: 40%;
    height: 40%;
}

.profile-hero-body[b-e6147xtgll] {
    flex: 1;
    min-width: 12rem;
}

.profile-hero-eyebrow[b-e6147xtgll] {
    font-size: var(--font-size-caption);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 0.2rem;
}

.profile-hero-name[b-e6147xtgll] {
    font-family: var(--font-family-display);
    font-weight: 700;
    font-size: var(--font-size-h1);
    line-height: 1.1;
    margin: 0 0 0.4rem;
    /* No signature double-rule here -- the hero already has its own bottom
       border for the whole block; a second rule under just the name would
       compete with it. */
    border-bottom: none;
    padding-bottom: 0;
    width: auto;
}

.profile-hero-meta[b-e6147xtgll] {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.9rem;
    font-size: var(--font-size-small);
    color: var(--color-text-muted);
    margin: 0;
}

.profile-hero-meta-link:not(:last-child)[b-e6147xtgll]::after {
    content: "·";
    margin-left: 0.9rem;
    color: var(--color-border);
}

.profile-hero-meta-link[b-e6147xtgll] {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.profile-hero-meta-link:hover[b-e6147xtgll] {
    color: var(--color-text-primary);
    text-decoration: underline;
}

.profile-hero-actions[b-e6147xtgll] {
    flex-shrink: 0;
    padding-bottom: 0.3rem;
}

/* Primary "+ Folgen" CTA by default; once following, a deliberately
   quieter outline "✓ Gefolgt" -- the issue wants the post-follow state to
   read as calmer, not more prominent. */
.btn-follow[b-e6147xtgll] {
    position: relative;
    overflow: hidden;
    font-family: inherit;
    font-size: var(--font-size-small);
    font-weight: 500;
    border-radius: 999px;
    border: 1px solid var(--color-primary);
    background: var(--color-primary);
    color: var(--color-bg-light);
    padding: 0.5rem 1.2rem;
    cursor: pointer;
    letter-spacing: 0.02em;
    transition: background-color var(--motion-standard) var(--ease-standard), color var(--motion-standard) var(--ease-standard), border-color var(--motion-standard) var(--ease-standard), transform var(--motion-micro) var(--ease-standard);
}

.btn-follow:hover[b-e6147xtgll] {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.btn-follow:active[b-e6147xtgll] {
    transform: scale(0.97);
}

/* Restrained press feedback -- a soft radial fade from the center, not a
   literal Material ripple (issue #341 explicitly asks for something more
   subdued than a ripple effect). ::after avoids fighting the button's own
   background-color transition above. */
.btn-follow[b-e6147xtgll]::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.35), transparent 70%);
    opacity: 0;
    transition: opacity var(--motion-micro) var(--ease-standard);
    pointer-events: none;
}

.btn-follow:active[b-e6147xtgll]::after {
    opacity: 1;
    transition-duration: 60ms;
}

.btn-follow.is-following[b-e6147xtgll] {
    background: transparent;
    color: var(--color-text-secondary);
    border-color: var(--color-border);
}

.btn-follow.is-following:hover[b-e6147xtgll] {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.btn-follow:disabled[b-e6147xtgll] {
    cursor: not-allowed;
    opacity: 0.6;
}

/* Hero skeleton (loading state) -- same shape as the real hero so nothing
   jumps once data arrives. Individual shapes are now SkeletonBlock
   (issue #349 Phase B) sized to match .profile-hero-portrait/-eyebrow/
   -name/-meta exactly; only the stacking gap between the three text lines
   is page-specific layout, kept here. */
.profile-hero-skeleton[b-e6147xtgll] {
    align-items: center;
}

.profile-hero-body-skeleton[b-e6147xtgll] {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Chapters ("Bibliothek" / "Projekte" / "Aktivität") -- a sparse Roman
   numeral + flanking rules above the heading, then the same double-gold
   signature rule the rest of the app already uses under h1 (app.css),
   reapplied here at chapter scale since that global rule only targets h1. */
.profile-chapter[b-e6147xtgll] {
    margin-bottom: var(--space-6);
}

.profile-chapter-numeral-row[b-e6147xtgll] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    color: var(--color-text-muted);
    font-family: var(--font-family-display);
    font-style: italic;
    font-size: var(--font-size-small);
    letter-spacing: 0.1em;
    margin-bottom: 0.3rem;
}

.profile-chapter-numeral-row[b-e6147xtgll]::before,
.profile-chapter-numeral-row[b-e6147xtgll]::after {
    content: "";
    flex: 0 1 3rem;
    height: 1px;
    background: var(--color-border);
}

/* .chapter-title / .chapter-caption are shared utilities in app.css
   (issue #340 gave them a second consumer -- Discover's "Bibliotheksregal"
   heading -- so they moved out of this page-scoped file). */

/* .empty-state-literary / .empty-state-ornament (incl. the .btn margin
   rule) are shared utilities in app.css -- rendered via the EmptyState
   component now (issue #349 Phase B), not hand-rolled markup here. */

/* Activity chapter */
.profile-activity-list[b-e6147xtgll] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.profile-activity-item[b-e6147xtgll] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    padding: 0.7rem 0;
    border-bottom: 1px dashed var(--color-border);
    font-size: var(--font-size-small);
}

.profile-activity-item:last-child[b-e6147xtgll] {
    border-bottom: none;
}

.profile-activity-dot[b-e6147xtgll] {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--color-gold-accent);
    flex-shrink: 0;
}

.profile-activity-text[b-e6147xtgll] {
    flex: 1;
    color: var(--color-text-secondary);
}

.profile-activity-date[b-e6147xtgll] {
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .btn-follow[b-e6147xtgll],
    .btn-follow[b-e6147xtgll]::after {
        transition: none;
    }
}

@media (max-width: 640px) {
    .profile-hero[b-e6147xtgll] {
        flex-direction: column;
        align-items: flex-start;
    }

    .profile-hero-actions[b-e6147xtgll] {
        padding-bottom: 0;
    }
}
/* /Pages/Settings.razor.rz.scp.css */
.settings-hero[b-tpsou312ov] {
    position: relative;
    height: 150px;
    border-radius: var(--radius-lg);
    overflow: clip;
    margin-bottom: var(--space-2);
    box-shadow: var(--shadow-card);
    background-color: var(--color-bg-dark);
}

.settings-hero-image[b-tpsou312ov] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.settings-hero-scrim[b-tpsou312ov] {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 12, 6, 0.25) 0%, rgba(20, 12, 6, 0.15) 45%, rgba(15, 9, 5, 0.7) 100%);
}

.settings-hero-content[b-tpsou312ov] {
    position: relative;
    height: 100%;
    display: flex;
    align-items: flex-end;
    padding: var(--space-2) var(--space-3);
}

.settings-hero-content h1[b-tpsou312ov] {
    font-family: var(--font-family-display);
    font-size: var(--font-size-h2);
    color: var(--color-text-on-dark);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    margin: 0;
}

.settings-card[b-tpsou312ov] {
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    border-radius: var(--radius-lg);
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
}

.settings-card h2[b-tpsou312ov] {
    margin-top: 0;
}
/* /Pages/Statistics.razor.rz.scp.css */
.stats-hero[b-1zs88avqzi] {
    position: relative;
    /* isolation: isolate -- forms this box's own stacking context so
       layer-2's mix-blend-mode: screen (see .stats-hero-layer-2 below)
       stays contained to the hero. Not load-bearing today (layer-1 is
       fully opaque and covers the whole box), but guards against future
       bleed-through if layer-1 ever gains transparency or .stats-hero
       gains a semi-transparent overlay -- same defensive pattern as
       .stats-panel.calendar-card and .goal-ring in app.css. */
    isolation: isolate;
    height: 38vh;
    min-height: 260px;
    border-radius: var(--radius-lg);
    /* overflow: clip, not hidden -- hidden makes this element a scroll
       container, which makes it the source of the layers' animation-timeline:
       view(), pinning progress near 0.5 instead of tracking page scroll. */
    overflow: clip;
    margin-bottom: var(--space-3);
    box-shadow: var(--shadow-card);
    background-color: var(--color-bg-dark);
    transition: height var(--motion-standard) var(--ease-standard);
}

/* Three depth layers (Statistics Rework Phase 2), same technique as the
   Dashboard hero (Home.razor.css). Each layer is sized larger than its
   container (inset: -10% 0 -> 120% height) so Task 2's parallax
   translateY can move it without ever exposing empty space at the top/
   bottom edge. Note translateY(%) resolves against the layer's OWN
   height (120% of the container), not the container's — layer-3's
   translateY(9%) is actually a 10.8%-of-container shift, slightly past
   this 10% overhang. No empty space is exposed in practice: layer-1 (the
   only fully opaque layer) only moves 2% (2.4% of container, well inside
   the margin), and layer-3 is mostly transparent, so its edge crossing
   the container bound has no visible effect. */
.stats-hero-layer[b-1zs88avqzi] {
    position: absolute;
    inset: -10% 0;
    width: 100%;
    height: 120%;
    object-fit: cover;
}

.stats-hero-layer-1[b-1zs88avqzi] {
    z-index: 1;
}

/* mix-blend-mode: screen lightens rather than darkens -- black pixels
   contribute nothing while bright pixels lighten what's beneath them,
   the correct model for "light shaft over a dark scene." Without it, the
   moonlight/dust layer reads as a solid, milky white shape instead of
   translucent light (user feedback, 2026-09-08). Verified live: the
   background architecture and star-chart windows show through the beam
   with this applied; without it, they don't. Statistics-only -- the
   Dashboard hero's own light layer (dashboard-hero-layer2-lights.webp)
   was delivered with genuine per-pixel alpha transparency baked into the
   asset, so it never needed this compositing fix. */
.stats-hero-layer-2[b-1zs88avqzi] {
    z-index: 2;
    mix-blend-mode: screen;
}

.stats-hero-layer-3[b-1zs88avqzi] {
    z-index: 3;
}

/* Scroll-driven parallax (Statistics Rework Phase 2) — pure CSS, no JS
   scroll listener, same technique as the Dashboard hero. Background
   moves least, foreground moves most — standard parallax depth
   ordering. All three keyframes start at the layer's own neutral
   transform (translateY(0), implicit "from"), so removing the animation
   entirely (the @supports/prefers-reduced-motion fallback below) leaves
   every layer in exactly the same resting position as the animated
   case's starting point.

   Browser support note: animation-timeline: view() shipped in Chromium
   115+ (2023) and Firefox 144+ (2026); Safari does not support it as of
   this writing. The @supports gate means unsupported browsers receive
   none of these rules at all and simply show the static layered hero. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .stats-hero-layer-1[b-1zs88avqzi] {
            animation: stats-hero-parallax-layer-1-b-1zs88avqzi linear both;
            animation-timeline: view();
            animation-range: cover;
        }

        .stats-hero-layer-2[b-1zs88avqzi] {
            animation: stats-hero-parallax-layer-2-b-1zs88avqzi linear both;
            animation-timeline: view();
            animation-range: cover;
        }

        .stats-hero-layer-3[b-1zs88avqzi] {
            animation: stats-hero-parallax-layer-3-b-1zs88avqzi linear both;
            animation-timeline: view();
            animation-range: cover;
        }
    }
}

@keyframes stats-hero-parallax-layer-1-b-1zs88avqzi {
    to {
        transform: translateY(2%);
    }
}

@keyframes stats-hero-parallax-layer-2-b-1zs88avqzi {
    to {
        transform: translateY(5%);
    }
}

@keyframes stats-hero-parallax-layer-3-b-1zs88avqzi {
    to {
        transform: translateY(9%);
    }
}

.stats-hero-scrim[b-1zs88avqzi] {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 14, 24, 0.35) 0%, rgba(10, 14, 24, 0.2) 45%, rgba(6, 9, 16, 0.75) 100%);
    z-index: 4;
}

.stats-hero-content[b-1zs88avqzi] {
    position: relative;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: var(--space-3);
    z-index: 5;
}

.stats-hero-content h1[b-1zs88avqzi] {
    font-family: var(--font-family-display);
    color: var(--color-text-on-dark);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    margin: 0;
}

.stats-hero-content .stats-subtitle[b-1zs88avqzi] {
    color: var(--color-text-on-dark);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
    opacity: 0.85;
    margin: 0;
}

/* Sentinel for Task 3's motion.js initHeaderCompact call — placed BEFORE
   .stats-hero in Statistics.razor, not after. .stats-hero is a normal,
   non-sticky block; a sentinel placed after it would only leave the
   viewport once the hero itself had already fully scrolled away — the
   compaction would apply to an element the user can no longer see (the
   bug the Dashboard hero shipped and only caught via its final review).
   Placing the sentinel first means it clears the viewport (just below
   the app header) while the hero is still mostly on screen. */
.stats-hero-sentinel[b-1zs88avqzi] {
    height: 1px;
}

/* Toggled by motion.js's initHeaderCompact once .stats-hero-sentinel
   scrolls out of view — same mechanism, transition tokens, and compact
   dimensions as the Dashboard hero's .home-hero.is-compact.
   .stats-hero's base rule has min-height: 260px, which would otherwise
   clamp this compact state's height: 22vh on typical viewport heights —
   this second, more specific min-height overrides that floor for the
   compact state only. */
.stats-hero.is-compact[b-1zs88avqzi] {
    height: 22vh;
    min-height: 160px;
}

@media (prefers-reduced-motion: reduce) {
    .stats-hero[b-1zs88avqzi] {
        transition: none;
    }
}
