/* ============================================================================
   Library of the Missionary Sisters of Saint Benedict
   ----------------------------------------------------------------------------
   Aesthetic: "illuminated catalog" — parchment, oxblood, sepia gold.
   Typography: Cormorant Garamond (display) + Lora (body), both serif.
   ========================================================================= */

:root {
    --parchment-1:   #f6ecd4;
    --parchment-2:   #ebdcb6;
    --parchment-3:   #d9c79b;
    --ink:           #261a12;
    --ink-soft:      #5a4632;
    --ink-mute:      #8a7456;
    --rule:          #b9a274;
    --rule-soft:     #d6c39a;

    --burgundy:      #7a1a1a;
    --burgundy-deep: #4a0e0e;
    --burgundy-soft: #9a3030;
    --gold:          #a07c2c;
    --gold-soft:     #c4a05a;
    --olive:         #6b6a3a;
    --alert:         #a8421f;
    --moss:          #4a6238;

    --shadow-soft:   0 1px 0 rgba(74, 14, 14, 0.04), 0 8px 24px rgba(74, 14, 14, 0.08);
    --shadow-deep:   0 2px 0 rgba(74, 14, 14, 0.06), 0 24px 60px rgba(74, 14, 14, 0.18);
    --shadow-inset:  inset 0 0 0 1px var(--rule-soft);

    --radius:        4px;
    --radius-lg:     10px;

    --display:       'Cormorant Garamond', 'EB Garamond', Georgia, serif;
    --body:          'Lora', Georgia, serif;

    --bg-image:      none;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    min-height: 100%;
    background-color: var(--parchment-1);
    color: var(--ink);
    font-family: var(--body);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

body {
    background-image:
        var(--bg-image),
        radial-gradient(ellipse 70% 50% at 20% 0%, rgba(160, 124, 44, 0.14), transparent 60%),
        radial-gradient(ellipse 70% 50% at 90% 100%, rgba(122, 26, 26, 0.10), transparent 60%);
    background-size: cover, auto, auto;
    background-position: center center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

/* Translucent veil so any custom background stays legible */
.parchment-overlay {
    position: fixed;
    inset: 0;
    pointer-events: none;
    background-color: rgba(246, 236, 212, 0.78);
    background-image:
        repeating-linear-gradient(0deg,
            rgba(122, 26, 26, 0.018) 0 1px,
            transparent 1px 3px),
        radial-gradient(circle at 25% 35%, rgba(122, 26, 26, 0.06), transparent 60%),
        radial-gradient(circle at 75% 65%, rgba(160, 124, 44, 0.06), transparent 60%);
    z-index: 0;
}
body:has(.bg-disabled) .parchment-overlay { background-color: var(--parchment-1); }

.app-root {
    position: relative;
    z-index: 1;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* ---------- Typography ---------- */
h1, h2, h3, h4 {
    font-family: var(--display);
    font-weight: 600;
    color: var(--burgundy-deep);
    letter-spacing: 0.01em;
    margin: 0 0 0.4em 0;
}
h1 {
    font-size: clamp(2.2rem, 4vw + 1rem, 3.4rem);
    line-height: 1.05;
    font-weight: 500;
    font-style: italic;
}
h2 { font-size: clamp(1.4rem, 1.5vw + 1rem, 1.9rem); font-style: italic; font-weight: 500; }
h3 { font-size: 1.2rem; font-weight: 600; }

p { margin: 0 0 1rem 0; }

.eyebrow {
    font-family: var(--body);
    font-size: 0.72rem;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 0.3rem;
}

.flourish {
    text-align: center;
    color: var(--gold-soft);
    font-size: 1.1rem;
    margin: 0.5rem 0;
    letter-spacing: 1em;
}
.flourish::before, .flourish::after {
    content: "";
    display: inline-block;
    width: 4ch;
    border-top: 1px solid var(--rule-soft);
    vertical-align: middle;
    margin: 0 0.8em;
}

/* Drop cap */
.drop-cap::first-letter {
    font-family: var(--display);
    font-weight: 600;
    font-style: italic;
    color: var(--burgundy);
    float: left;
    font-size: 3.6em;
    line-height: 0.82;
    padding: 0.06em 0.12em 0 0;
    margin-right: 0.04em;
}

/* ---------- Boot ---------- */
.boot-screen {
    flex: 1;
    display: grid;
    place-items: center;
}
.boot-mark {
    color: var(--burgundy);
    font-size: 5rem;
    animation: breathe 2.2s ease-in-out infinite;
}
@keyframes breathe {
    0%, 100% { opacity: 0.4; transform: scale(1); }
    50%      { opacity: 1.0; transform: scale(1.04); }
}

/* ---------- Header / TopBar ---------- */
.topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    background: linear-gradient(180deg, rgba(246, 236, 212, 0.96), rgba(235, 220, 182, 0.92));
    backdrop-filter: blur(6px);
    border-bottom: 1px solid var(--rule);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) inset, 0 12px 24px -16px rgba(74, 14, 14, 0.18);
}
.topbar-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0.9rem 1.2rem;
    display: flex;
    align-items: center;
    gap: 0.8rem;
}
.brand        { flex: 0 0 auto; }
.search       { flex: 1 1 auto; min-width: 0; max-width: 720px; }
.top-actions  { flex: 0 0 auto; margin-left: auto; }
.brand {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    text-decoration: none;
    color: inherit;
}
.brand-mark {
    font-family: var(--display);
    color: var(--burgundy);
    font-size: 1.7rem;
    line-height: 1;
}
.brand-name {
    font-family: var(--display);
    font-style: italic;
    font-weight: 500;
    font-size: 1.15rem;
    color: var(--ink);
    letter-spacing: 0.01em;
}
.brand-name small {
    display: block;
    font-style: normal;
    font-size: 0.66rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--gold);
}

