/* ============================================================
   Greek Library of London LMS — OPAC redesign
   public/css/opac.css

   Loaded ONLY by app/views/layouts/public.php, after main.css
   and components.css. Everything here is scoped under
   `.opac-body` so the staff, member and kiosk layouts — which
   reuse some .opac-* class names — are left untouched.

   Palette: light surfaces only (#f9f8f9 page / #ffffff cards),
   buttons black or #d90a2c. Type: Poppins (inherited).
   ============================================================ */

.opac-body {
    /* Scoped tokens ---------------------------------------- */
    --o-bg:          #f9f8f9;
    --o-surface:     #ffffff;
    --o-border:      #e6e8ef;
    --o-border-soft: #f0f1f5;

    --o-accent:       #d90a2c;
    --o-accent-soft:  rgba(217, 10, 44, 0.08);
    --o-accent-hover: #b60824;
    --o-black:        #111318;
    --o-navy:         #00378F;
    --o-lime:         #AAC10A;

    --o-text:      #111827;
    --o-text-soft: #374151;
    --o-muted:     #6b7280;

    --o-radius-sm:   8px;
    --o-radius:      14px;
    --o-radius-full: 999px;

    --o-shadow-sm: 0 1px 3px rgba(17, 19, 24, 0.06);
    --o-shadow-md: 0 6px 18px rgba(17, 19, 24, 0.08), 0 2px 5px rgba(17, 19, 24, 0.04);
    --o-shadow-lg: 0 18px 44px rgba(17, 19, 24, 0.12), 0 5px 14px rgba(17, 19, 24, 0.06);

    /* Re-point the shared accent so .btn--primary, pills and
       links inside the OPAC use the darker brand red.        */
    --color-accent:       #d90a2c;
    --color-accent-soft:  rgba(217, 10, 44, 0.08);
    --color-accent-hover: #b60824;

    background: var(--o-bg);
    color: var(--o-text);
    display: flex;
    flex-direction: column;
    min-height: 100vh;

    /* Mobile browsers overlay a translucent grey/blue block on a tapped
       element by default, ignoring its border-radius — on a solid pill
       button (e.g. the accent "Advanced Categories" CTA) that reads as
       the whole button flashing into one flat colour on touch. */
    -webkit-tap-highlight-color: transparent;
}

.opac-body a:hover { color: var(--o-accent); }

.opac-body :focus-visible {
    outline: 2px solid var(--o-accent);
    outline-offset: 2px;
    border-radius: 4px;
}


/* ================================================================
   HEADER
   ================================================================ */
.opac-body .opac-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: rgba(249, 248, 249, 0.86);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    border-bottom: 1px solid var(--o-border);
    padding: 0 var(--sp-8);
}

.opac-body .opac-header__inner {
    max-width: 1440px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: var(--sp-8);
    padding-block: 0.85rem;
    transition: padding-block var(--ease);
}

.opac-body .opac-header__brand { flex-shrink: 0; }

/* Height drives both lockups and width follows; object-fit stops a
   differently-proportioned logo uploaded in Settings from stretching. */
.opac-body .opac-header__logo {
    height: 40px;
    width: auto;
    max-width: 200px;
    object-fit: contain;
    object-position: left center;
}

.opac-body .opac-header__logo--full    { height: 52px; max-width: 150px; }
.opac-body .opac-header__logo--compact { height: 28px; max-width: 190px; display: none; }

/* Condensed state — once the reader scrolls past the top of the page
   the sticky bar tightens and the tall stacked lockup hands over to the
   wide wordmark, which stays readable in a shallow bar. Toggled by the
   scroll script in layouts/public.php. */
.opac-body .opac-header--condensed .opac-header__logo--full    { display: none; }
.opac-body .opac-header--condensed .opac-header__logo--compact { display: block; }

.opac-body .opac-header--condensed .opac-header__inner { padding-block: 0.5rem; }

.opac-body .opac-header--condensed {
    box-shadow: 0 1px 14px rgba(17, 24, 39, 0.07);
}

@media (prefers-reduced-motion: reduce) {
    .opac-body .opac-header__inner { transition: none; }
}

.opac-body .opac-nav {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-inline: auto;
}

.opac-body .opac-nav__item {
    padding: 0.55rem 0.9rem;
    border-radius: var(--o-radius-full);
    font-size: 0.87rem;
    font-weight: 500;
    color: var(--o-text-soft);
    border: none;
    background: transparent;
    transition: background var(--ease), color var(--ease);
}

.opac-body .opac-nav__item:hover {
    background: var(--o-border-soft);
    color: var(--o-text);
}

.opac-body .opac-nav__item--active,
.opac-body .opac-nav__item--active:hover {
    background: var(--o-black);
    color: #fff;
}

/* ================================================================
   MOBILE NAV DRAWER
   Below 980px .opac-nav is hidden (see the responsive block near the
   foot of this file); this drawer is what replaces it, so the four
   catalogue links stay reachable on a phone.
   ================================================================ */
.opac-body .opac-nav-toggle {
    display: none;               /* shown only under the 980px query */
    align-items: center;
    justify-content: center;
    width: 44px;                 /* 44px minimum touch target */
    height: 44px;
    flex-shrink: 0;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    background: var(--o-surface);
    color: var(--o-text-soft);
    cursor: pointer;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-body .opac-nav-toggle:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}

/* Round icon button matching .opac-nav-toggle — used by the phone
   header (search / sign in) so the bar reads as one row of circles
   rather than a hamburger next to a full-width red pill. Hidden above
   the phone breakpoint by .opac-show-sm. */
.opac-body .opac-icon-btn {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    background: var(--o-surface);
    color: var(--o-text-soft);
    cursor: pointer;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-body .opac-icon-btn:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}

.opac-body .opac-drawer {
    position: fixed;
    inset: 0;
    z-index: 300;                /* over the sticky header (100) and menus (200) */
    visibility: hidden;
}
.opac-body .opac-drawer--open { visibility: visible; }

.opac-body .opac-drawer__scrim {
    position: absolute;
    inset: 0;
    background: rgba(11, 16, 35, 0.45);
    opacity: 0;
    transition: opacity 220ms ease;
    border: none;
    padding: 0;
    width: 100%;
    cursor: pointer;
}
.opac-body .opac-drawer--open .opac-drawer__scrim { opacity: 1; }

.opac-body .opac-drawer__panel {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(78%, 320px);
    display: flex;
    flex-direction: column;
    background: var(--o-surface);
    box-shadow: var(--o-shadow-lg);
    padding: 1rem 0.9rem calc(1rem + env(safe-area-inset-bottom));
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform 260ms cubic-bezier(0.4, 0, 0.2, 1);
}
.opac-body .opac-drawer--open .opac-drawer__panel { transform: none; }

.opac-body .opac-drawer__top {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding-bottom: 0.9rem;
    border-bottom: 1px solid var(--o-border-soft);
}
.opac-body .opac-drawer__logo { height: 34px; width: auto; }
.opac-body .opac-drawer__close {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border: none;
    border-radius: var(--o-radius-full);
    background: transparent;
    color: var(--o-muted);
    cursor: pointer;
    transition: background var(--ease), color var(--ease);
}
.opac-body .opac-drawer__close:hover { background: var(--o-border-soft); color: var(--o-text); }

.opac-body .opac-drawer__nav {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding-top: 0.7rem;
}
.opac-body .opac-drawer__item {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-height: 44px;
    padding: 0.6rem 0.6rem;
    border-radius: 10px;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--o-text-soft);
    transition: background var(--ease), color var(--ease);
}
.opac-body .opac-drawer__item svg { color: var(--o-muted); flex-shrink: 0; }
.opac-body .opac-drawer__item:hover { background: var(--o-border-soft); color: var(--o-text); }
.opac-body .opac-drawer__item--active,
.opac-body .opac-drawer__item--active:hover {
    background: var(--o-black);
    color: #fff;
}
.opac-body .opac-drawer__item--active svg { color: #fff; }

.opac-body .opac-drawer__divider {
    height: 1px;
    background: var(--o-border-soft);
    margin: 0.8rem 0;
}

.opac-body .opac-drawer__label {
    display: block;
    padding: 0 0.6rem;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--o-muted);
}

/* The switcher also sits in the header on desktop; inside the drawer it
   needs to sit left-aligned rather than pinned to the header's flex row. */
.opac-body .opac-drawer .lang-switch { justify-content: flex-start; padding-inline: 0.6rem; }

.opac-body .opac-drawer__cta {
    margin-top: auto;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding-top: 1.2rem;
}
.opac-body .opac-drawer__cta .btn {
    width: 100%;
    min-height: 44px;
    justify-content: center;
}

/* -- Browse buttons (catalogue page) ------------------------- */
.opac-migration-banner {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    margin-bottom: 1.25rem;
    padding: 0.85rem 1.1rem;
    border: 1px solid rgba(0, 55, 143, 0.18);
    border-left: 4px solid var(--o-navy);
    border-radius: var(--o-radius-sm);
    background: rgba(0, 55, 143, 0.06);
    color: var(--o-navy);
    font-size: 0.9rem;
    line-height: 1.5;
}
.opac-migration-banner svg { flex: none; margin-top: 0.1rem; }

.opac-browse-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}

.opac-browse-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 1.15rem;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    font-size: 0.87rem;
    font-weight: 600;
    color: var(--o-text);
    cursor: pointer;
    transition: background var(--ease), color var(--ease),
                border-color var(--ease), transform var(--ease), box-shadow var(--ease);
}
.opac-browse-btn svg { color: var(--o-muted); transition: color var(--ease); }

.opac-browse-btn:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: var(--o-shadow-md);
}
.opac-browse-btn:hover svg { color: #fff; }

/* Groups the result count with the back button in a section header. */
.opac-section__hdr-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6rem 1rem;
    /* flex-shrink: 0 (as before this had 3 items) refused to let this box
       shrink at all, so it never got squeezed enough to trigger its own
       flex-wrap and just overflowed past its container instead. Letting
       it shrink (down to its own min-content, since it wraps internally)
       is what actually lets narrow screens break it onto multiple lines. */
    flex-shrink: 1;
    min-width: 0;
}

/* -- Back to catalogue -------------------------------------- */
.opac-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 1rem;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    font-size: 0.83rem;
    font-weight: 600;
    color: var(--o-text-soft);
    white-space: nowrap;
    flex-shrink: 0;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-back-btn:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}

.opac-body .opac-header__actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
}

/* Buttons — black or brand red only */
.opac-body .btn {
    border-radius: var(--o-radius-full);
    font-weight: 600;
    transition: transform var(--ease), box-shadow var(--ease),
                background var(--ease), border-color var(--ease), color var(--ease);
}
.opac-body .btn:active { transform: scale(0.97); }

.opac-body .btn--primary {
    background: var(--o-accent);
    border-color: var(--o-accent);
    color: #fff;
    box-shadow: 0 5px 14px rgba(217, 10, 44, 0.24);
}
.opac-body .btn--primary:hover {
    background: var(--o-accent-hover);
    border-color: var(--o-accent-hover);
    transform: translateY(-1px);
    box-shadow: 0 9px 20px rgba(217, 10, 44, 0.30);
}

.opac-body .btn--dark {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}
.opac-body .btn--dark:hover { background: #000; transform: translateY(-1px); }

.opac-body .btn--ghost {
    background: transparent;
    border: 1px solid var(--o-border);
    color: var(--o-text);
}
.opac-body .btn--ghost:hover {
    border-color: var(--o-black);
    background: transparent;
    color: var(--o-text);
}


/* ================================================================
   MEMBER HEADER CONTROLS (bell + split profile menu)
   Shared by the public OPAC header and the member-portal header —
   kept in one place so a signed-in member sees identical controls
   everywhere.
   ================================================================ */
.opac-body .member-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--o-radius-full);
    border: 1px solid var(--o-border);
    background: var(--o-surface);
    color: var(--o-text-soft);
    flex-shrink: 0;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-body .member-bell:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}
.opac-body .member-bell__badge {
    position: absolute;
    top: -4px;
    right: -4px;
    background: var(--o-accent);
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1;
    padding: 2px 5px;
    border-radius: 999px;
    min-width: 16px;
    text-align: center;
    border: 2px solid var(--o-bg);
}

/* Split profile button: left half links straight to the dashboard,
   the caret opens the account menu. */
.opac-body .member-profile-menu {
    position: relative;
    display: inline-flex;
    align-items: stretch;
}
.opac-body .opac-member-btn--split {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    padding-right: 0.6rem;
}
.opac-body .opac-member-btn__caret {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.6rem;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    border-left: 1px solid rgba(255, 255, 255, 0.3);
    margin: 0;
}
.opac-body .opac-member-btn__caret svg {
    transition: transform var(--ease);
}
.opac-body .opac-member-btn__caret[aria-expanded="true"] svg {
    transform: rotate(180deg);
}

.opac-body .member-profile-menu__panel {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    min-width: 190px;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    box-shadow: var(--o-shadow-md);
    padding: 0.4rem;
    z-index: 200;
}
.opac-body .member-profile-menu__item {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 0.55rem 0.75rem;
    border-radius: 8px;
    font-size: 0.875rem;
    font-weight: 500;
    font-family: inherit;
    color: var(--o-text);
    text-decoration: none;
    background: none;
    border: none;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.opac-body .member-profile-menu__item:hover { background: var(--o-border-soft); }
.opac-body .member-profile-menu__item--danger { color: #b91c1c; }
.opac-body .member-profile-menu__item--danger:hover { background: #fef2f2; }
.opac-body .member-profile-menu__divider {
    height: 1px;
    background: var(--o-border-soft);
    margin: 0.3rem 0.25rem;
}


/* ================================================================
   MAIN CONTAINER
   ================================================================ */
.opac-body .opac-main {
    max-width: 1440px;
    width: 100%;
    margin: 0 auto;
    padding: var(--sp-10) var(--sp-8) var(--sp-16);
    flex: 1;
}

/* The home page opens on the hero, so it needs no top padding. */
.opac-body .opac-main--home { padding-top: 0; }


/* ================================================================
   HERO
   ================================================================ */
.opac-body .opac-hero {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    gap: 3.5rem;
    align-items: center;
    padding-block: 4rem 3.5rem;
    background: none;
    border: none;
    text-align: left;
}

.opac-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--o-accent);
    margin-bottom: 1rem;
}
.opac-hero__eyebrow::before {
    content: "";
    width: 22px;
    height: 2px;
    background: var(--o-accent);
    border-radius: 2px;
}

.opac-body .opac-hero__title {
    font-size: clamp(2.2rem, 4.2vw, 3.2rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
    color: var(--o-text);
    margin: 0;
}
.opac-hero__title em {
    font-style: normal;
    color: var(--o-accent);
}

.opac-body .opac-hero__sub {
    margin-top: 1.1rem;
    font-size: 1rem;
    color: var(--o-text-soft);
    max-width: 42ch;
}

/* -- Search ------------------------------------------------- */
.opac-body .opac-hero__search {
    margin: 1.9rem 0 0;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    max-width: 560px;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    padding: 0.5rem 0.6rem 0.5rem 1.2rem;
    box-shadow: var(--o-shadow-md);
    transition: border-color var(--ease), box-shadow var(--ease);
}
.opac-body .opac-hero__search:focus-within {
    border-color: var(--o-accent);
    box-shadow: 0 0 0 4px var(--o-accent-soft), var(--o-shadow-md);
}

.opac-body .opac-hero__search-icon {
    position: static;
    display: flex;
    align-items: center;
    color: var(--o-muted);
    flex-shrink: 0;
}

.opac-body .opac-hero__search-input {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    box-shadow: none;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--o-text);
    padding: 0.55rem 0;
}
.opac-body .opac-hero__search-input::placeholder { color: var(--o-muted); opacity: 1; }

.opac-body .opac-hero__search-btn {
    position: static;
    background: var(--o-black);
    color: #fff;
    border: none;
    border-radius: var(--o-radius-full);
    padding: 0.7rem 1.3rem;
    font-weight: 600;
    font-size: 0.86rem;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--ease), transform var(--ease);
}
.opac-body .opac-hero__search-btn:hover {
    background: var(--o-accent);
    transform: translateY(-1px);
}

/* -- Suggested topic chips ---------------------------------- */
.opac-hero__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
}
.opac-hero__tag {
    font-size: 0.78rem;
    color: var(--o-muted);
    background: var(--o-surface);
    padding: 0.3rem 0.8rem;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    cursor: pointer;
    transition: border-color var(--ease), color var(--ease);
}
.opac-hero__tag:hover { border-color: var(--o-navy); color: var(--o-navy); }


/* ================================================================
   HERO STATS
   ================================================================ */
.opac-body .opac-stats {
    display: flex;
    gap: 2.25rem;
    margin: 2.1rem 0 0;
    padding: 0;
    background: none;
    border: none;
    box-shadow: none;
    justify-content: flex-start;
}

.opac-body .opac-stat {
    display: block;
    text-align: left;
}

.opac-body .opac-stat__num {
    display: block;
    font-size: 1.65rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--o-text);
    line-height: 1.2;
}

.opac-body .opac-stat__lbl {
    display: block;
    font-size: 0.74rem;
    color: var(--o-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.opac-body .opac-stat__divider { display: none; }


/* ================================================================
   HERO COVER COLLAGE
   ================================================================ */
.opac-collage {
    position: relative;
    height: 430px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The covers fan out as one overlapping deck rather than sitting at
   fixed corners, so the row stays gap-free whatever the cover count
   is (the member dashboard can render as few as two). */
.opac-collage__card {
    position: relative;
    flex: 0 0 auto;
    width: 29%;
    margin-left: -11.5%;
    aspect-ratio: 2 / 3;
    border-radius: var(--o-radius);
    overflow: hidden;
    background: var(--o-border-soft);
    box-shadow: var(--o-shadow-lg);
    transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
}
.opac-collage__card:first-child { margin-left: 0; }

.opac-collage__card > img,
.opac-collage__card > .opac-cover-fallback {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Any deck size (the member hero can render as few as two covers):
   the outer covers tilt outwards and sit low, inner ones ride high. */
.opac-collage__card              { transform: rotate(-2deg) translateY(-18px); z-index: 3; }
.opac-collage__card:nth-child(even) { transform: rotate(4deg) translateY(-6px); z-index: 4; }
.opac-collage__card:first-child  { transform: rotate(-9deg) translateY(30px); z-index: 1; }
.opac-collage__card:last-child   { transform: rotate(9deg)  translateY(30px); z-index: 2; }

/* Full five-cover deck: a shallow arc with the middle cover raised and
   in front, filling the hero column edge to edge. */
.opac-collage--5 .opac-collage__card:nth-child(1) { transform: rotate(-9deg) translateY(48px);  z-index: 1; }
.opac-collage--5 .opac-collage__card:nth-child(2) { transform: rotate(-4deg) translateY(6px);   z-index: 2; }
.opac-collage--5 .opac-collage__card:nth-child(3) { transform: rotate(1deg)  translateY(-46px); z-index: 5; }
.opac-collage--5 .opac-collage__card:nth-child(4) { transform: rotate(5deg)  translateY(6px);   z-index: 4; }
.opac-collage--5 .opac-collage__card:nth-child(5) { transform: rotate(10deg) translateY(48px);  z-index: 3; }

.opac-collage__card:hover {
    transform: translateY(-16px) rotate(0deg) scale(1.04) !important;
    z-index: 6;
}

.opac-collage__badge {
    position: absolute;
    left: 50%;
    bottom: -12px;
    transform: translateX(-50%);
    z-index: 8;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    white-space: nowrap;
    background: var(--o-black);
    color: #fff;
    padding: 0.55rem 1.05rem;
    border-radius: var(--o-radius-full);
    font-size: 0.76rem;
    font-weight: 600;
    box-shadow: var(--o-shadow-lg);
}
.opac-collage__badge .opac-collage__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--o-lime);
}


/* ================================================================
   SECTION HEADERS
   ================================================================ */
.opac-body .opac-section { margin-top: 3rem; }

.opac-body .opac-section__hdr {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;                  /* actions drop below on narrow screens */
    gap: 0.75rem 1rem;
    margin-bottom: 1.6rem;
    border: none;
    padding: 0;
}

.opac-section__eyebrow {
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--o-accent);
    margin-bottom: 0.35rem;
}

.opac-body .opac-section__title {
    display: block;
    font-size: 1.65rem;
    font-weight: 700;
    letter-spacing: -0.025em;
    color: var(--o-text);
    text-transform: none;
}

.opac-body .opac-section__link {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--o-text-soft);
    flex-shrink: 0;
}
.opac-body .opac-section__link:hover { color: var(--o-accent); }

/* Section heading between groups of simple-category shelf cards
   (Λογοτεχνία, Ιστορία & Βιογραφίες, ...) — see opac/categories.php. */
.opac-body .opac-shelf-group__title {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--o-muted);
    margin: 2rem 0 0.9rem;
}
.opac-body .opac-shelf-group__title:first-of-type { margin-top: 0; }


/* ================================================================
   BOOK CARD  (.opac-card — shared by catalog, new, A–Z,
   author and publisher pages)
   ================================================================ */
.opac-body .opac-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1.4rem;
}

/* The book page shows exactly six related titles — keep them on one
   row rather than letting the sixth wrap on its own. */
.opac-body .bk-related__grid {
    grid-template-columns: repeat(6, 1fr);
}

.opac-body .opac-card {
    display: flex;
    flex-direction: column;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    overflow: hidden;
    cursor: pointer;
    box-shadow: none;
    transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.opac-body .opac-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--o-shadow-md);
    border-color: transparent;
}

/* True book proportions, cover fills the frame edge to edge. */
.opac-body .opac-card__cover {
    width: 100%;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 0;
    display: block;
    background: var(--o-border-soft);
}

.opac-body .opac-card__cover--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.9);
    background: linear-gradient(155deg, #00378F, #1c5fd6);
}

/* Vinyl sleeves are square, not book-shaped. Three-class selector so this
   reliably beats the two-class base rules above regardless of stylesheet
   load order (main.css's .vinyl-card override loses that tie-break since
   opac.css loads after it — this is the belt-and-braces version). */
.opac-body .vinyl-card .opac-card__cover,
.opac-body .vinyl-card .opac-card__cover--placeholder {
    aspect-ratio: 1 / 1;
}

/* Deterministic cover tints so a wall of placeholders still
   reads as a shelf rather than a block of one colour. */