.search { position: relative; }
.search input {
    width: 100%;
    background-color: rgba(255, 252, 240, 0.7);
    background-repeat: no-repeat;
    background-position: 0.85rem center;
    background-size: 1.05rem 1.05rem;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a7456' stroke-width='2' stroke-linecap='round'><circle cx='10.5' cy='10.5' r='6.5'/><line x1='15.5' y1='15.5' x2='20.5' y2='20.5'/></svg>");
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 0.6rem 0.9rem 0.6rem 2.6rem;
    font-family: var(--body);
    font-size: 0.98rem;
    color: var(--ink);
    transition: border-color 0.2s, box-shadow 0.2s;
}
.search input::placeholder { color: var(--ink-mute); font-style: italic; }
.search input:focus {
    outline: none;
    border-color: var(--burgundy);
    box-shadow: 0 0 0 3px rgba(122, 26, 26, 0.12);
}
/* Defensive: kill any older pseudo-element magnifier if the cache still holds them */
.search::before, .search::after { content: none; }
/* Leave room for the clear button so it doesn't overlap the typed text. */
.search input { padding-right: 2.4rem; }
.search-clear {
    position: absolute;
    right: 0.45rem;
    top: 50%;
    transform: translateY(-50%);
    border: none;
    background: transparent;
    color: var(--ink-mute);
    font-family: var(--display);
    font-size: 1.5rem;
    line-height: 1;
    padding: 0.1rem 0.45rem;
    border-radius: 50%;
    cursor: pointer;
    min-height: auto;
    transition: color 0.15s, background 0.15s;
}
.search-clear:hover {
    color: var(--burgundy);
    background: rgba(122, 26, 26, 0.08);
}

.top-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}
/* "?" help button right after the search box. Slightly larger than the
   inline label-side help button and styled as a flat-circle affordance. */
.search-help {
    flex: 0 0 auto;
    width: 2.1rem;
    height: 2.1rem;
    font-size: 1.05rem;
}

/* ---------- Buttons ---------- */
button, .btn {
    font-family: var(--body);
    font-size: 0.92rem;
    font-weight: 500;
    border: 1px solid var(--rule);
    background: rgba(255, 252, 240, 0.6);
    color: var(--ink);
    padding: 0.5rem 0.9rem;
    border-radius: var(--radius);
    cursor: pointer;
    transition: border-color 0.18s, background 0.18s, color 0.18s, transform 0.05s;
    letter-spacing: 0.01em;
}
button:hover, .btn:hover {
    border-color: var(--burgundy);
    color: var(--burgundy);
}
button:active, .btn:active { transform: translateY(1px); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
    background: var(--burgundy);
    color: #faecd0;
    border-color: var(--burgundy-deep);
    font-family: var(--display);
    font-size: 1rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0.6rem 1.2rem;
}
.btn-primary:hover {
    background: var(--burgundy-deep);
    color: #fff5dc;
    border-color: var(--burgundy-deep);
}

.btn-quiet {
    border: none;
    background: none;
    color: var(--ink-soft);
    padding: 0.5rem 0.6rem;
}
.btn-quiet:hover { color: var(--burgundy); }

.btn-danger {
    background: transparent;
    color: var(--alert);
    border-color: var(--alert);
}
.btn-danger:hover { background: var(--alert); color: var(--parchment-1); border-color: var(--alert); }

select {
    font-family: var(--body);
    font-size: 0.9rem;
    background: rgba(255, 252, 240, 0.7);
    border: 1px solid var(--rule);
    color: var(--ink);
    padding: 0.45rem 0.7rem;
    border-radius: var(--radius);
}

/* User menu */
.user-menu {
    position: relative;
}
.user-menu .user-avatar {
    width: 2.2rem;
    height: 2.2rem;
    padding: 0;
    border-radius: 50%;
    background: linear-gradient(140deg, var(--burgundy), var(--burgundy-deep));
    color: var(--parchment-1);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--display);
    font-style: italic;
    font-weight: 500;
    font-size: 1rem;
    line-height: 1;
    border: 1px solid var(--burgundy-deep);
    cursor: pointer;
    /* serif glyphs have a slight optical drop — nudge them back to centre */
    text-indent: 0;
    letter-spacing: 0;
    box-sizing: content-box;
}
.user-menu .user-avatar > span {
    display: block;
    transform: translateY(-1px);
}
.user-menu .user-avatar.admin {
    background: linear-gradient(140deg, var(--gold), var(--burgundy));
}
.menu-pop {
    position: absolute;
    right: 0;
    top: calc(100% + 0.4rem);
    min-width: 14rem;
    /* Never extend past the viewport edge on small screens */
    max-width: min(20rem, calc(100vw - 1.5rem));
    background: var(--parchment-1);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-deep);
    padding: 0.8rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.menu-pop hr { border: 0; border-top: 1px solid var(--rule-soft); margin: 0.2rem 0; }
.menu-pop label { font-size: 0.78rem; color: var(--ink-soft); letter-spacing: 0.06em; text-transform: uppercase; }
.menu-pop .row { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }

/* ---------- Main canvas ---------- */
.canvas {
    max-width: 1200px;
    width: 100%;
    margin: 0 auto;
    padding: 1.4rem 1.2rem 3rem;
    flex: 1;
}

.toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    align-items: center;
    justify-content: space-between;
    margin: 0.5rem 0 1rem;
    color: var(--ink-soft);
}
.toolbar .left, .toolbar .right { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }
.toolbar .count { font-style: italic; color: var(--ink-mute); }

/* Secondary filter row underneath the toolbar — catalog-letter dropdown
   + free-form tag input. Each label+control pair is its own .filter-group
   so a narrow viewport can stack them into clean rows instead of letting
   flex-wrap shuffle labels and inputs out of order. */
.filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 0.7rem;
    align-items: center;
    margin: -0.4rem 0 0.9rem;
    color: var(--ink-soft);
}
.filter-bar select { min-height: 2.4rem; }
.filter-bar .link {
    background: none;
    border: none;
    color: var(--burgundy);
    font-style: italic;
    cursor: pointer;
    padding: 0.25rem 0.4rem;
}
.filter-bar .link:hover { text-decoration: underline; }
.filter-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: nowrap;
}
.filter-letter { flex: 0 0 auto; }
.filter-tags   { flex: 1 1 16rem; min-width: 12rem; }
/* The tag input fills whatever's left in its group on wide layouts. */
.filter-tags .tags-input-wrap { flex: 1 1 auto; min-width: 0; }

/* Icon-only mode shorthand. Desktop never shows the icons — they sit
   inside the markup as zero-width placeholders so the mobile media query
   only has to swap visibility, not insert new nodes. */
.ctrl-icon  { display: none; }
.ctrl-label { display: inline; }
.btn-label  { display: inline; }

/* ---------- Mobile toolbar + filter rows ----------
   Below 600px the SORT BY / CATALOG / TAGS labels collapse into single-
   character icons next to their controls, and the "+ Add book" button
   shrinks to a "+" glyph. The toolbar fits on one row; the filter bar
   keeps the catalog dropdown inline and drops the tags input below. */
@media (max-width: 600px) {
    .ctrl-icon  { display: inline-flex; align-items: center; color: var(--gold); font-size: 1.05rem; padding: 0 0.05rem; }
    .ctrl-label { display: none; }
    .btn-label  { display: none; }

    /* Toolbar holds the whole control set on one row: count + add + sort
       + direction + catalog. Everything is compact; selects shrink before
       they wrap. */
    .toolbar {
        justify-content: flex-start;
        gap: 0.4rem;
        align-items: center;
        flex-wrap: nowrap;
    }
    .toolbar .left  { flex: 0 0 auto; gap: 0.35rem; flex-wrap: nowrap; }
    .toolbar .right {
        flex: 1 1 auto;
        min-width: 0;
        gap: 0.3rem;
        justify-content: flex-end;
        flex-wrap: nowrap;
    }
    .toolbar .left > .btn-compact {
        padding: 0.35rem 0.65rem;
        font-size: 1.1rem;
        line-height: 1;
        min-height: 2.2rem;
    }
    .toolbar .right select,
    .toolbar .right .filter-letter > select {
        min-height: 2.4rem;
        font-size: 0.85rem;
        padding: 0.3rem 0.4rem;
    }
    /* Column dropdown — let it shrink with content; cap so long Polish
       option labels truncate rather than steal the row. */
    .toolbar .right > select:not(.ctrl-dir) {
        flex: 1 1 3.5rem;
        min-width: 3.2rem;
        max-width: 6rem;
    }
    .toolbar .right > .ctrl-dir { flex: 0 0 auto; min-width: 3.5rem; }
    /* In-toolbar catalog group: glue the icon and the dropdown, cap its width. */
    .toolbar .right > .filter-letter { flex: 0 1 auto; gap: 0.2rem; min-width: 0; }
    .toolbar .right > .filter-letter > select {
        min-width: 3.2rem;
        max-width: 5.5rem;
    }

    /* The filter bar now only ever holds the tag input (+ Clear filters). */
    .filter-bar {
        justify-content: flex-start;
        gap: 0.45rem;
        align-items: center;
    }
    .filter-group { gap: 0.35rem; flex-wrap: nowrap; }
    .filter-tags { flex: 1 1 100%; min-width: 0; }
    .filter-tags .tags-input-wrap { flex: 1 1 auto; min-width: 0; }
    .filter-bar .link { margin-left: auto; padding-top: 0; }
}

/* ---------- Tag chips ---------- */
/* Positioning context for the autocomplete dropdown. */
.tags-input-wrap {
    position: relative;
    width: 100%;
}
/* Wrapper around chips + a text input. Looks like a single input field. */
.tags-input {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.4rem;
    min-height: 2.5rem;
    width: 100%;
    box-sizing: border-box;
    background: rgba(255, 252, 240, 0.7);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
}
.tags-input:focus-within {
    border-color: var(--burgundy);
    box-shadow: 0 0 0 3px rgba(122, 26, 26, 0.12);
}
.tags-input input {
    flex: 1 1 6rem;
    min-width: 4rem;
    border: none;
    background: transparent;
    padding: 0.25rem 0.2rem;
    min-height: 1.8rem;
    font-size: 0.95rem;
}
.tags-input input:focus { outline: none; box-shadow: none; }