.opac-body .opac-card:nth-child(8n+2) .opac-card__cover--placeholder { background: linear-gradient(155deg, #d90a2c, #f2536e); }
.opac-body .opac-card:nth-child(8n+3) .opac-card__cover--placeholder { background: linear-gradient(155deg, #5b21b6, #8b5cf6); }
.opac-body .opac-card:nth-child(8n+4) .opac-card__cover--placeholder { background: linear-gradient(155deg, #7a8a07, #aac10a); }
.opac-body .opac-card:nth-child(8n+5) .opac-card__cover--placeholder { background: linear-gradient(155deg, #0f766e, #2dd4bf); }
.opac-body .opac-card:nth-child(8n+6) .opac-card__cover--placeholder { background: linear-gradient(155deg, #b45309, #f59e0b); }
.opac-body .opac-card:nth-child(8n+7) .opac-card__cover--placeholder { background: linear-gradient(155deg, #0369a1, #38bdf8); }
.opac-body .opac-card:nth-child(8n+8) .opac-card__cover--placeholder { background: linear-gradient(155deg, #334155, #64748b); }

.opac-body .opac-card__body { padding: 0.85rem 0.9rem 1rem; }

/* Max two lines, then an ellipsis. */
.opac-body .opac-card__title {
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--o-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    margin: 0;
}

.opac-body .opac-card__author {
    font-size: 0.8rem;
    color: var(--o-muted);
    margin-top: 0.2rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.opac-body .opac-card__meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: 0.65rem;
}

.opac-body .opac-card__year { font-size: 0.77rem; color: var(--o-muted); }

.opac-body .opac-card__avail {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.22rem 0.55rem;
    border-radius: var(--o-radius-full);
    white-space: nowrap;
    margin-top: 0;
}
.opac-body .opac-card__avail--yes { background: var(--color-green-soft); color: var(--color-green); }
.opac-body .opac-card__avail--no  { background: var(--color-red-soft);   color: var(--color-red); }

.opac-body .opac-card__dot { width: 6px; height: 6px; border-radius: 50%; }

.opac-card__badge {
    position: absolute;
    top: 0.6rem;
    left: 0.6rem;
    z-index: 2;
    font-size: 0.63rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0.22rem 0.55rem;
    border-radius: var(--o-radius-full);
    background: var(--o-lime);
    color: #1d2405;
}
.opac-card__cover-wrap { position: relative; }


/* Closing call to action, e.g. under the new-arrivals grid. */
.opac-see-all {
    display: flex;
    justify-content: center;
    margin-top: 2.5rem;
}


/* ================================================================
   NEW ARRIVALS SHELF (home)
   ================================================================ */
.opac-shelf-row { position: relative; }

.opac-shelf {
    display: flex;
    gap: 1.25rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-bottom: 0.5rem;
    scrollbar-width: none;
}
.opac-shelf::-webkit-scrollbar { display: none; }

.opac-shelf .opac-card {
    flex: 0 0 176px;
    scroll-snap-align: start;
}

.opac-shelf-nav {
    position: absolute;
    top: 34%;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    box-shadow: var(--o-shadow-md);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 5;
    color: var(--o-text);
    transition: background var(--ease), color var(--ease);
}
.opac-shelf-nav:hover { background: var(--o-black); color: #fff; }
.opac-shelf-nav--prev { left: -14px; }
.opac-shelf-nav--next { right: -14px; }


/* ================================================================
   CATEGORY CARDS (home) — no counts, by request
   ================================================================ */
.opac-cat-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1rem;
}

.opac-cat-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.2rem;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    cursor: pointer;
    transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.opac-cat-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--o-shadow-md);
    border-color: transparent;
}

.opac-cat-card__icon {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 55, 143, 0.08);
    color: var(--o-navy);
}
.opac-cat-card:nth-child(8n+2) .opac-cat-card__icon { background: rgba(217, 10, 44, 0.08); color: #d90a2c; }
.opac-cat-card:nth-child(8n+3) .opac-cat-card__icon { background: rgba(122, 138, 7, 0.10); color: #7a8a07; }
.opac-cat-card:nth-child(8n+4) .opac-cat-card__icon { background: rgba(91, 33, 182, 0.08); color: #5b21b6; }
.opac-cat-card:nth-child(8n+5) .opac-cat-card__icon { background: rgba(15, 118, 110, 0.09); color: #0f766e; }
.opac-cat-card:nth-child(8n+6) .opac-cat-card__icon { background: rgba(180, 83, 9, 0.09);  color: #b45309; }
.opac-cat-card:nth-child(8n+7) .opac-cat-card__icon { background: rgba(3, 105, 161, 0.09); color: #0369a1; }
.opac-cat-card:nth-child(8n+8) .opac-cat-card__icon { background: rgba(51, 65, 85, 0.09);  color: #334155; }

.opac-cat-card__name {
    font-weight: 600;
    font-size: 0.94rem;
    color: var(--o-text);
}


/* ================================================================
   INDEX PAGES (authors / publishers / categories)
   main.css stacks these in a single column, which strands a lot of
   whitespace now the container is wider — flow them into columns.
   ================================================================ */
.opac-body .opac-index-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 0.6rem;
}

.opac-body .opac-index-card {
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    padding: 0.85rem 1rem;
    transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.opac-body .opac-index-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--o-shadow-md);
    border-color: transparent;
}

.opac-body .opac-index-card__icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: var(--o-accent-soft);
    color: var(--o-accent);
    font-weight: 700;
}

.opac-body .opac-index-card__name  { font-size: 0.9rem; font-weight: 600; color: var(--o-text); }
.opac-body .opac-index-card__count { font-size: 0.76rem; color: var(--o-muted); }


/* ================================================================
   CATEGORY SHELF CARDS
   A fanned trio of real covers from the category, with the name
   floating over them on a banner. Covers are decorative — the link
   text carries the meaning — so they are hidden from assistive tech.
   ================================================================ */
.opac-body .opac-shelf-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
    gap: 1.5rem 1.35rem;
}

.opac-body .opac-shelf-card {
    display: block;
    position: relative;
    padding-bottom: 0.15rem;
    border-radius: var(--o-radius);
    cursor: pointer;
    transition: transform var(--ease);
}
.opac-body .opac-shelf-card:hover { transform: translateY(-4px); }
.opac-body .opac-shelf-card:focus-visible {
    outline: 2px solid var(--o-accent);
    outline-offset: 4px;
}

/* Stage — the shelf the covers stand on. Its own rounded, clipped box,
   so the banner can overhang the bottom edge and sit on the page. */
.opac-shelf-card__stage {
    position: relative;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    height: 208px;
    padding-top: 26px;
    overflow: hidden;
    border-radius: var(--o-radius) var(--o-radius) var(--o-radius-sm) var(--o-radius-sm);
    background: linear-gradient(180deg, #f2f3f7 0%, #e9ebf1 100%);
}

/* Each cover keeps its own slot so a broken image can swap in a spine. */
.opac-shelf-card__slot {
    position: relative;
    width: 92px;
    height: 172px;
    flex-shrink: 0;
    border-radius: 3px 5px 5px 3px;
    background: var(--o-surface);
    box-shadow: 0 10px 22px rgba(17, 19, 24, 0.16), 0 2px 6px rgba(17, 19, 24, 0.08);
    transition: transform var(--ease);
}

/* Left and right lean outward and sit above the middle, as on a table. */
.opac-shelf-card__slot--1 { z-index: 2; transform: translateX(20px) translateY(6px) rotate(-6deg); }
.opac-shelf-card__slot--2 { z-index: 1; }
.opac-shelf-card__slot--3 { z-index: 2; transform: translateX(-20px) translateY(6px) rotate(6deg); }

.opac-body .opac-shelf-card:hover .opac-shelf-card__slot--1 { transform: translateX(8px)  translateY(0) rotate(-9deg); }
.opac-body .opac-shelf-card:hover .opac-shelf-card__slot--2 { transform: translateY(-6px); }
.opac-body .opac-shelf-card:hover .opac-shelf-card__slot--3 { transform: translateX(-8px) translateY(0) rotate(9deg); }

/* A hairline ring keeps pale or placeholder covers reading as objects. */
.opac-shelf-card__cover {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
    background: var(--o-surface);
    box-shadow: inset 0 0 0 1px rgba(17, 19, 24, 0.10);
}
.opac-shelf-card__slot.is-blank .opac-shelf-card__cover { display: none; }

/* Shown only when a cover URL fails — a plain spine with the title. */
.opac-shelf-card__fallback {
    display: none;
    position: absolute;
    inset: 0;
    padding: 0.6rem 0.5rem;
    overflow: hidden;
    border-radius: inherit;
    background: linear-gradient(160deg, var(--o-navy) 0%, #052a63 100%);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1.35;
}
.opac-shelf-card__slot.is-blank .opac-shelf-card__fallback { display: block; }

.opac-shelf-card__empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 92px;
    height: 172px;
    border: 1px dashed #cdd1dc;
    border-radius: var(--o-radius-sm);
    color: var(--o-muted);
}

/* Banner — floats over the lower third of the covers and overhangs the
   shelf, so it reads as a label laid on top rather than part of the card. */
.opac-shelf-card__banner {
    position: relative;
    z-index: 3;
    margin: -58px 0.9rem 0;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.95rem 1.05rem;
    background: var(--o-surface);
    border-radius: var(--o-radius);
    box-shadow: var(--o-shadow-lg);
    transition: box-shadow var(--ease);
}
.opac-body .opac-shelf-card:hover .opac-shelf-card__banner {
    box-shadow: 0 22px 50px rgba(17, 19, 24, 0.16), 0 6px 16px rgba(17, 19, 24, 0.08);
}

.opac-shelf-card__text { min-width: 0; flex: 1; }

.opac-shelf-card__name {
    display: block;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--o-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.opac-shelf-card__count {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.76rem;
    color: var(--o-muted);
}

.opac-shelf-card__arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: var(--o-radius-full);
    color: var(--o-text-soft);
    background: transparent;
    transition: background var(--ease), color var(--ease), transform var(--ease);
}
.opac-body .opac-shelf-card:hover .opac-shelf-card__arrow {
    background: var(--o-accent);
    color: #fff;
    transform: translateX(3px);
}

/* One card per row on phones — scale the fan up to match the wider card. */
@media (max-width: 560px) {
    /* minmax(0,1fr), not 1fr: the track otherwise can't shrink below the
       card's min-content (~397px from the banner's Greek category name)
       and scrolls the page sideways on a 375px screen. */
    .opac-body .opac-shelf-grid { grid-template-columns: minmax(0, 1fr); }
    .opac-body .opac-shelf-card { min-width: 0; }
    .opac-body .opac-shelf-card__banner { min-width: 0; }
    .opac-shelf-card__stage     { height: 244px; padding-top: 30px; }
    .opac-shelf-card__slot,
    .opac-shelf-card__empty     { width: 116px; height: 204px; }
    .opac-shelf-card__slot--1   { transform: translateX(28px) translateY(6px) rotate(-6deg); }
    .opac-shelf-card__slot--3   { transform: translateX(-28px) translateY(6px) rotate(6deg); }
}

@media (prefers-reduced-motion: reduce) {
    .opac-body .opac-shelf-card,
    .opac-body .opac-shelf-card:hover,
    .opac-shelf-card__slot,
    .opac-body .opac-shelf-card:hover .opac-shelf-card__slot--1,
    .opac-body .opac-shelf-card:hover .opac-shelf-card__slot--2,
    .opac-body .opac-shelf-card:hover .opac-shelf-card__slot--3,
    .opac-body .opac-shelf-card:hover .opac-shelf-card__arrow {
        transform: none;
        transition: none;
    }
    .opac-shelf-card__slot--1 { transform: translateX(20px) translateY(6px) rotate(-6deg); }
    .opac-shelf-card__slot--3 { transform: translateX(-20px) translateY(6px) rotate(6deg); }
}


/* ================================================================
   CATALOG — layout + sidebar filters
   ================================================================ */
.opac-body .opac-catalog-layout {
    display: grid;
    grid-template-columns: 250px 1fr;
    gap: 2.5rem;
    align-items: start;
}

/* The whole rail is one card, with hairline-separated facets. */
.opac-body .opac-sidebar {
    position: sticky;
    top: 88px;
    display: block;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    padding: 0.35rem 1.15rem;
    box-shadow: var(--o-shadow-sm);
}

.opac-sidebar__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.9rem 0 0.85rem;
    border-bottom: 1px solid var(--o-border);
}
.opac-sidebar__title {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--o-text);
}
.opac-sidebar__clear { font-size: 0.78rem; font-weight: 600; color: var(--o-accent); }
.opac-sidebar__clear:hover { text-decoration: underline; }

.opac-body .sf-card {
    background: none;
    border: none;
    border-bottom: 1px solid var(--o-border-soft);
    border-radius: 0;
    box-shadow: none;
    padding-block: 0.95rem;
    margin: 0;
}
.opac-body .sf-card:last-child { border-bottom: none; }

.opac-body .sf-card__head {
    width: 100%;
    padding: 0;
    margin: 0 0 0.7rem;
    background: none;
    border: none;
    font: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    user-select: none;
}
.opac-body .sf-card__head:hover { background: none; }
.opac-body .sf-card__head:hover .sf-card__title,
.opac-body .sf-card__head:hover .sf-card__chevron { color: var(--o-accent); }

.opac-body .sf-card--collapsed .sf-card__head { margin-bottom: 0; }

.opac-body .sf-card__title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--o-muted);
    transition: color var(--ease);
}

.opac-body .sf-card__chevron {
    color: var(--o-muted);
    flex-shrink: 0;
    transition: transform var(--ease), color var(--ease);
}

.opac-body .sf-card__body { padding: 0; }

/* Long facet lists scroll rather than running down the page. */
.opac-body .sf-list {
    display: block;
    max-height: 216px;
    overflow-y: auto;
    margin: 0 -0.4rem;
    padding: 0 0.4rem;
    scrollbar-width: thin;
    scrollbar-color: #d7d9e2 transparent;
}
.opac-body .sf-list::-webkit-scrollbar { width: 6px; }
.opac-body .sf-list::-webkit-scrollbar-track { background: transparent; }
.opac-body .sf-list::-webkit-scrollbar-thumb {
    background: #d7d9e2;
    border-radius: var(--o-radius-full);
}
.opac-body .sf-list::-webkit-scrollbar-thumb:hover { background: #c2c5d2; }

.opac-body .sf-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.42rem 0.55rem;
    margin-bottom: 1px;
    font-size: 0.855rem;
    color: var(--o-text-soft);
    background: none;
    border: none;
    border-radius: var(--o-radius-sm);
    transition: background var(--ease), color var(--ease);
}
.opac-body .sf-item:hover {
    color: var(--o-text);
    background: var(--o-border-soft);
}

.opac-body .sf-item--active,
.opac-body .sf-item--active:hover {
    color: var(--o-accent);
    font-weight: 600;
    background: var(--o-accent-soft);
}

.sf-item__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Counts sit in a soft chip so the ragged right edge reads calmly. */
.sf-item__count {
    flex-shrink: 0;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--o-muted);
    background: var(--o-bg);
    border-radius: var(--o-radius-full);
    padding: 0.1rem 0.45rem;
    line-height: 1.5;
}
.opac-body .sf-item:hover .sf-item__count { background: #fff; }
.opac-body .sf-item--active .sf-item__count {
    background: #fff;
    color: var(--o-accent);
}

.sf-more {
    display: inline-block;
    margin-top: 0.55rem;
    padding-left: 0.55rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--o-navy);
}
.sf-more:hover { color: var(--o-accent); }

/* Category facet — a flat list of the ~28 simple buckets (see
   SimpleCategories.php), lightly grouped under non-interactive subject
   labels. The sidebar column is narrow and these are long Greek names, so
   names wrap to a second line rather than ellipsing almost every row. */
.opac-body .sf-list--categories { max-height: 400px; }

.opac-body .sf-group-label {
    padding: 0.6rem 0.55rem 0.2rem;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--o-muted);
}
.opac-body .sf-group-label:first-child { padding-top: 0.1rem; }

.opac-body .sf-list--categories .sf-item__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    white-space: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.35;
}

.opac-body .sf-group + .sf-group { margin-top: 1px; }

/* The row — not the link — carries hover/active, so the highlight spans
   the full width including the chevron and lines up with "All categories". */
.opac-body .sf-group__row {
    display: flex;
    align-items: flex-start;
    border-radius: var(--o-radius-sm);
    transition: background var(--ease);
}
.opac-body .sf-group__row:hover { background: var(--o-border-soft); }

.opac-body .sf-group__row--active,
.opac-body .sf-group__row--active:hover { background: var(--o-accent-soft); }

.opac-body .sf-group__link {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.4rem;
    padding: 0.42rem 0.3rem 0.42rem 0.55rem;
    font-size: 0.855rem;
    color: var(--o-text-soft);
    transition: color var(--ease);
}
.opac-body .sf-group__row:hover .sf-group__link { color: var(--o-text); }
.opac-body .sf-group__row--active .sf-group__link,
.opac-body .sf-group__row--active:hover .sf-group__link {
    color: var(--o-accent);
    font-weight: 600;
}
.opac-body .sf-group__link--static { cursor: default; }

/* Fixed height, top-aligned — so the chevron sits on the name's first
   line instead of drifting to the middle of a wrapped two-line row. */
.opac-body .sf-group__toggle {
    flex-shrink: 0;
    align-self: flex-start;
    width: 26px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: 0 var(--o-radius-sm) var(--o-radius-sm) 0;
    color: var(--o-muted);
    cursor: pointer;
}
.opac-body .sf-group__toggle:hover { color: var(--o-text); }
.opac-body .sf-group__row--active .sf-group__toggle { color: var(--o-accent); }

.opac-body .sf-group__chevron {
    flex-shrink: 0;
    width: 13px;
    height: 13px;
    transition: transform var(--ease);
}
.opac-body .sf-group--open > .sf-group__row .sf-group__chevron { transform: rotate(180deg); }

/* Names wrap to at most two lines — enough to read these long Greek
   class names in full in most cases, without a single category eating
   four rows of sidebar height. The count chip stays pinned to line one. */
.opac-body .sf-group__link .sf-item__name,
.opac-body .sf-item--sub .sf-item__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    white-space: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.35;
}
.opac-body .sf-group__link .sf-item__count,
.opac-body .sf-item--sub .sf-item__count { margin-top: 0.06rem; }

.opac-body .sf-sublist {
    display: none;
    padding-left: 0.6rem;
    border-left: 1px solid var(--o-border);
    margin: 0.2rem 0 0.35rem 0.9rem;
}
.opac-body .sf-group--open > .sf-sublist { display: block; }

.opac-body .sf-item--sub {
    align-items: flex-start;
    font-size: 0.8rem;
    padding: 0.34rem 0.5rem;
    color: var(--o-muted);
}
.opac-body .sf-item--sub:hover { color: var(--o-text); }

/* Year range */
.opac-body .sf-year-row { display: flex; align-items: center; gap: 0.5rem; }
.opac-body .sf-year-input {
    width: 100%;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-sm);
    padding: 0.5rem 0.6rem;
    font-size: 0.84rem;
    font-family: inherit;
    background: var(--o-bg);
    color: var(--o-text);
}
.opac-body .sf-year-sep { color: var(--o-muted); }

.opac-body .sf-year-btn {
    margin-top: 0.6rem;
    width: auto;
    background: var(--o-bg);
    color: var(--o-text);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    padding: 0.42rem 1rem;
    font-family: inherit;
    font-size: 0.79rem;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-body .sf-year-btn:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}

/* Availability toggle */
.opac-body .sf-avail { display: flex; gap: 0.5rem; }

.opac-body .sf-avail-btn {
    flex: 1;
    text-align: center;
    background: var(--o-bg);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    padding: 0.45rem 0.75rem;
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--o-text-soft);
    cursor: pointer;
    transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.opac-body .sf-avail-btn:hover { border-color: var(--o-black); }

.opac-body .sf-avail-btn--active,
.opac-body .sf-avail-btn--active:hover {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}


/* ================================================================
   CATALOG — toolbar
   ================================================================ */
.opac-body .cat-topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.15rem;
    padding: 0;
    background: none;
    border: none;
}

.opac-body .cat-topbar__search {
    flex: 1;
    min-width: 220px;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    padding: 0.5rem 0.6rem 0.5rem 1rem;
    background: var(--o-bg);
    transition: border-color var(--ease), box-shadow var(--ease);
}
.opac-body .cat-topbar__search:focus-within {
    border-color: var(--o-accent);
    box-shadow: 0 0 0 3px var(--o-accent-soft);
}

.opac-body .cat-topbar__search-input {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    font-family: inherit;
    font-size: 0.86rem;
    color: var(--o-text);
    padding: 0;
}

.opac-body .cat-topbar__search-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: var(--o-black);
    color: #fff;
    border-radius: 50%;
    width: 30px;
    height: 30px;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--ease);
}
.opac-body .cat-topbar__search-btn:hover { background: var(--o-accent); }

.opac-body .cat-browse {
    display: flex;
    gap: 0.35rem;
    flex-shrink: 0;
}
.opac-body .cat-browse__link {
    font-size: 0.83rem;
    font-weight: 500;
    color: var(--o-text-soft);
    padding: 0.5rem 0.8rem;
    border-radius: var(--o-radius-full);
    transition: background var(--ease), color var(--ease);
}
.opac-body .cat-browse__link:hover { background: var(--o-border-soft); color: var(--o-text); }

.opac-body .cat-sort {
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    padding: 0.55rem 1rem;
    font-family: inherit;
    font-size: 0.85rem;
    background: var(--o-bg);
    color: var(--o-text);
    cursor: pointer;
    flex-shrink: 0;
}

.opac-body .cat-view-toggle {
    display: flex;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    overflow: hidden;
    flex-shrink: 0;
}
.opac-body .cat-view-btn {
    border: none;
    background: transparent;
    padding: 0.55rem 0.8rem;
    cursor: pointer;
    color: var(--o-muted);
    display: flex;
    align-items: center;
    transition: background var(--ease), color var(--ease);
}
.opac-body .cat-view-btn--active { background: var(--o-black); color: #fff; }

/* Active filter pills */
.opac-body .cat-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}
.opac-body .cat-filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.79rem;
    font-weight: 500;
    background: var(--o-accent-soft);
    color: var(--o-accent);
    padding: 0.33rem 0.75rem;
    border-radius: var(--o-radius-full);
    border: none;
}
.opac-body .cat-filter-pill__x { color: inherit; opacity: 0.7; cursor: pointer; }
.opac-body .cat-filter-pill__x:hover { opacity: 1; color: inherit; }

.opac-body .cat-count {
    font-size: 0.85rem;
    color: var(--o-muted);
    margin-bottom: 1.2rem;
}
.opac-body .cat-count em {
    font-style: normal;
    color: var(--o-text);
    font-weight: 600;
}


/* ================================================================
   CATALOG — list view rows
   ================================================================ */
.opac-body .cat-list { display: flex; flex-direction: column; gap: 0.6rem; }

.opac-body .cat-list-row {
    display: grid;
    grid-template-columns: 40px 1fr auto auto auto;
    align-items: center;
    gap: 1rem;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-sm);
    padding: 0.6rem 1rem;
    transition: border-color var(--ease), transform var(--ease);
}
.opac-body .cat-list-row:hover {
    border-color: var(--o-accent);
    transform: translateX(3px);
}

.opac-body .cat-list-row__cover,
.opac-body .cat-list-row__cover--placeholder {
    width: 40px;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(155deg, #00378F, #1c5fd6);
    color: rgba(255, 255, 255, 0.9);
}

/* Title and author stack in the redesign, so the author stays
   visible at every width (main.css hides it below 780px). */
.opac-body .cat-list-row__title {
    display: block;
    font-weight: 600;
    font-size: 0.89rem;
    color: var(--o-text);
    line-height: 1.35;
}
.opac-body .cat-list-row__author {
    display: block;
    flex: none;
    font-size: 0.79rem;
    color: var(--o-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.opac-body .cat-list-row__year { font-size: 0.79rem; color: var(--o-muted); }

/* The title/author wrapper must be able to shrink inside the grid. */
.opac-body .cat-list-row__text { min-width: 0; }

.opac-body .cat-list-row__cat {
    font-size: 0.77rem;
    color: var(--o-text-soft);
    background: var(--o-border-soft);
    padding: 0.25rem 0.6rem;
    border-radius: var(--o-radius-full);
}

.opac-body .cat-list-row__avail {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.22rem 0.55rem;
    border-radius: var(--o-radius-full);
    white-space: nowrap;
}
.opac-body .cat-list-row__avail--yes { background: var(--color-green-soft); color: var(--color-green); }
.opac-body .cat-list-row__avail--no  { background: var(--color-red-soft);   color: var(--color-red); }
.opac-body .cat-list-row__dot { width: 6px; height: 6px; border-radius: 50%; }


/* ================================================================
   FOOTER — light, four columns
   ================================================================ */
.opac-body .opac-footer {
    background: var(--o-surface);
    border-top: 1px solid var(--o-border);
    padding: 3rem var(--sp-8) 1.5rem;
    margin-top: 2rem;
}

.opac-body .opac-footer__inner {
    max-width: 1440px;
    margin: 0 auto;
    font-size: inherit;
    color: inherit;
}

.opac-footer__grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 1.2fr;
    gap: 2.5rem;
}

.opac-footer__logo { height: 40px; width: auto; margin-bottom: 0.9rem; }

.opac-footer__desc {
    font-size: 0.85rem;
    color: var(--o-muted);
    max-width: 32ch;
    line-height: 1.65;
}

.opac-footer__col h4 {
    font-size: 0.76rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--o-muted);
    margin-bottom: 0.95rem;
    font-weight: 600;
}
.opac-footer__col ul { display: flex; flex-direction: column; gap: 0.6rem; }
.opac-footer__col a  { font-size: 0.86rem; color: var(--o-text-soft); }
.opac-footer__col a:hover { color: var(--o-accent); }

.opac-footer__contact {
    font-size: 0.86rem;
    color: var(--o-muted);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.opac-footer__bottom {
    border-top: 1px solid var(--o-border);
    margin-top: 2.5rem;
    padding-top: 1.4rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    justify-content: space-between;
    font-size: 0.78rem;
    color: var(--o-muted);
}
.opac-footer__bottom a { color: var(--o-muted); }
.opac-footer__bottom a:hover { color: var(--o-accent); }

/* "Powered by InterILS". Deliberately the quietest thing in the
   row — the library's name and charity number are what a visitor
   came for. Plain text, not a link: an acknowledgement, and it
   should not compete with the real footer links beside it. */
.product-credit {
    color: var(--o-muted);
    opacity: 0.75;
}

.opac-footer__site {
    margin-top: 0.6rem;
    font-size: 0.85rem;
}
.opac-footer__site a {
    color: var(--o-accent);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}
.opac-footer__site a:hover { border-bottom-color: currentColor; }

.opac-footer__charity a { text-decoration: underline; }
.opac-footer__charity span[aria-hidden] { opacity: 0.5; padding-inline: 0.25rem; }


/* ================================================================
   RESPONSIVE
   ================================================================ */
/* Five across once there is genuinely room for it. */
@media (min-width: 1360px) {
    .opac-body .opac-grid { grid-template-columns: repeat(5, 1fr); }
    .opac-body .bk-related__grid { grid-template-columns: repeat(6, 1fr); }
}

@media (max-width: 1080px) {
    .opac-body .opac-grid { grid-template-columns: repeat(3, 1fr); }
    .opac-body .bk-related__grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 980px) {
    .opac-body .opac-hero {
        grid-template-columns: 1fr;
        padding-block: 2.5rem;
        gap: 2.5rem;
    }
    /* The hero collapses to one column here, so the collage column is
       full-page-width — narrower cards keep the deck inside its box. */
    .opac-collage { height: 320px; }
    .opac-collage__card { width: 21%; margin-left: -8%; }
    .opac-collage__card:first-child { margin-left: 0; }
    /* The drawer (.opac-drawer, defined near the top of this file) is
       what carries these links from here down. */
    .opac-body .opac-nav { display: none; }
    .opac-body .opac-nav-toggle { display: inline-flex; }
    /* The switcher stays in the bar at phone widths — it took the
       place of the search circle, which only ever went to the
       catalogue the drawer and the Catalogue tab already reach.
       margin-left pins it to the right of the logo; the drawer keeps
       its own copy for anyone who opens it looking there. */
    .opac-body .opac-header__inner > .lang-switch { margin-left: auto; }
    .opac-cat-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Above the drawer's breakpoint it must never be reachable, even if it
   was left open when the viewport was widened. */
@media (min-width: 981px) {
    .opac-body .opac-drawer { display: none; }
}

@media (max-width: 900px) {
    .opac-body .opac-catalog-layout { grid-template-columns: 1fr; }
    .opac-body .opac-sidebar { position: static; }
    .opac-footer__grid { grid-template-columns: 1fr 1fr; row-gap: 2rem; }
}

@media (max-width: 760px) {
    .opac-body .opac-grid { grid-template-columns: repeat(2, 1fr); }
    .opac-body .bk-related__grid { grid-template-columns: repeat(2, 1fr); }
    .opac-body .cat-list-row { grid-template-columns: 40px 1fr auto; }
    .opac-body .cat-list-row__cat,
    .opac-body .cat-list-row__year { display: none; }
    .opac-shelf-nav { display: none; }
}

@media (max-width: 640px) {
    .opac-body .opac-header,
    .opac-body .opac-main,
    .opac-body .opac-footer { padding-inline: 1.1rem; }

    .opac-body .opac-header__inner { gap: 0.6rem; }
    .opac-body .opac-grid { gap: 1rem; }
    .opac-footer__grid { grid-template-columns: 1fr; }

    /* The footer centres itself at this width, but the logo is a
       block-level <img>, so text-align leaves it pinned to the left
       edge while every line beneath it is centred. Centre the boxes
       themselves so the lockup sits over its own text. */
    .opac-footer__logo,
    .opac-footer__desc { margin-inline: auto; }
    .opac-hide-sm { display: none !important; }

    /* Counterpart to .opac-hide-sm: the phone-only icon buttons. */
    .opac-body .opac-show-sm { display: inline-flex !important; }

    /* Nav is hidden at this width, so nothing else pushes the actions
       over to the right edge. */
    .opac-body .opac-header__actions { margin-inline-start: auto; }
    .opac-body .opac-header__inner > .member-bell { margin-inline-start: auto; }
    .opac-body .opac-header__inner > .member-bell ~ .opac-header__actions { margin-inline-start: 0; }

    /* A full-height logo plus three 44px circles overflows a 375px bar. */
    .opac-body .opac-header__logo--full    { height: 40px; }
    .opac-body .opac-header__logo--compact { height: 24px; }

    /* Three stats across a 375px screen: the labels are what get
       clipped, so they shrink and the row shares the space evenly
       instead of relying on a fixed gap. */
    .opac-body .opac-stats {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0.75rem;
    }
    .opac-body .opac-stat { min-width: 0; }
    .opac-body .opac-stat__lbl {
        font-size: 0.62rem;
        letter-spacing: 0.06em;
    }
}

/* Fills the gap the (desktop-only) cover collage leaves on a phone —
   see the media query below. */
.opac-hero__catalogue-cta { display: none; }


/* ================================================================
   HOME — PHONE LAYOUT
   The hero is sized for a desktop canvas: a 3.2rem headline and a
   430px cover collage filled the whole first screen, pushing the
   search and the shelves below the fold. On a phone the job of this
   page is "search, or start browsing", so it opens on those.
   ================================================================ */
@media (max-width: 760px) {
    .opac-body .opac-hero {
        padding-block: 1.5rem 1.75rem;
        gap: 1.5rem;
    }
    .opac-body .opac-hero__title { font-size: 1.85rem; }
    .opac-body .opac-hero__sub {
        margin-top: 0.7rem;
        font-size: 0.94rem;
    }
    .opac-hero__eyebrow { margin-bottom: 0.6rem; }

    .opac-body .opac-hero__search {
        margin-top: 1.25rem;
        padding: 0.4rem 0.45rem 0.4rem 1rem;
    }
    .opac-body .opac-hero__search-btn { padding: 0.65rem 1rem; }

    /* A grid/flex item defaults to min-width:auto, so the no-wrap rows
       below would force this column to their full min-content width and
       scroll the whole page sideways. These let them shrink and scroll
       inside themselves instead. */
    .opac-body .opac-hero,
    .opac-body .opac-hero__copy,
    .opac-body .opac-section { min-width: 0; }

    /* Five topic pills stacked five rows deep; they scroll now. */
    .opac-hero__tags {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        margin-inline: -1.1rem;
        padding-inline: 1.1rem;
    }
    .opac-hero__tags::-webkit-scrollbar { display: none; }
    .opac-hero__tag { flex-shrink: 0; }

    /* Decorative, and the tallest thing on the page — the shelves below
       are the actual content, so it stands down on a phone. */
    .opac-collage { display: none; }

    .opac-hero__catalogue-cta {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        margin-top: 1.5rem;
        min-height: 46px;
    }

    .opac-body .opac-stats {
        margin-top: 1.6rem;
        gap: 1.75rem;
    }
    .opac-body .opac-stat__num { font-size: 1.35rem; }

    .opac-body .opac-section { margin-top: 2.25rem; }

    /* Two tiles a row reads as a grid; one reads as a list of buttons.
       minmax(0,1fr) rather than 1fr: a plain 1fr track can't shrink below
       its min-content, and the long Greek category names then pushed each
       tile to 231px and scrolled the page sideways. */
    /* Side-by-side icon + name left the name a ~150px column, which
       broke the long Greek category names mid-word ("Μυθιστόρ ημα").
       Stacking the icon above gives the name the full tile width. */
    .opac-cat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.65rem;
    }
    .opac-cat-card {
        min-width: 0;
        flex-direction: column;
        align-items: flex-start;
        gap: 0.7rem;
        padding: 0.9rem;
    }
    .opac-cat-card__icon {
        width: 38px;
        height: 38px;
        border-radius: 10px;
    }
    .opac-cat-card__name {
        font-size: 0.86rem;
        line-height: 1.35;
        overflow-wrap: break-word;   /* only break a word with nowhere to go */
        word-break: normal;
        hyphens: auto;
    }

    /* Let the shelf bleed to the screen edges so it reads as swipeable. */
    .opac-body .opac-shelf {
        margin-inline: -1.1rem;
        padding-inline: 1.1rem;
        scroll-padding-left: 1.1rem;
    }
}


/* ================================================================
   CATALOGUE — MOBILE FILTER SHEET
   The facet sidebar is a screen and a half tall. Stacked above the
   results (which is what the 900px layout collapse did) it pushed the
   first book past 1100px of scroll. Below 900px it becomes a slide-up
   sheet: taking it out of flow puts the results at the top of the page.
   ================================================================ */
.opac-body .cat-filter-toggle,
.opac-body .cat-filter-scrim,
.opac-body .opac-sidebar__close,
.opac-body .opac-sidebar__done { display: none; }

@media (max-width: 900px) {
    .opac-body .cat-filter-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        flex-shrink: 0;
        border: 1px solid var(--o-black);
        border-radius: var(--o-radius-full);
        background: var(--o-black);
        color: #fff;
        cursor: pointer;
    }
    /* A filter is on — say so without relying on colour alone. */
    .opac-body .cat-filter-toggle--on {
        background: var(--o-accent);
        border-color: var(--o-accent);
    }

    .opac-body .cat-filter-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 240;
        background: rgba(11, 16, 35, 0.45);
    }
    .opac-body .cat-filter-scrim[hidden] { display: none; }

    .opac-body .opac-sidebar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        z-index: 250;
        width: auto;
        max-height: 85vh;
        overflow-y: auto;
        overscroll-behavior: contain;
        margin: 0;
        padding: 0 1.1rem calc(1rem + env(safe-area-inset-bottom));
        background: var(--o-surface);
        border: none;
        border-radius: 18px 18px 0 0;
        box-shadow: var(--o-shadow-lg);
        transform: translateY(100%);
        transition: transform 280ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    .opac-body .opac-sidebar--open { transform: none; }

    /* Sticky sheet header, so Filters/Clear stay reachable while the
       facet list scrolls underneath. */
    .opac-body .opac-sidebar__head {
        position: sticky;
        top: 0;
        z-index: 1;
        display: flex;
        align-items: center;
        gap: 0.75rem;
        padding: 1rem 0 0.75rem;
        margin: 0;
        background: var(--o-surface);
        border-bottom: 1px solid var(--o-border-soft);
    }
    .opac-body .opac-sidebar__close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        margin-left: auto;
        flex-shrink: 0;
        border: none;
        border-radius: var(--o-radius-full);
        background: var(--o-border-soft);
        color: var(--o-text-soft);
        cursor: pointer;
    }

    .opac-body .opac-sidebar__done {
        display: block;
        position: sticky;
        bottom: 0;
        padding: 0.75rem 0 0.25rem;
        background: linear-gradient(to top, var(--o-surface) 70%, transparent);
    }
    .opac-body .opac-sidebar__done-btn {
        width: 100%;
        min-height: 46px;
        border: none;
        border-radius: var(--o-radius-full);
        background: var(--o-black);
        color: #fff;
        font-family: inherit;
        font-size: 0.88rem;
        font-weight: 700;
        cursor: pointer;
    }

    /* Categories / Authors / Publishers / A–Z are "browse somewhere
       else" links, not filters — at the top of the results they cost a
       whole row before a single book. They live in the nav drawer on a
       phone (see partials/opac_drawer.php). */
    .opac-body .opac-browse-bar { display: none; }

    /* One row: search grows, filter button pinned to its right. Sort and
       the grid/list toggle move into the sheet — a phone shows the grid. */
    .opac-body .cat-topbar {
        display: flex;
        flex-wrap: nowrap;
        align-items: center;
        gap: 0.6rem;
    }
    .opac-body .cat-topbar__search { flex: 1; min-width: 0; }
    .opac-body .cat-topbar > .cat-sort,
    .opac-body .cat-view-toggle { display: none; }

    /* Sort, restated inside the filter sheet. The display:block that
       reveals it lives with the quick-chip rules below — it has to come
       after the base `display:none`, or that would win at every width. */
    .opac-body .sf-card--sort { padding-block: 0.9rem; }
    .opac-body .sf-sort__label {
        display: block;
        font-size: 0.72rem;
        font-weight: 700;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: var(--o-muted);
        margin-bottom: 0.45rem;
    }
    .opac-body .sf-sort__select {
        display: block;
        width: 100%;
        min-height: 44px;
    }
}

/* -- Quick filter chips (phones only) ------------------------- */
.opac-body .cat-quickchips { display: none; }

/* Desktop keeps its sort in the top bar; this sheet copy would be a
   second, competing control on the same page. */
.opac-body .sf-card--sort { display: none; }

@media (max-width: 900px) {
    .opac-body .cat-quickchips {
        display: flex;
        gap: 0.45rem;
        overflow-x: auto;
        scrollbar-width: none;
        margin: 0.75rem -1.1rem 0.25rem;
        padding-inline: 1.1rem;
    }
    .opac-body .cat-quickchips::-webkit-scrollbar { display: none; }

    .opac-body .cat-quickchip {
        flex-shrink: 0;
        display: inline-flex;
        align-items: center;
        min-height: 36px;
        padding: 0.4rem 0.85rem;
        border: 1px solid var(--o-border);
        border-radius: var(--o-radius-full);
        background: var(--o-surface);
        font-size: 0.78rem;
        font-weight: 600;
        color: var(--o-text-soft);
        white-space: nowrap;
        transition: background var(--ease), color var(--ease), border-color var(--ease);
    }
    .opac-body .cat-quickchip--active {
        background: var(--o-black);
        border-color: var(--o-black);
        color: #fff;
    }

    /* Reveals the sheet's sort control (styled further up). */
    .opac-body .sf-card--sort { display: block; }
}