.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.2rem 0.5rem;
    background: rgba(160, 124, 44, 0.14);
    border: 1px solid rgba(160, 124, 44, 0.35);
    border-radius: 999px;
    font-size: 0.82rem;
    color: var(--ink);
    white-space: nowrap;
}
.tag-chip-remove {
    background: none;
    border: none;
    color: var(--ink-soft);
    cursor: pointer;
    padding: 0 0.1rem;
    font-size: 1rem;
    line-height: 1;
    min-height: 1rem;
}
.tag-chip-remove:hover { color: var(--alert); }
/* Read-only chip — no remove button, slightly muted. */
.tag-chip-static { color: var(--ink-soft); }

/* Compact tag row used under book titles in the list / detail. */
.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 0.25rem;
}

/* Autocomplete dropdown anchored under .tags-input. Stays inside the form
   (.modal & .filter-bar both scroll/contain it on small screens). */
.tags-suggestions {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 0.25rem;
    background: var(--parchment-1);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    box-shadow: var(--shadow-soft);
    max-height: 14rem;
    overflow: auto;
    z-index: 5;
    padding: 0.2rem 0;
}
.tag-suggestion {
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.45rem 0.7rem;
    background: transparent;
    border: none;
    text-align: left;
    color: var(--ink);
    cursor: pointer;
    font-size: 0.92rem;
    min-height: auto;
    line-height: 1.3;
}
.tag-suggestion.highlight,
.tag-suggestion:hover {
    background: rgba(160, 124, 44, 0.16);
}
.suggestion-name { color: var(--ink); }
.suggestion-count {
    color: var(--ink-mute);
    font-size: 0.8rem;
    font-style: italic;
}

/* ---------- Book table (desktop) ---------- */
.book-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: rgba(255, 252, 240, 0.6);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-soft);
}
.book-table thead th {
    text-align: left;
    font-family: var(--display);
    font-weight: 600;
    font-style: italic;
    color: var(--burgundy-deep);
    background: linear-gradient(180deg, var(--parchment-2), var(--parchment-1));
    border-bottom: 1px solid var(--rule);
    padding: 0.7rem 0.9rem;
    font-size: 0.98rem;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.book-table thead th .arrow {
    display: inline-block;
    margin-left: 0.3em;
    color: var(--gold);
    font-style: normal;
    opacity: 0;
    transform: translateY(1px);
}
.book-table thead th.active .arrow { opacity: 1; }
.book-table tbody tr {
    transition: background-color 0.15s;
    cursor: pointer;
}
.book-table tbody tr:nth-child(even) { background: rgba(235, 220, 182, 0.28); }
.book-table tbody tr:hover { background: rgba(160, 124, 44, 0.14); }
.book-table td {
    padding: 0.65rem 0.9rem;
    border-bottom: 1px solid var(--rule-soft);
    vertical-align: top;
}
.book-table .col-catalog {
    font-family: var(--display);
    color: var(--gold);
    font-weight: 600;
    font-style: italic;
    white-space: nowrap;
    width: 7.5rem;
}
.book-table .col-author { color: var(--ink-soft); font-style: italic; width: 22%; }
.book-table .col-title { font-weight: 500; }
.book-table .col-year { color: var(--ink-mute); width: 4rem; }
.book-table .col-status { width: 14rem; }

/* Status pills */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.18rem 0.55rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-family: var(--body);
    border: 1px solid currentColor;
    background: rgba(255, 252, 240, 0.6);
    white-space: nowrap;
}
.pill .dot { width: 0.4rem; height: 0.4rem; border-radius: 50%; background: currentColor; }
.pill-available { color: var(--moss); }
.pill-on-loan   { color: var(--gold); }
.pill-overdue   { color: var(--alert); background: rgba(168, 66, 31, 0.08); }

.borrower-note {
    display: block;
    font-style: italic;
    font-size: 0.86rem;
    color: var(--ink-soft);
    margin-top: 0.25rem;
}
.borrower-note.is-overdue { color: var(--alert); }

/* Inline "(xx)" language tag tacked onto the end of a title — small and
   muted so it reads as metadata, not part of the title itself. */
.book-lang {
    font-size: 0.78rem;
    color: var(--ink-mute);
    font-style: italic;
    white-space: nowrap;
}

/* ---------- Book cards (mobile) ----------
   Two-column grid: title / author / tags / borrower-note flow in the left
   column; catalog code, copies-count and the status pill stack vertically
   in a right-edge column so the pill can never overlap the tag chips. */
.book-cards { display: none; flex-direction: column; gap: 0.7rem; }
.book-card {
    background: rgba(255, 252, 240, 0.78);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    padding: 0.85rem 1rem;
    box-shadow: var(--shadow-soft);
    cursor: pointer;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 0.9rem;
    row-gap: 0.2rem;
    align-items: start;
}
.book-card .card-main { min-width: 0; }
.book-card .card-aside {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.3rem;
    text-align: right;
    /* The pill has its own padding — keep the column narrow. */
    max-width: 9rem;
}
.book-card .card-catalog {
    font-family: var(--display);
    font-style: italic;
    color: var(--gold);
    font-size: 0.95rem;
    line-height: 1.1;
}
.book-card .card-copies {
    font-size: 0.78rem;
    color: var(--ink-mute);
    font-style: italic;
    white-space: nowrap;
    line-height: 1.1;
}
.book-card .card-title {
    font-family: var(--display);
    font-size: 1.2rem;
    color: var(--ink);
    margin: 0 0 0.1rem;
    line-height: 1.15;
    /* The right column already reserves space, so the title is free to use
       its full column width — no need for the old right-margin hack. */
    overflow-wrap: anywhere;
}
.book-card .card-author {
    font-style: italic;
    color: var(--ink-soft);
    font-size: 0.92rem;
    margin-bottom: 0.4rem;
}

@media (max-width: 767px) {
    .book-table { display: none; }
    .book-cards { display: flex; }
    .canvas    { padding: 1rem 0.9rem 2rem; }
}

/* Narrow viewports: keep the topbar usable down to ~360px by shrinking
   non-critical elements rather than wrapping the avatar to a new row. */
@media (max-width: 540px) {
    .brand-name        { font-size: 0.98rem; }
    .brand-name small  { display: none; }
    .topbar-inner      { padding: 0.7rem 0.9rem; gap: 0.6rem; }
}

/* Add User form: 3-up layout where labels live in row 1 and inputs in
   row 2, so a long Polish/Ukrainian label can wrap to two lines without
   misaligning the inputs across columns. On narrow screens it collapses
   to a single column of label / input pairs in source order. */
.add-user-grid {
    display: grid;
    gap: 0.3rem 0.6rem;
    grid-template-columns: 1fr;
    grid-template-areas:
        "lbl1"
        "in1"
        "lbl2"
        "in2"
        "lbl3"
        "in3";
    margin-bottom: 0.9rem;
}
.add-user-label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--gold);
    align-self: end;                  /* hug the input below */
    line-height: 1.2;
}
/* Inputs and the role <select> inherit nothing from .form-row, so without
   width:100% they collapse to their content width on narrow screens while
   the select sizes itself to its longest option — visually slim inputs and
   a much wider select. Force every grid-cell control to fill its column,
   and give them a chunkier touch target on mobile (the base input height
   of 2.5rem ≈ 40px is below the recommended 48px touch minimum). */
.add-user-grid input,
.add-user-grid select {
    width: 100%;
    box-sizing: border-box;
    min-height: 3rem;
    font-size: 1.05rem;
    padding: 0.7rem 0.85rem;
}
@media (min-width: 580px) {
    .add-user-grid {
        /* Display name and email/username carry real-world strings ("Sister
           Berenika", "sr.berenika@osb.example") so they get the lion's share
           of the row; the role <select> only ever shows a short word. */
        grid-template-columns: 2fr 2fr 1fr;
        grid-template-areas:
            "lbl1 lbl2 lbl3"
            "in1  in2  in3";
    }
}

/* Small inline help button — used next to labels like "Role" to open
   an explanatory modal. Styled like an italic glyph in a burgundy ring. */
.help-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.3rem;
    height: 1.3rem;
    min-height: 1.3rem;
    padding: 0;
    font-family: var(--display);
    font-style: italic;
    font-weight: 600;
    font-size: 0.9rem;
    line-height: 1;
    color: var(--burgundy);
    background: transparent;
    border: 1px solid var(--burgundy-soft);
    border-radius: 50%;
    cursor: help;
    text-transform: none;
    letter-spacing: 0;
}
.help-button:hover {
    background: var(--burgundy);
    color: var(--parchment-1);
    border-color: var(--burgundy-deep);
}

/* ---------- Modal / overlay ---------- */
.overlay {
    position: fixed;
    inset: 0;
    background: rgba(38, 26, 18, 0.42);
    backdrop-filter: blur(2px);
    z-index: 60;
    display: grid;
    place-items: center;
    padding: 1.2rem;
    animation: fadeIn 0.18s ease-out;
    /* Touch-drags on the overlay should not chain to the page underneath. */
    overscroll-behavior: contain;
    touch-action: none;
}
.modal {
    background: var(--parchment-1);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    width: min(640px, 100%);
    max-height: calc(100vh - 2rem);
    overflow: auto;
    padding: 1.6rem 1.8rem;
    box-shadow: var(--shadow-deep);
    position: relative;
    animation: pop 0.22s cubic-bezier(0.2, 1, 0.4, 1);
    /* The modal itself can scroll in both axes (so wide tables like the
       loan history can be panned horizontally on touch); the scroll never
       bubbles out to its overlay or the body. */
    overscroll-behavior: contain;
    touch-action: pan-x pan-y;
}
/* While any overlay is in the DOM, freeze body scroll so a finger drag
   across the modal can't move the book list beneath it. */
body:has(.overlay) {
    overflow: hidden;
    touch-action: none;
}
.modal.large { width: min(880px, 100%); }
/* Admin panel needs a touch more room than other large modals so the Book
   Audit table fits without horizontal scroll. ~1cm extra on desktop;
   mobile still falls back to 100% via min(). */
.modal.large.admin-modal { width: min(930px, 100%); }
.modal-close {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    background: transparent;
    border: none;
    font-family: var(--display);
    font-size: 1.5rem;
    color: var(--ink-soft);
    cursor: pointer;
    padding: 0.2rem 0.5rem;
}
.modal-close:hover { color: var(--burgundy); }
.modal h2 + .flourish { margin-top: -0.3rem; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop   { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }

/* ---------- Forms ---------- */
.form-row {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: 0.9rem;
}
.form-row label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--gold);
}
/* input:where(:not([type])) catches type-less <input> elements (JSX often
   omits type="text") at zero extra specificity, so scoped rules like
   .search input / .tags-input input / .add-user-grid input still win. */