/* ================================================================
   BOOK DETAIL — PHONE LAYOUT
   The three-column desktop layout collapses to one, but everything
   stayed left-aligned under a 200px cover with a desktop-sized
   headline. Centring the head gives the cover and title the focus
   they have on the artifact's book screen.
   ================================================================ */
@media (max-width: 760px) {
    .opac-body .bk-detail {
        gap: 1.5rem;
        justify-items: center;
        text-align: center;
    }
    .opac-body .bk-detail__cover-col { justify-self: center; }
    .opac-body .bk-detail__cover {
        width: 158px;
        max-width: 158px;
        margin-inline: auto;
        box-shadow: var(--o-shadow-md);
    }

    .opac-body .bk-detail__info-col {
        min-width: 0;
        width: 100%;
        text-align: center;
    }
    .opac-body .bk-detail__title {
        font-size: 1.4rem;
        line-height: 1.2;
        text-wrap: balance;
    }
    .opac-body .bk-detail__subtitle { font-size: .95rem; }
    .opac-body .bk-detail__author { margin-top: .35rem; }
    .opac-body .bk-rating { justify-content: center; }

    /* Body copy reads badly centred — only the head is. */
    .opac-body .bk-detail__desc {
        text-align: left;
        font-size: .92rem;
        margin-top: 1.1rem;
    }
    /* The "See more" toggle follows the body copy, not the centred head. */
    .opac-body .bk-detail__desc-wrap { text-align: left; }
    /* Less room on a phone, so the collapsed blurb is shorter too. */
    .opac-body .bk-detail__desc--clamped {
        -webkit-line-clamp: 5;
        line-clamp: 5;
    }

    /* Label/value pairs, left-aligned, tighter than the desktop table. */
    .opac-body .bk-detail__table { text-align: left; }
    .opac-body .bk-detail__table th,
    .opac-body .bk-detail__table td {
        padding-block: .45rem;
        font-size: .84rem;
    }
    .opac-body .bk-detail__table th { width: 42%; }

    .opac-body .bk-detail__sidebar,
    .opac-body .bk-sidebar { text-align: left; }
}