input:where(:not([type])), input[type=text], input[type=email], input[type=password],
input[type=number], input[type=file], textarea {
    box-sizing: border-box;
    font-family: var(--body);
    font-size: 1rem;
    line-height: 1.45;
    color: var(--ink);
    background: rgba(255, 252, 240, 0.7);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 0.55rem 0.7rem;
    min-height: 2.5rem;          /* same target height as buttons / select pills */
    -moz-appearance: textfield;  /* hide Firefox spin buttons on number inputs */
}
/* Form-row children fill their column — the BookFormModal grid lays
   catalog-letter / number / extension side-by-side, and unsized inputs
   would shrink to their content width. */
.form-row input, .form-row textarea, .form-row select {
    width: 100%;
    box-sizing: border-box;
    min-height: 2.5rem;
}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
    /* Browser chrome on number inputs caused them to render taller than text
       inputs. The buttons aren't useful here, so hide them. */
    -webkit-appearance: none;
    margin: 0;
}
input[type=file] {
    padding: 0.35rem 0.5rem;     /* file inputs have their own button — give them a bit less padding */
}
textarea {
    min-height: 4.5rem;
    resize: vertical;
    /* Textareas inherit a serif body face, which looks cohesive next to
       the rest of the form. */
    font-family: var(--body);
}
input:focus, textarea:focus, select:focus {
    outline: none;
    border-color: var(--burgundy);
    box-shadow: 0 0 0 3px rgba(122, 26, 26, 0.12);
}
.form-actions { display: flex; gap: 0.6rem; justify-content: flex-end; margin-top: 1rem; }

.form-error {
    background: rgba(168, 66, 31, 0.08);
    border-left: 3px solid var(--alert);
    padding: 0.55rem 0.7rem;
    color: var(--alert);
    font-style: italic;
    margin-bottom: 0.8rem;
    border-radius: 0 var(--radius) var(--radius) 0;
}
.form-info {
    background: rgba(74, 98, 56, 0.07);
    border-left: 3px solid var(--moss);
    padding: 0.55rem 0.7rem;
    color: var(--moss);
    font-style: italic;
    margin-bottom: 0.8rem;
    border-radius: 0 var(--radius) var(--radius) 0;
}

/* ---------- Replace-word admin tab ---------- */
.replace-form {
    display: flex;
    align-items: flex-end;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-bottom: 0.9rem;
}
.replace-form .form-row { flex: 1 1 11rem; margin-bottom: 0; }
.replace-form button { white-space: nowrap; }
.replace-count { font-style: italic; color: var(--ink-soft); margin-bottom: 0.4rem; }
.replace-results {
    max-height: 46vh;
    overflow-y: auto;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: rgba(255, 252, 240, 0.5);
}
.replace-row {
    padding: 0.5rem 0.7rem;
    border-bottom: 1px solid var(--rule);
    font-size: 0.92rem;
}
.replace-row:last-child { border-bottom: none; }
.replace-meta {
    display: flex;
    align-items: baseline;
    gap: 0.7rem;
    margin-bottom: 0.15rem;
}
.replace-code { font-family: var(--display); font-style: italic; color: var(--gold); white-space: nowrap; }
.replace-id { color: var(--ink-mute); font-size: 0.78rem; }
.replace-field {
    color: var(--ink-soft);
    text-transform: uppercase;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
}
.replace-old { color: var(--ink-mute); }
.replace-new { color: var(--ink); }
.replace-old mark, .replace-new mark {
    border-radius: 3px;
    padding: 0 0.15em;
}
.replace-old mark {
    background: rgba(122, 26, 26, 0.12);
    color: var(--burgundy);
    text-decoration: line-through;
}
.replace-new mark {
    background: rgba(74, 98, 56, 0.15);
    color: var(--moss);
    font-weight: 600;
}

/* ---------- Login / Auth scene ---------- */
.auth-scene {
    flex: 1;
    display: grid;
    place-items: center;
    padding: 2rem 1rem;
}
.auth-card {
    width: min(440px, 100%);
    background: rgba(255, 252, 240, 0.88);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    padding: 2rem 2.2rem 2.4rem;
    box-shadow: var(--shadow-deep);
    position: relative;
}
.auth-card::before {
    /* decorative cross at the top */
    content: "\2720";
    position: absolute;
    top: -1.2rem;
    left: 50%;
    transform: translateX(-50%);
    font-size: 2rem;
    color: var(--burgundy);
    background: var(--parchment-1);
    padding: 0 0.6rem;
    line-height: 1;
}
.auth-card .eyebrow { text-align: center; }
.auth-card h1 { text-align: center; margin-bottom: 0.4rem; }
/* Tighter sizing for the auth title so a long Polish/Ukrainian translation
   ("Biblioteka Sióstr Misjonarek św. Benedykta") balances on the card. */
.auth-card h1.auth-title {
    font-size: clamp(1.65rem, 2.2vw + 0.8rem, 2.2rem);
    line-height: 1.12;
    letter-spacing: 0;
    margin-top: 0.2rem;
    padding: 0 0.4rem;
}
.auth-card .tagline { text-align: center; color: var(--ink-soft); font-style: italic; margin-bottom: 1.4rem; }

.tabs {
    display: flex;
    gap: 0.4rem;
    border-bottom: 1px solid var(--rule-soft);
    margin-bottom: 1rem;
}
.tabs button {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 0.45rem 0.9rem;
    font-family: var(--display);
    font-size: 1rem;
    font-style: italic;
    color: var(--ink-soft);
    border-radius: 0;
}
.tabs button.active { color: var(--burgundy); border-bottom-color: var(--burgundy); }