/* ================================================================
   BOOK DETAIL — MOBILE THUMB-ZONE ACTION BAR
   Desktop keeps the sidebar buttons; below 768px the two actions
   people came for move into a fixed bar and the sidebar's copies of
   them are hidden so nothing appears twice.
   ================================================================ */
.opac-body .bk-sticky { display: none; }

@media (max-width: 768px) {
    .opac-body .bk-action--reserve,
    .opac-body .bk-action--favourite { display: none; }

    .opac-body .bk-sticky {
        display: flex;
        align-items: center;
        gap: 0.6rem;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 150;
        padding: 0.7rem 1.1rem calc(0.7rem + env(safe-area-inset-bottom));
        background: rgba(255, 255, 255, 0.94);
        backdrop-filter: blur(12px) saturate(140%);
        -webkit-backdrop-filter: blur(12px) saturate(140%);
        border-top: 1px solid var(--o-border-soft);
    }

    .opac-body .bk-sticky__icon {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 46px;
        height: 46px;
        flex-shrink: 0;
        border: 1px solid var(--o-border);
        border-radius: var(--o-radius-full);
        background: var(--o-surface);
        color: var(--o-accent);
        cursor: pointer;
    }
    .opac-body .bk-sticky__icon--on {
        background: var(--o-accent-soft);
        border-color: transparent;
    }

    .opac-body .bk-sticky__form { flex: 1; min-width: 0; }

    .opac-body .bk-sticky__cta {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        flex: 1;
        min-height: 46px;
        padding: 0.7rem 1.2rem;
        border: none;
        border-radius: var(--o-radius-full);
        background: var(--o-black);
        color: #fff;
        font-family: inherit;
        font-size: 0.88rem;
        font-weight: 700;
        cursor: pointer;
    }
    .opac-body .bk-sticky__cta:disabled {
        background: var(--o-border);
        color: var(--o-muted);
        cursor: default;
    }
}


/* ================================================================
   MOTION
   ================================================================ */
.opac-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 600ms cubic-bezier(0.4, 0, 0.2, 1),
                transform 600ms cubic-bezier(0.4, 0, 0.2, 1);
}
.opac-reveal--in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .opac-body *,
    .opac-reveal {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    .opac-reveal { opacity: 1; transform: none; }
}


/* ================================================================
   ADVANCED CATEGORIES — full Dewey tree explorer
   /opac/catalog/categories/tree
   ================================================================ */

/* CTA that opens it, on the plain categories grid */
.opac-body .opac-back-btn--accent {
    background: var(--o-black);
    border-color: var(--o-black);
    color: #fff;
}
.opac-body .opac-back-btn--accent:hover {
    background: var(--o-accent);
    border-color: var(--o-accent);
}

.opac-body .cat-tree__intro {
    max-width: 62ch;
    margin: 0.35rem 0 1.5rem;
    color: var(--o-text-soft);
    font-size: 0.92rem;
    line-height: 1.6;
}

/* -- Toolbar: live search + expand/collapse ------------------ */
.opac-body .cat-tree__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}
.opac-body .cat-tree__search {
    flex: 1 1 280px;
    max-width: 400px;
    color: var(--o-muted);
}
.opac-body .cat-tree__toolbar-actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}
.opac-body .cat-tree__empty-filter {
    padding: 0.9rem 1.1rem;
    margin: -0.5rem 0 1.25rem;
    background: var(--o-border-soft);
    border-radius: var(--o-radius-sm);
    color: var(--o-muted);
    font-size: 0.87rem;
}

/* -- The tree itself ------------------------------------------ */
.opac-body ul.cat-tree,
.opac-body ul.cat-tree__children {
    list-style: none;
    margin: 0;
    padding: 0;
}

.opac-body .cat-tree--root {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.opac-body .cat-tree__node { position: relative; }

/* Nested branches: indent + a guide line down the left edge so a
   deep chain still reads as one continuous limb, not disconnected
   rows. At least 40px between the guide line and a child row's own
   content at every depth.
   Selector must match "ul.cat-tree__children" (not just the class) —
   the reset above is element+class specificity, so a plain-class rule
   here loses the cascade and its padding-left is silently dropped
   regardless of source order. */
.opac-body ul.cat-tree__children {
    margin: 0.3rem 0 0.3rem 0.6rem;
    padding-left: 40px;
    border-left: 2px solid var(--o-border);
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}
.opac-body .cat-tree__node:hover > .cat-tree__children,
.opac-body .cat-tree__children:hover {
    border-left-color: var(--o-accent-soft);
}

.opac-body .cat-tree__details { border: none; }
.opac-body .cat-tree__details > summary.cat-tree__row { list-style: none; }
.opac-body .cat-tree__details > summary.cat-tree__row::-webkit-details-marker,
.opac-body .cat-tree__details > summary.cat-tree__row::marker { display: none; content: ''; }

/* -- Row (shared by <summary> branches and <a> leaves) --------- */
.opac-body .cat-tree__row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border-radius: var(--o-radius-sm);
    color: var(--o-text);
    cursor: pointer;
    transition: background var(--ease);
}
.opac-body .cat-tree__row:hover { background: var(--o-border-soft); }
.opac-body .cat-tree__row:focus-visible { outline: 2px solid var(--o-accent); outline-offset: -2px; }

.opac-body .cat-tree__row--root {
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    padding: 0.75rem 1rem;
    box-shadow: var(--o-shadow-sm);
}
.opac-body .cat-tree__row--root:hover {
    border-color: var(--o-black);
    background: var(--o-surface);
    box-shadow: var(--o-shadow-md);
}
.opac-body .cat-tree__row--root .cat-tree__name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
}

.opac-body .cat-tree__row--leaf { text-decoration: none; }

.opac-body .cat-tree__chevron {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    color: var(--o-muted);
    transition: transform var(--ease);
}
.opac-body details[open] > summary.cat-tree__row > .cat-tree__chevron { transform: rotate(90deg); color: var(--o-text); }

.opac-body .cat-tree__chevron--leaf {
    width: 20px;
    color: var(--o-border);
}
.opac-body .cat-tree__chevron--leaf svg { width: 7px; height: 7px; }

/* Root-only numeral badge, e.g. "800" */
.opac-body .cat-tree__badge {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 42px;
    height: 28px;
    padding: 0 0.4rem;
    border-radius: var(--o-radius-full);
    background: var(--o-navy);
    color: #fff;
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.opac-body .cat-tree__label {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 0.55rem;
    flex-wrap: wrap;
}
.opac-body .cat-tree__name {
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--o-text);
}
.opac-body .cat-tree__code {
    font-family: 'SFMono-Regular', Consolas, monospace;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--o-muted);
    background: var(--o-border-soft);
    padding: 0.1rem 0.4rem;
    border-radius: var(--o-radius-sm);
    flex-shrink: 0;
}

/* Go button — icon-only (no counts shown), a real link so a branch can
   be browsed without being expanded first. Leaf rows reuse the same
   circle but as a plain <span> (cat-tree__go--static, see below) since
   the whole row is already the link — the box-model rule has to match
   both, not just the <a> variant, or the span renders unsized. */
.opac-body .cat-tree__go {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--o-accent-soft);
    color: var(--o-accent);
    text-decoration: none;
    transition: background var(--ease), color var(--ease), transform var(--ease);
}
.opac-body a.cat-tree__go:hover {
    background: var(--o-accent);
    color: #fff;
    transform: translateX(1px);
}
.opac-body a.cat-tree__go:focus-visible { outline: 2px solid var(--o-accent); outline-offset: 2px; }
.opac-body .cat-tree__go svg { flex-shrink: 0; }

.opac-body .cat-tree__go--static {
    background: var(--o-border-soft);
    color: var(--o-muted);
}
.opac-body .cat-tree__row--leaf:hover .cat-tree__go--static {
    background: var(--o-accent);
    color: #fff;
}

@media (max-width: 640px) {
    /* Only the outer margin (which just nudges the guide line under the
       parent's chevron, not the space before a child row's own content)
       shrinks on narrow screens. */
    .opac-body ul.cat-tree__children { margin-left: 0.3rem; padding-left: 15px; }
    .opac-body .cat-tree__row--root .cat-tree__name { font-size: 0.92rem; }
    .opac-body .cat-tree__code { display: none; }
    .opac-body .cat-tree__toolbar { flex-direction: column; align-items: stretch; }
    /* flex-basis tracks the main axis — once the toolbar above switches to
       column, the 280px meant as a row min-width becomes a fixed height
       instead, and border-radius: 999px turns the search pill into a
       circle. Reset it alongside the max-width already cleared here. */
    .opac-body .cat-tree__search { flex-basis: auto; max-width: none; }
}


/* ================================================================
   AUTHORS — shared portrait cards and profile hero
   The components live in main.css so the staff and public sides
   stay identical. Only the bits the OPAC's own link colours would
   otherwise repaint are re-stated here.
   ================================================================ */
.opac-body .author-card:hover { border-color: var(--o-accent); }
.opac-body .author-card:hover .author-card__name { color: var(--o-accent); }
.opac-body .author-card__bio { color: var(--o-muted); }

.opac-body .author-card:hover .author-portrait {
    box-shadow: 0 0 0 1px var(--o-accent), 0 0 0 5px var(--o-accent-soft);
}

.opac-body .author-portrait--monogram,
.opac-body .author-hero__portrait--monogram {
    color: var(--o-accent);
    background: var(--o-accent-soft);
}

.opac-body .author-hero__eyebrow { color: var(--o-accent); }

.opac-body .author-hero {
    border-color: var(--o-border);
    border-radius: var(--o-radius);
}

.opac-body .author-bio {
    color: var(--o-text-soft);
    border-left-color: var(--o-accent-soft);
}

.opac-body .author-bio__toggle { color: var(--o-accent); }
.opac-body .author-bio__toggle:hover { color: var(--o-accent-hover); }

/* Not a link on the public side — it's the freshness date, not a
   source credit, so it must not pick up the OPAC's link colour. */
.opac-body .author-source { color: var(--o-muted); }


/* ================================================================
   DIRECTORY BROWSE (authors / publishers)
   A search box and a card/A–Z toggle above the index, then the A–Z
   itself: a multi-column list filed by surname, which fits several
   hundred names on one screen where the cards need a dozen pages.
   ================================================================ */
.opac-body .opac-dir-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1.15rem;
}

/* The toggle halves are links here, not buttons. */
.opac-body .opac-dir-toolbar .cat-view-btn {
    text-decoration: none;
}
.opac-body .opac-dir-toolbar .cat-view-btn:hover {
    background: var(--o-accent-soft);
    color: var(--o-accent);
}
.opac-body .opac-dir-toolbar .cat-view-btn--active,
.opac-body .opac-dir-toolbar .cat-view-btn--active:hover {
    background: var(--o-black);
    color: #fff;
}

.opac-body .opac-dir-summary {
    margin: -0.4rem 0 1.15rem;
    font-size: 0.84rem;
    color: var(--o-muted);
}
.opac-body .opac-dir-clear {
    margin-left: 0.6rem;
    font-size: 0.8rem;
    color: var(--o-accent);
    text-decoration: none;
}
.opac-body .opac-dir-clear:hover { text-decoration: underline; }

.opac-body .opac-dir-jump {
    margin-bottom: 1.75rem;
    padding-bottom: 1.1rem;
    border-bottom: 1px solid var(--o-border);
}
.opac-body .opac-dir-jump .opac-az__script-label {
    margin-top: 0.9rem;
}
.opac-body .opac-dir-jump .opac-az__script-label:first-child {
    margin-top: 0;
}