/* ---------- Detail / history table ---------- */
.history {
    /* Render natural column widths; fill the modal at minimum but allow
       overflow so a wide table can be horizontally panned inside the modal. */
    width: auto;
    min-width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}
.history th, .history td {
    padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--rule-soft);
    text-align: left;
    /* Don't squish text into hyphens — keep narrow columns wide enough to
       read, the modal will scroll if it has to. */
    white-space: nowrap;
}
.history th {
    font-family: var(--display);
    font-style: italic;
    color: var(--burgundy-deep);
}
.history .active-row { background: rgba(160, 124, 44, 0.10); }

.book-meta {
    display: grid;
    grid-template-columns: 8rem 1fr;
    gap: 0.4rem 1rem;
    margin-bottom: 1rem;
}
.book-meta dt {
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gold);
    align-self: center;
}
.book-meta dd { margin: 0; }

/* ---------- Admin panel ---------- */
.admin-tabs {
    display: flex;
    gap: 0.6rem;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 1rem;
}
.admin-tabs button {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 0.6rem 0.9rem;
    font-family: var(--display);
    font-style: italic;
    color: var(--ink-soft);
    border-radius: 0;
    font-size: 1.05rem;
}
.admin-tabs button.active { color: var(--burgundy); border-bottom-color: var(--burgundy); }
/* Admin tabs share a row with horizontal scrolling on small screens so a
   fourth tab ("Catalogs") doesn't push anything off the modal. */
.admin-tabs { overflow-x: auto; flex-wrap: nowrap; }
.admin-tabs button { white-space: nowrap; }

/* Add-catalog form: key + en + pl on one line for desktop, stack on narrow
   screens. Same shape as the add-user grid. */
.catalog-grid {
    display: grid;
    gap: 0.5rem 0.7rem;
    grid-template-columns: minmax(4rem, 6rem) 1fr 1fr;
    margin-bottom: 0.8rem;
}
.catalog-grid input { width: 100%; box-sizing: border-box; }
@media (max-width: 580px) {
    .catalog-grid { grid-template-columns: 1fr; }
}
/* Existing-entries table: keep the editor inputs from stretching to the
   full cell width on desktop. */
.catalog-table input { width: 100%; box-sizing: border-box; }
.catalog-table .cell-actions { white-space: nowrap; }
.catalog-table .cell-actions button + button { margin-left: 0.4rem; }
/* Letter column reads as a stylised catalog code on every viewport. */
.catalog-table .cell-key {
    font-family: var(--display);
    color: var(--gold);
    font-style: italic;
    white-space: nowrap;
}

/* Backup tab — type checkboxes laid out as a simple vertical list. */
.backup-types {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0.6rem 0 1rem;
}
.backup-type-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.6rem;
    background: rgba(160, 124, 44, 0.06);
    border: 1px solid var(--rule-soft);
    border-radius: var(--radius);
}
.backup-type-row input { width: auto; min-height: 0; }
/* Sub-option (e.g. "apply filters" under Books) nested beneath its parent. */
.backup-sub-row {
    margin-left: 1.6rem;
    background: rgba(160, 124, 44, 0.03);
    border-style: dashed;
}
/* Audit-table marker: a small italic chip following the main action badge
   to call out events written by the import flow. Stylistically tied to the
   gold palette so it sits beside the green/burgundy event badges without
   competing for attention. */
.audit-import-badge {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-style: italic;
    color: var(--gold);
    border: 1px dashed var(--gold);
    border-radius: 999px;
    background: rgba(160, 124, 44, 0.05);
    vertical-align: middle;
}

/* Conflict modal — one card per field, with old/new stacked beneath the
   field name so they read top-down. Cards with a real difference are
   marked with an alert-coloured left rule so the operator's eye jumps to
   what's actually changing. */
.conflict-fields {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    margin-bottom: 1rem;
}
.conflict-field {
    padding: 0.55rem 0.7rem 0.55rem 0.9rem;
    background: rgba(160, 124, 44, 0.05);
    border: 1px solid var(--rule-soft);
    border-left: 3px solid var(--rule);
    border-radius: var(--radius);
}
.conflict-field.changed {
    background: rgba(168, 66, 31, 0.06);
    border-left-color: var(--alert);
}
.conflict-field-name {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--gold);
    margin-bottom: 0.35rem;
}
.conflict-line {
    display: grid;
    grid-template-columns: 3.2rem 1fr;
    gap: 0.5rem;
    align-items: baseline;
    font-size: 0.92rem;
    line-height: 1.35;
}
.conflict-line + .conflict-line { margin-top: 0.15rem; }
.conflict-tag {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--ink-mute);
    font-style: italic;
}
.conflict-val { word-break: break-word; }
.conflict-field.changed .conflict-old .conflict-val {
    color: var(--ink-soft);
    text-decoration: line-through;
}
.conflict-field.changed .conflict-new .conflict-val {
    color: var(--ink);
    font-weight: 600;
}
/* Unchanged fields stay subdued — they're context, not the decision point. */
.conflict-field:not(.changed) .conflict-old .conflict-val,
.conflict-field:not(.changed) .conflict-new .conflict-val {
    color: var(--ink-soft);
}

/* Informational note attached below a backup-type-row (no input, just text). */
.backup-note {
    margin: -0.1rem 0 0 1.6rem;
    padding: 0.4rem 0.6rem;
    font-size: 0.82rem;
    font-style: italic;
    color: var(--ink-soft);
    border-left: 2px solid var(--gold);
    background: rgba(160, 124, 44, 0.04);
}