.opac-body .opac-dir-group {
    margin-bottom: 1.9rem;
    /* Anchor jumps must not tuck the heading under the sticky header. */
    scroll-margin-top: 5rem;
}

.opac-body .opac-dir-group__letter {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    margin: 0 0 0.7rem;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--o-text);
    padding-bottom: 0.35rem;
    border-bottom: 2px solid var(--o-accent-soft);
}

.opac-body .opac-dir-group__script {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--o-muted);
}

.opac-body .opac-dir-list {
    columns: 3 260px;
    column-gap: 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.opac-body .opac-dir-list li {
    /* Keep a name and its count on the same side of a column break. */
    break-inside: avoid;
    margin-bottom: 0.12rem;
}

.opac-body .opac-dir-list__link {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.28rem 0.45rem;
    border-radius: 6px;
    font-size: 0.88rem;
    text-decoration: none;
    color: var(--o-accent);
    transition: background var(--ease), color var(--ease);
}
.opac-body .opac-dir-list__link:hover {
    background: var(--o-accent-soft);
}

.opac-body .opac-dir-list__name {
    min-width: 0;
    overflow-wrap: anywhere;
}

.opac-body .opac-dir-list__count {
    flex-shrink: 0;
    font-size: 0.74rem;
    font-variant-numeric: tabular-nums;
    color: var(--o-muted);
}

@media (max-width: 640px) {
    .opac-body .opac-dir-list { columns: 1; }
    /* flex-basis, not width — .cat-topbar__search is flex:1, so a width
       here would lose to its 0% basis and the field would stay cramped. */
    .opac-body .opac-dir-toolbar .cat-topbar__search { flex-basis: 100%; }
}


/* ================================================================
   VINYL RECORD — DETAIL PAGE  (app/views/opac/vinyl_show.php)

   The album profile: a full-width hero carrying the sleeve, the
   identity and the single action, then a reading column (blurb,
   tracklist, credits) beside a rail holding the player and the
   pressing's specs. Everything the reader came for is above the
   fold or one short scroll away, instead of three full-width
   sections stacked end to end.

   Own namespace rather than the book page's .bk-detail — the two
   pages now diverge enough that sharing classes would mean each
   one fighting the other's overrides.
   ================================================================ */
.opac-body .vnl {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}


/* ── Hero ────────────────────────────────────────────────────── */
.opac-body .vnl-hero {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    /* Wide enough for the record to slide out of the sleeve without
       reaching the title — see .vnl-disc. */
    gap: 4rem;
    align-items: center;
    padding: 2rem;
    background:
        linear-gradient(135deg, rgba(217, 10, 44, 0.035) 0%, rgba(217, 10, 44, 0) 46%),
        var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    box-shadow: var(--o-shadow-sm);
}

/* -- Sleeve, with the record sliding out from behind it -------- */
.opac-body .vnl-hero__art {
    position: relative;
    width: 100%;
}

.opac-body .vnl-hero__cover {
    position: relative;
    z-index: 1;
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 10px;
    box-shadow: var(--o-shadow-md);
}

.opac-body .vnl-hero__cover--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--o-border-soft);
    color: var(--o-muted);
    box-shadow: none;
}

/* Sits centred on the sleeve, then shifts right so only its outer
   edge shows — the sleeve's own z-index covers the rest. The travel
   is sized to stop inside the column gap: any further and the disc
   would slide under the title. */
.opac-body .vnl-disc {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 0;
    width: 80%;
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%) translateX(28%);
    pointer-events: none;
    filter: drop-shadow(0 10px 20px rgba(17, 19, 24, 0.22));
    transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.opac-body .vnl-disc svg { display: block; width: 100%; height: 100%; }

.opac-body .vnl-hero__art:hover .vnl-disc {
    transform: translate(-50%, -50%) translateX(38%);
}

@media (prefers-reduced-motion: no-preference) {
    /* Held paused rather than added on hover, so the disc keeps its
       angle when the pointer leaves instead of snapping back to 0. */
    .opac-body .vnl-disc svg {
        animation: vnl-disc-spin 4s linear infinite;
        animation-play-state: paused;
    }
    .opac-body .vnl-hero__art:hover .vnl-disc svg { animation-play-state: running; }

    /* Touch has no hover to start it, so it just turns. */
    @media (hover: none) {
        .opac-body .vnl-disc svg { animation-play-state: running; }
    }
}
@keyframes vnl-disc-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .opac-body .vnl-disc { transition: none; }
}

/* -- Identity -------------------------------------------------- */
/* Above the disc, which is positioned and would otherwise paint over
   this column's static content at the narrower breakpoints. */
.opac-body .vnl-hero__body {
    position: relative;
    z-index: 2;
}

.opac-body .vnl-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.32rem 0.8rem;
    border-radius: var(--o-radius-full);
    background: var(--o-accent-soft);
    color: var(--o-accent);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background var(--ease);
}
.opac-body .vnl-hero__eyebrow:hover {
    background: rgba(217, 10, 44, 0.14);
    color: var(--o-accent);
}

.opac-body .vnl-hero__title {
    margin: 0.85rem 0 0.35rem;
    font-size: clamp(1.65rem, 2.6vw, 2.4rem);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.08;
    color: var(--o-text);
    text-wrap: balance;
}

.opac-body .vnl-hero__artist {
    font-size: 1.05rem;
    font-weight: 500;
    color: var(--o-text-soft);
}
.opac-body .vnl-hero__artist a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color var(--ease), border-color var(--ease);
}
.opac-body .vnl-hero__artist a:hover {
    color: var(--o-accent);
    border-bottom-color: currentColor;
}

/* -- Year / genre / format / track-count chips ------------------ */
.opac-body .vnl-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-top: 1.1rem;
    padding: 0;
    list-style: none;
}
.opac-body .vnl-chip {
    padding: 0.32rem 0.8rem;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius-full);
    background: var(--o-surface);
    font-size: 0.78rem;
    color: var(--o-text-soft);
    white-space: nowrap;
}

/* -- Availability + the one call to action --------------------- */
.opac-body .vnl-hero__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1.25rem 2rem;
    margin-top: 1.5rem;
    padding-top: 1.35rem;
    border-top: 1px solid var(--o-border-soft);
}

.opac-body .vnl-hero__avail { min-width: 0; }

.opac-body .vnl-status {
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--color-green);
}
/* Inline rather than a flex item: the label wraps to two lines in the
   narrow hero, and a flex dot would float beside the gap between them
   instead of sitting on the first line. */
.opac-body .vnl-status__dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 0.45rem;
    border-radius: 50%;
    background: currentColor;
}

.opac-body .vnl-hero__note {
    margin-top: 0.4rem;
    max-width: 46ch;
    font-size: 0.8rem;
    line-height: 1.6;
    color: var(--o-muted);
}

.opac-body .vnl-hero__actions { flex-shrink: 0; }

.opac-body .vnl-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 44px;
    padding: 0.7rem 1.5rem;
    border: 1.5px solid transparent;
    border-radius: var(--o-radius-full);
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--ease), color var(--ease),
                border-color var(--ease), transform var(--ease);
}
.opac-body .vnl-btn--primary {
    background: var(--o-accent);
    border-color: var(--o-accent);
    color: #fff;
}
.opac-body .vnl-btn--primary:hover {
    background: var(--o-accent-hover);
    border-color: var(--o-accent-hover);
    color: #fff;
    transform: translateY(-1px);
}
.opac-body .vnl-btn:disabled,
.opac-body .vnl-btn[disabled] {
    opacity: 0.6;
    cursor: default;
    transform: none;
}

.opac-body .vnl-hint {
    margin-top: 0.55rem;
    font-size: 0.75rem;
    text-align: center;
    color: var(--o-muted);
}
.opac-body .vnl-hint a {
    color: var(--o-accent);
    text-decoration: none;
}
.opac-body .vnl-hint a:hover { color: var(--o-accent-hover); }


/* ── Body grid: reading column + specs/player rail ───────────── */
.opac-body .vnl-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 1.5rem;
    align-items: start;
}

.opac-body .vnl-main,
.opac-body .vnl-aside {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    min-width: 0;
}

/* Clears the sticky OPAC header. */
.opac-body .vnl-aside {
    position: sticky;
    top: 92px;
}

.opac-body .vnl-panel {
    min-width: 0;
    padding: 1.5rem;
    background: var(--o-surface);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    box-shadow: var(--o-shadow-sm);
}

.opac-body .vnl-panel__hdr {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.15rem;
}

.opac-body .vnl-panel__title {
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--o-text);
}
.opac-body .vnl-panel__title--spotify a {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    color: inherit;
    text-decoration: none;
    transition: color var(--ease);
}
.opac-body .vnl-panel__title--spotify a:hover { color: var(--o-accent); }
.opac-body .vnl-panel__title--spotify svg {
    color: #1db954;
    flex-shrink: 0;
}
.opac-body .vnl-panel__title--spotify .vnl-panel__title-ext {
    color: var(--o-muted);
    margin-left: 0.1rem;
}

.opac-body .vnl-panel__meta {
    flex-shrink: 0;
    font-size: 0.78rem;
    color: var(--o-muted);
}

.opac-body .vnl-panel__link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex-shrink: 0;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--o-muted);
    text-decoration: none;
    transition: color var(--ease);
}
.opac-body .vnl-panel__link:hover { color: var(--o-accent); }

/* The blurb keeps the shared collapsible-description component, but
   its standalone bottom margins would double the panel's padding. */
.opac-body .vnl-panel .bk-detail__desc {
    margin-bottom: 0;
    font-size: 0.93rem;
    color: var(--o-text-soft);
}
.opac-body .vnl-panel .bk-detail__desc--clamped { margin-bottom: 0.5rem; }
.opac-body .vnl-panel .bk-detail__desc-toggle { margin-bottom: 0; }


/* ── Tracklist ───────────────────────────────────────────────── */
/* Side A and side B sit next to each other: a 20-track running order
   is two short lists rather than one column running off the screen. */
.opac-body .vnl-sides {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 1.6rem 2.5rem;
}

.opac-body .vnl-side__label {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.55rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--o-muted);
}
/* Rule trailing the label, drawn to whatever width is left over. */
.opac-body .vnl-side__label::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--o-border);
}

.opac-body .vnl-tracks {
    margin: 0;
    padding: 0;
    list-style: none;
}

.opac-body .vnl-track {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    padding: 0.45rem 0.5rem;
    border-radius: 8px;
    font-size: 0.9rem;
    transition: background var(--ease);
}
.opac-body .vnl-track:hover { background: var(--o-border-soft); }

.opac-body .vnl-track__num {
    flex-shrink: 0;
    min-width: 1.5rem;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--o-muted);
}

.opac-body .vnl-track__title {
    flex: 1;
    min-width: 0;
    color: var(--o-text);
    overflow-wrap: anywhere;
}

.opac-body .vnl-track__credits {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.75rem;
    color: var(--o-muted);
}

.opac-body .vnl-track__dur {
    flex-shrink: 0;
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
    color: var(--o-muted);
}


/* ── Credits ─────────────────────────────────────────────────── */
/* Grouped by role — the raw Discogs list repeats "Voice [Quintet]"
   once per singer, which reads as a wall of near-identical lines. */
.opac-body .vnl-credits {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 0 3rem;
}

/* Role and names sit in their own two columns so every row lines up,
   however many lines a "Conductor [Chorus & Performers]" takes. */
.opac-body .vnl-credit {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: 0.5rem 1.25rem;
    align-items: baseline;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--o-border-soft);
}

.opac-body .vnl-credit__role {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--o-muted);
}

.opac-body .vnl-credit__names {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.88rem;
    line-height: 1.65;
    color: var(--o-text);
}


/* ── Player + specs rail ─────────────────────────────────────── */
.opac-body .vnl-player {
    display: block;
    width: 100%;
    border: 0;
    border-radius: 12px;
}

.opac-body .vnl-specs { margin: 0; }

.opac-body .vnl-specs__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--o-border-soft);
    font-size: 0.85rem;
}
.opac-body .vnl-specs__row:first-child { padding-top: 0; }
.opac-body .vnl-specs__row:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.opac-body .vnl-specs dt { color: var(--o-muted); }
.opac-body .vnl-specs dd {
    margin: 0;
    min-width: 0;
    font-weight: 500;
    color: var(--o-text);
    text-align: right;
    overflow-wrap: anywhere;
}


/* ── Responsive ──────────────────────────────────────────────── */
@media (max-width: 1100px) {
    .opac-body .vnl-hero {
        grid-template-columns: 235px minmax(0, 1fr);
        gap: 2.75rem;
    }
    .opac-body .vnl-grid { grid-template-columns: minmax(0, 1fr) 300px; }
}

/* One column — and the rail's two panels break apart so the player
   lands right under the hero and the specs settle at the end,
   instead of both being pushed below the whole tracklist. */
@media (max-width: 900px) {
    .opac-body .vnl-grid {
        display: flex;
        flex-direction: column;
        gap: 1.25rem;
        /* The grid layout's `start` would size each panel to its own
           content once these are flex items, not the column's width. */
        align-items: stretch;
    }
    .opac-body .vnl-main,
    .opac-body .vnl-aside { display: contents; }

    .opac-body .vnl-panel--player { order: 1; }
    .opac-body .vnl-panel--about  { order: 2; }
    .opac-body .vnl-panel--tracks { order: 3; }
    .opac-body .vnl-panel--specs  { order: 4; }
}

@media (max-width: 700px) {
    .opac-body .vnl-hero {
        grid-template-columns: 1fr;
        justify-items: center;
        text-align: center;
        gap: 1.6rem;
        padding: 1.5rem 1.25rem;
    }
    .opac-body .vnl-hero__art { width: 190px; }
    /* The peek would push the sleeve off-centre at this size. */
    .opac-body .vnl-disc {
        width: 74%;
        transform: translate(-50%, -50%) translateX(42%);
    }
    .opac-body .vnl-hero__body { width: 100%; }
    .opac-body .vnl-chips { justify-content: center; }

    .opac-body .vnl-hero__foot {
        flex-direction: column;
        align-items: stretch;
        gap: 1.15rem;
    }
    /* Body copy reads badly centred — only the head is. */
    .opac-body .vnl-hero__note {
        max-width: none;
        text-align: left;
    }
    .opac-body .vnl-btn { width: 100%; }

    .opac-body .vnl-panel { padding: 1.25rem; }
    .opac-body .vnl-sides { gap: 1.4rem; }

    /* No room for the role/names split — stack them again. */
    .opac-body .vnl-credit {
        grid-template-columns: 1fr;
        gap: 0.15rem;
    }
}

/* ============================================================
   Privacy notice  (/opac/privacy)
   Long-form legal text. Optimised for actually being read:
   a narrow measure, generous line-height, and clear hierarchy.
   Many members are older readers, so the base size is bumped
   above the site default rather than shrunk to fit.
   ============================================================ */

.pp {
    max-width: 46rem;              /* ~70 characters — a readable measure */
    margin: 0 auto;
    padding: var(--sp-8) var(--sp-5) var(--sp-12);
    font-size: 1.0625rem;
    line-height: 1.75;
    color: var(--color-text-soft);
}

/* ── Staff-only "not ready to publish" banner ─────────────── */
.pp-warn {
    margin-bottom: var(--sp-8);
    padding: var(--sp-5) var(--sp-6);
    border: 1px solid #f0c2c9;
    border-left: 4px solid var(--color-accent);
    border-radius: var(--radius-lg);
    background: var(--color-accent-soft);
}
.pp-warn__title {
    margin: 0 0 var(--sp-2);
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--color-accent-hover);
}
.pp-warn__body { margin: 0 0 var(--sp-3); font-size: .95rem; }
.pp-warn__list {
    margin: 0 0 var(--sp-3);
    padding-left: var(--sp-5);
    font-size: .9rem;
}
.pp-warn__list li { margin-bottom: var(--sp-1); }
.pp-warn__note { margin: 0; font-size: .85rem; color: var(--color-muted); }

/* ── Header ───────────────────────────────────────────────── */
.pp-head {
    margin-bottom: var(--sp-8);
    padding-bottom: var(--sp-5);
    border-bottom: 2px solid var(--color-border);
}
.pp-head__title {
    margin: 0 0 var(--sp-2);
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 4vw, 2.25rem);
    font-weight: 700;
    line-height: 1.2;
    color: var(--color-navy);
}
.pp-head__sub   { margin: 0 0 var(--sp-3); font-size: 1.05rem; color: var(--color-muted); }
.pp-head__date  { margin: 0; font-size: .875rem; color: var(--color-muted-light); }

.pp-lead {
    margin-bottom: var(--sp-8);
    font-size: 1.125rem;
    line-height: 1.7;
    color: var(--color-text);
}

/* ── Sections ─────────────────────────────────────────────── */
.pp-sec { margin-bottom: var(--sp-10); }

.pp-sec h2 {
    margin: 0 0 var(--sp-4);
    padding-top: var(--sp-2);
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--color-navy);
}
.pp-sec h3 {
    margin: var(--sp-6) 0 var(--sp-2);
    font-size: 1.02rem;
    font-weight: 600;
    color: var(--color-text);
}
.pp-sec p { margin: 0 0 var(--sp-4); }
.pp-sec p:last-child { margin-bottom: 0; }

/* Sections that deserve visual weight: reading history, children */
.pp-sec--mark {
    padding: var(--sp-6);
    border-radius: var(--radius-lg);
    background: var(--color-navy-soft);
}
.pp-sec--mark h2 { padding-top: 0; }

.pp-sec--contact {
    padding: var(--sp-6);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}
.pp-sec--contact h2 { padding-top: 0; }

/* ── Lists ────────────────────────────────────────────────── */
.pp-list {
    margin: 0 0 var(--sp-4);
    padding-left: var(--sp-5);
}
.pp-list li { margin-bottom: var(--sp-3); }

.pp-dl { margin: 0; }
.pp-dl dt {
    margin-top: var(--sp-5);
    font-weight: 600;
    color: var(--color-text);
}
.pp-dl dt:first-child { margin-top: 0; }
.pp-dl dd { margin: var(--sp-1) 0 0; padding: 0; }

.pp-note {
    padding: var(--sp-4);
    border-radius: var(--radius);
    background: var(--color-bg);
    font-size: .95rem;
    color: var(--color-muted);
}

/* Unfilled organisational fact — must be impossible to miss */
.pp-todo {
    padding: 0 .35em;
    border-radius: var(--radius-sm);
    background: #fff2b2;
    color: #7a5c00;
    font-weight: 600;
    font-style: normal;
    white-space: nowrap;
}

@media (max-width: 640px) {
    .pp { padding: var(--sp-6) var(--sp-4) var(--sp-10); font-size: 1rem; }
    .pp-sec { margin-bottom: var(--sp-8); }
    .pp-sec--mark,
    .pp-sec--contact { padding: var(--sp-5) var(--sp-4); }
}

/* ============================================================
   Contact page  (/opac/contact)
   A grid of address/phone/email/hours cards above the shared
   .pp-sec blocks, so it reads as one page with the privacy
   notice and terms rather than a bespoke layout.
   ============================================================ */

.contact-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-4);
    margin-bottom: var(--sp-10);
}
.contact-card {
    padding: var(--sp-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}
.contact-card h2 {
    margin: 0 0 var(--sp-2);
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-navy);
}
.contact-card p { margin: 0; font-size: .95rem; line-height: 1.6; }
.contact-card__link {
    display: inline-block;
    margin-top: var(--sp-2);
    font-weight: 600;
    color: var(--color-accent);
    text-decoration: none;
}
.contact-card__link:hover { text-decoration: underline; }

@media (max-width: 640px) {
    .contact-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   FUNDRAISING CAMPAIGN BANNER
   partials/campaign_banner.php — two registers of the same
   appeal. `.opac-campaign` is the band on the public home page;
   `.opac-campaign-card` is the quieter card on the member
   dashboard and the visit page, deliberately built from the same
   parts as `.opac-migration-banner` above so it reads as site
   furniture rather than a second pitch.

   Both are laid out so the Donorbox meter — a fixed 90px-tall
   iframe we do not control the inside of — can never squash the
   copy beside it: it sits in its own track and drops below on a
   narrow screen rather than shrinking.
   ============================================================ */

.opac-campaign {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 2rem;
    margin: 2.5rem 0;
    padding: 1.6rem 1.8rem;
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    /* The flag's two colours at a whisper, over white — enough to
       lift the band off the page without competing with the red
       button sitting inside it. */
    background:
        linear-gradient(135deg, rgba(217, 10, 44, .05) 0%, rgba(0, 55, 143, .045) 100%),
        var(--o-surface);
    box-shadow: var(--o-shadow-sm);
}

.opac-campaign__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin: 0 0 .5rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--o-accent);
}
.opac-campaign__eyebrow svg { flex: none; }

.opac-campaign__title {
    margin: 0 0 .45rem;
    font-size: 1.28rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--o-text);
}

.opac-campaign__body {
    margin: 0;
    max-width: 56ch;
    font-size: .92rem;
    line-height: 1.6;
    color: var(--o-text-soft);
}

.opac-campaign__aside {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .75rem;
    width: 300px;
}

/* Donorbox's own minimum is 250px and its maximum 332px; anything
   outside that and the meter's internal layout breaks. */
.opac-campaign__meter,
.opac-campaign-card__meter {
    width: 100%;
    max-width: 332px;
    min-width: 250px;
    height: 93px;
    min-height: 90px;
    border: 0;
}

.opac-body .opac-campaign__cta {
    min-height: 44px;
    justify-content: center;
}

@media (max-width: 860px) {
    .opac-campaign {
        grid-template-columns: 1fr;
        gap: 1.25rem;
        padding: 1.4rem 1.25rem;
    }
    .opac-campaign__aside { width: 100%; }
    .opac-campaign__title { font-size: 1.15rem; }
}

/* -- Card (member dashboard, visit page) --------------------- */
.opac-campaign-card {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin: 2rem 0;
    padding: 1.1rem 1.3rem;
    border: 1px solid rgba(217, 10, 44, .18);
    border-left: 4px solid var(--o-accent);
    border-radius: var(--o-radius-sm);
    background: rgba(217, 10, 44, .04);
}

/* 280px basis, not 0: below that the copy wraps to one word a
   line beside the 250px meter, so it takes the whole row first. */
.opac-campaign-card__text { flex: 1 1 280px; }

.opac-campaign-card__title {
    margin: 0 0 .2rem;
    font-size: 1rem;
    font-weight: 700;
    color: var(--o-text);
}

.opac-campaign-card__body {
    margin: 0;
    font-size: .87rem;
    line-height: 1.55;
    color: var(--o-text-soft);
}

.opac-campaign-card__cta {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    /* 44px of target on a phone without a 44px-tall link in the
       middle of a paragraph on desktop. */
    min-height: 44px;
    margin-top: .15rem;
    font-size: .88rem;
    font-weight: 700;
    color: var(--o-accent);
    text-decoration: none;
}
.opac-campaign-card__cta:hover {
    color: var(--o-accent-hover);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.opac-campaign-card__cta svg { flex: none; }

.opac-campaign-card__meter { flex: none; width: 300px; }

@media (max-width: 560px) {
    .opac-campaign-card { padding: 1rem 1.1rem; }
    .opac-campaign-card__meter { width: 100%; }
}


/* ================================================================
   VOLUNTEER STRIP
   A slim "Join our volunteer team" line at the top of the public
   footer (partials/volunteer_banner.php). Same surfaces as the
   footer around it, the red accent only on the icon and the link.
   ================================================================ */
.opac-body .vol-banner {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    margin-bottom: 2.25rem;
    padding: 0.85rem 1.1rem;
    background: var(--o-bg);
    border: 1px solid var(--o-border);
    border-radius: var(--o-radius);
    color: var(--o-text);
    text-decoration: none;
    transition: border-color 0.18s ease, background-color 0.18s ease;
}
.opac-body .vol-banner:hover {
    border-color: rgba(217, 10, 44, 0.35);
    background: var(--o-accent-soft);
    color: var(--o-text);
}

.opac-body .vol-banner__icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px; height: 36px;
    border-radius: 50%;
    background: var(--o-accent-soft);
    color: var(--o-accent);
}

.opac-body .vol-banner__text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0.6rem;
    row-gap: 0.1rem;
    font-size: 0.9rem;
    line-height: 1.45;
}
.opac-body .vol-banner__title { font-weight: 600; color: var(--o-text); }
.opac-body .vol-banner__body  { color: var(--o-muted); }

.opac-body .vol-banner__cta {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--o-accent);
    white-space: nowrap;
}
.opac-body .vol-banner:hover .vol-banner__cta svg { transform: translateX(2px); }
.opac-body .vol-banner__cta svg { transition: transform 0.18s ease; }

/* The footer centres everything on phones; the strip follows suit. */
@media (max-width: 760px) {
    .opac-body .vol-banner {
        flex-direction: column;
        gap: 0.5rem;
        padding: 1rem;
        text-align: center;
    }
    .opac-body .vol-banner__text { justify-content: center; flex-direction: column; align-items: center; }
    .opac-body .vol-banner__cta { min-height: 32px; }
}

@media (prefers-reduced-motion: reduce) {
    .opac-body .vol-banner__cta svg { transition: none; }
}