/* ----- Mobile card layout for the catalog list -----
   Below 640px the table collapses to a stack of cards. Each row becomes
   a self-contained card with the catalog letter as a big heading, the
   two descriptions labelled below (label text comes from the cell's
   data-label attribute so locales translate automatically), the book
   count as a footnote, and the action buttons as a full-width row. */
@media (max-width: 640px) {
    .catalog-table,
    .catalog-table thead,
    .catalog-table tbody,
    .catalog-table tr,
    .catalog-table td { display: block; width: 100%; }
    .catalog-table thead { display: none; }
    .catalog-table tr {
        background: rgba(255, 252, 240, 0.78);
        border: 1px solid var(--rule);
        border-radius: var(--radius);
        padding: 0.75rem 0.9rem;
        margin-bottom: 0.6rem;
        box-shadow: var(--shadow-soft);
        position: relative;
    }
    .catalog-table td {
        padding: 0.25rem 0;
        border: none;
    }
    /* Label rendered from data-label="…", which the JSX populates with
       the localised header for that column. */
    .catalog-table td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-size: 0.7rem;
        text-transform: uppercase;
        letter-spacing: 0.18em;
        color: var(--gold);
        margin-bottom: 0.15rem;
    }
    /* Letter cell becomes a top-right badge so the descriptions get the
       full content width. */
    .catalog-table .cell-key {
        position: absolute;
        top: 0.75rem;
        right: 0.9rem;
        font-family: var(--display);
        font-style: italic;
        color: var(--gold);
        font-size: 1.5rem;
        line-height: 1;
        padding: 0;
        margin: 0;
        width: auto;
    }
    /* Use `td.<class>` so the selector matches `td[data-label]` specificity
       — same weight, later source wins. */
    .catalog-table td.cell-key::before { display: none; }
    /* Description rows get a top margin so the letter badge doesn't crowd them. */
    .catalog-table td:nth-child(2) { margin-top: 0; padding-right: 2.5rem; }
    /* Compact count: "Copies: 1" on a single line, not two. */
    .catalog-table td.cell-count {
        font-size: 0.85rem;
        color: var(--ink-soft);
        font-style: italic;
        margin-top: 0.3rem;
    }
    .catalog-table td.cell-count::before {
        display: inline;
        margin-right: 0.35rem;
        margin-bottom: 0;
    }
    /* Action buttons span the row at the bottom of the card. */
    .catalog-table .cell-actions {
        white-space: normal;
        margin-top: 0.6rem;
        display: flex;
        gap: 0.4rem;
    }
    .catalog-table .cell-actions button {
        flex: 1 1 auto;
        margin-left: 0 !important;
    }
    /* In edit mode the letter stays visible at top-right but the form fills
       the card body. */
    .catalog-table tr.is-editing td:nth-child(2),
    .catalog-table tr.is-editing td:nth-child(3) { padding-right: 0; }
}

.user-list { display: flex; flex-direction: column; gap: 0.5rem; }
.user-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "who badge"
        "actions actions";
    gap: 0.5rem 0.8rem;
    align-items: center;
    padding: 0.55rem 0.75rem;
    background: rgba(255, 252, 240, 0.6);
    border: 1px solid var(--rule-soft);
    border-radius: var(--radius);
}
.user-row .who     { grid-area: who; display: flex; flex-direction: column; min-width: 0; }
.user-row .who .name { font-weight: 500; }
.user-row .who .meta {
    font-size: 0.82rem;
    color: var(--ink-mute);
    font-style: italic;
    overflow-wrap: anywhere;
}
.user-row > .badge { grid-area: badge; justify-self: end; }
.user-row .row-actions {
    grid-area: actions;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    justify-content: flex-end;
}
.user-row .badge {
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    padding: 0.18rem 0.5rem;
    border-radius: 999px;
    color: var(--burgundy);
    border: 1px solid var(--burgundy-soft);
    white-space: nowrap;
}

/* On wider viewports lay everything out in a single row */
@media (min-width: 640px) {
    .user-row {
        grid-template-columns: 1fr auto auto;
        grid-template-areas: "who badge actions";
    }
    .user-row .row-actions { justify-content: flex-end; }
}

/* ---------- Toasts ---------- */
.toast-stack {
    position: fixed;
    bottom: 1rem;
    right: 1rem;
    z-index: 80;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.toast {
    background: var(--ink);
    color: var(--parchment-1);
    padding: 0.6rem 1rem;
    border-radius: var(--radius);
    box-shadow: var(--shadow-deep);
    font-style: italic;
    animation: slideIn 0.18s ease-out;
    border-left: 3px solid var(--gold);
    max-width: 22rem;
}
.toast.error { border-left-color: var(--alert); }
@keyframes slideIn { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---------- Misc ---------- */
.empty {
    text-align: center;
    padding: 4rem 1rem;
    color: var(--ink-mute);
    font-style: italic;
}
.spinner {
    width: 1.1rem;
    height: 1.1rem;
    border: 2px solid var(--rule);
    border-top-color: var(--burgundy);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    display: inline-block;
    vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }

footer.imprint {
    text-align: center;
    color: var(--ink-mute);
    font-style: italic;
    font-size: 0.82rem;
    padding: 1.5rem 1rem 2rem;
    margin-top: 2rem;
    border-top: 1px solid var(--rule-soft);
}
