/* The Canon — main.css. Filters-first single-column layout over the shared
   glass/token system in tokens.css, on top of the chrome in shell.css. Every
   colour is a token, a color-mix() over a token, or an accent-tinted rgba()
   glow (the one literal-colour exception).

   Medium is the organising axis here: the three --medium-* tokens colour the
   Medium chips in the rail and the badge on every card, so a mixed grid of
   films, anime and books stays readable at a glance. */

/* ── Layout shell ─────────────────────────────────────────────────────────── */
.container {
    max-width: 1440px;
    margin: 0 auto;
    padding: var(--space-3) var(--space-4) var(--space-8);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* ── Hero: the visual anchor, sat in its own air above the working chrome ──── */
.hero {
    position: relative;
    padding: var(--space-6) var(--space-3) var(--space-4);
    text-align: center;
}

/* Wide, soft cyan bloom behind the display type. Sits above the page gradient
   and below the text; nothing data-bearing is inside this region. Horizontal
   insets stay at 0 — a negative one widens the page and adds a horizontal
   scrollbar, since an absolutely positioned child still counts toward overflow. */
.hero::before {
    content: '';
    position: absolute;
    inset: -30% 0 -25%;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(58% 62% at 50% 45%, rgba(36, 224, 122, 0.17), transparent 72%);
}

.hero-title {
    font-size: clamp(2.2rem, 6vw, 4.2rem);
    font-weight: 700;
    line-height: 0.98;
    letter-spacing: -0.035em;
    margin-bottom: var(--space-2);
}

.hero-sub {
    color: var(--text-secondary);
    font-size: 1.05rem;
    line-height: 1.6;
    max-width: 62ch;
    margin: 0 auto var(--space-2);
}

.hero-count {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    color: var(--accent-primary);
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.hero-count strong {
    font-size: 1.3rem;
    font-weight: 700;
}

/* The three media, named in their own hues on the count line. Display only: the
   control that filters on them is the Medium popover. */
.hero-medium {
    font-weight: 700;
}

.hero-medium + .hero-medium::before {
    content: '·';
    color: var(--text-secondary);
    margin: 0 6px 0 2px;
}

.hero-medium[data-medium="film"] { color: var(--medium-film); }
.hero-medium[data-medium="anime"] { color: var(--medium-anime); }
.hero-medium[data-medium="book"] { color: var(--medium-book); }

/* ── Filter rail ──────────────────────────────────────────────────────────── */
/* The rail's backdrop-filter makes it a stacking context, so the similar-to
   dropdown on row two cannot escape it however high its own z-index. The rail
   is lifted above the panels that follow it and left below the popover layer
   (60) and the sticky top bar (80). */
.filter-rail {
    position: relative;
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-color: color-mix(in srgb, var(--accent-secondary) 35%, var(--panel-border));
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
    padding: var(--space-2);
}

/* Row one: the popover buttons, the match mode, discovery. Row two: the
   refinements, shown at rest so the rail states what it can do unopened. */
.rail-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.rail-row--refine {
    border-top: var(--border) solid var(--panel-border);
    padding-top: var(--space-2);
    gap: var(--space-3);
}

.rail-inline-field {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.rail-inline-field label {
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
}

.rail-inline-field select,
.rail-inline-field input[type="text"] {
    padding: 8px 12px;
    font-size: 0.85rem;
}

/* Grows into the space the two selects leave, but stops: it is the least-reached
   control on the rail and should not end up the widest thing in the panel. */
.rail-inline-field--grow {
    flex: 0 1 380px;
    min-width: 180px;
}

.rail-inline-field--grow .filter-autocomplete-wrapper {
    flex: 1;
}

.rail-inline-field--grow input[type="text"] {
    width: 100%;
}

/* Row two carries no badge, so the control itself has to show it is set. The
   violet stays on the chrome and the label; the value it holds is the thing
   being read, so it keeps full text contrast rather than the 4.7:1 the accent
   manages over its own dim fill. */
.rail-inline-field.is-set label {
    color: var(--accent-secondary);
}

.rail-inline-field.is-set select,
.rail-inline-field.is-set input[type="text"] {
    border-color: var(--accent-secondary);
    background: var(--accent-secondary-dim);
    color: var(--text-primary);
}

/* Match mode: each multi-valued category carries its own AND/OR rather than one
   global toggle governing all of them, so the control sits inside the popover it
   governs, on the same line as that group's label. Categories always AND with
   each other; this only decides how the picks *within* one of them combine. */
.filter-label {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-bottom: var(--space-1);
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
}

.logic-compact {
    display: inline-flex;
    gap: 3px;
    padding: 3px;
    background: var(--panel-fill-sunken);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-pill);
}

.logic-compact-btn {
    padding: 3px 12px;
    background: transparent;
    color: var(--text-secondary);
    border: none;
    border-radius: var(--radius-pill);
    font-size: 0.8rem;
    font-weight: 700;
    font-family: inherit;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: box-shadow var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

/* Segments in a joined control brighten in place rather than lifting; lifting one
   segment out of the group would break the object it belongs to. */
.logic-compact-btn:hover {
    background: var(--panel-fill-raised);
    color: var(--text-primary);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.logic-compact-btn:active {
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.45);
}

.logic-compact-btn.active {
    background: var(--accent-secondary);
    color: var(--text-on-accent);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 0 14px rgba(255, 138, 61, 0.32);
}

.rail-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-pill);
    padding: 10px 18px;
    font-size: 0.9rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.rail-btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--panel-lift-high);
    border-color: var(--panel-border-bright);
    color: var(--text-primary);
}

.rail-btn:active {
    transform: translateY(0) scale(0.98);
    box-shadow: var(--panel-lift);
}

.rail-btn.active,
.rail-btn[aria-expanded="true"] {
    border-color: var(--accent-secondary);
    color: var(--accent-secondary);
    background: var(--accent-secondary-dim);
    box-shadow: var(--panel-lift), 0 0 18px rgba(255, 138, 61, 0.22);
}

.rail-btn--discover {
    border-color: var(--accent-quaternary);
    color: var(--accent-quaternary);
}

/* Discovery is not part of the match control it now sits beside. Two spacing
   steps rather than one, so the row reads as filters, mode, then action. */
.rail-row--primary .rail-btn--discover {
    margin-left: var(--space-2);
}

.rail-btn--discover:hover {
    background: var(--accent-quaternary-dim);
    border-color: var(--accent-quaternary);
    color: var(--accent-quaternary);
    box-shadow: var(--panel-lift-high), 0 0 22px rgba(255, 95, 210, 0.35);
}

.rail-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-pill);
    background: var(--accent-secondary);
    color: var(--text-on-accent);
    font-size: 0.85rem;
    font-weight: 700;
}

.rail-caret {
    opacity: 0.6;
}

/* ── Popovers ─────────────────────────────────────────────────────────────── */
.popover-layer {
    position: relative;
    height: 0;
}

.filter-popover {
    position: absolute;
    top: 0;
    display: none;
    z-index: 60;
    min-width: 280px;
    max-width: min(440px, calc(100vw - 32px));
    max-height: min(70vh, 560px);
    overflow-y: auto;
    background: var(--panel-fill-raised);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift-high);
    padding: var(--space-3);
}

.filter-popover.open {
    display: block;
    animation: popover-in var(--motion-base) var(--ease-entrance);
}

@keyframes popover-in {
    from {
        opacity: 0;
        transform: translateY(-6px) scale(0.98);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.filter-popover--wide {
    min-width: 460px;
}

/* The Popular chip row takes height the genre grid used to have, which left the
   panel scrolling inside its own scrolling grid. The panel owns the height and
   the grid takes whatever is left, so there is exactly one scrollbar. */
#pop-genre {
    flex-direction: column;
    overflow: hidden;
}

#pop-genre.open {
    display: flex;
}

#pop-genre .popover-field:last-child {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

#pop-genre .genre-filter {
    flex: 1 1 auto;
    max-height: none;
    min-height: 120px;
}

.popover-title {
    color: var(--accent-secondary);
    font-size: 0.95rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: var(--space-2);
}

/* Themes is a search over 250 entries rather than a set of fields, so its input
   sits directly in the panel and has to take the full width itself. */
#pop-themes #themeSearch {
    width: 100%;
    margin-bottom: var(--space-2);
}

.popover-note {
    color: var(--text-secondary);
    font-size: 0.85rem;
    line-height: 1.5;
    margin-bottom: var(--space-2);
}

.popover-field {
    margin-bottom: var(--space-2);
}

.popover-field:last-child {
    margin-bottom: 0;
}

.popover-field label {
    display: block;
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.popover-field select,
.popover-field input[type="text"] {
    width: 100%;
}

.popover-field--pair .field-pair {
    display: flex;
    gap: var(--space-1);
}

.field-pair select {
    flex: 1;
}

.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.chip-btn {
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-pill);
    padding: 6px 14px;
    font-size: 0.85rem;
    font-family: inherit;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

.chip-btn:hover {
    transform: translateY(-2px);
    border-color: var(--panel-border-bright);
    color: var(--text-primary);
}

.chip-btn.active {
    background: var(--accent-secondary-dim);
    border-color: var(--accent-secondary);
    color: var(--accent-secondary);
}

/* Medium is the page's organising idea, so its chips carry their hue at rest
   rather than earning it on hover (a touch surface would otherwise never see
   it). Active fills the chip, which is the one place on the rail a chip goes
   solid: the cut the grid is under should be readable from across the room. */
.chip-btn--medium[data-medium="film"] {
    color: var(--medium-film);
    border-color: color-mix(in srgb, var(--medium-film) 45%, var(--panel-border));
}

.chip-btn--medium[data-medium="anime"] {
    color: var(--medium-anime);
    border-color: color-mix(in srgb, var(--medium-anime) 45%, var(--panel-border));
}

.chip-btn--medium[data-medium="book"] {
    color: var(--medium-book);
    border-color: color-mix(in srgb, var(--medium-book) 45%, var(--panel-border));
}

.chip-btn--medium .medium-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 7px;
    border-radius: 50%;
    background: currentColor;
}

.chip-btn--medium[data-medium="film"]:hover {
    color: var(--medium-film);
    border-color: var(--medium-film);
    background: color-mix(in srgb, var(--medium-film) 14%, transparent);
}

.chip-btn--medium[data-medium="anime"]:hover {
    color: var(--medium-anime);
    border-color: var(--medium-anime);
    background: color-mix(in srgb, var(--medium-anime) 14%, transparent);
}

.chip-btn--medium[data-medium="book"]:hover {
    color: var(--medium-book);
    border-color: var(--medium-book);
    background: color-mix(in srgb, var(--medium-book) 14%, transparent);
}

.chip-btn--medium.active[data-medium="film"] {
    background: var(--medium-film);
    border-color: var(--medium-film);
    color: var(--text-on-accent);
    box-shadow: 0 4px 14px rgba(255, 138, 61, 0.32);
}

.chip-btn--medium.active[data-medium="anime"] {
    background: var(--medium-anime);
    border-color: var(--medium-anime);
    color: var(--text-on-accent);
    box-shadow: 0 4px 14px rgba(255, 95, 210, 0.32);
}

.chip-btn--medium.active[data-medium="book"] {
    background: var(--medium-book);
    border-color: var(--medium-book);
    color: var(--text-on-accent);
    box-shadow: 0 4px 14px rgba(79, 195, 255, 0.32);
}

.medium-count {
    margin-left: 8px;
    font-variant-numeric: tabular-nums;
    opacity: 0.68;
}

/* The shut rail still says which way the grid is cut: with exactly one medium
   picked, the button wears that medium's hue instead of the rail's tangerine. */
.rail-btn[data-popover="pop-medium"][data-medium="film"] {
    border-color: var(--medium-film);
    color: var(--medium-film);
}

.rail-btn[data-popover="pop-medium"][data-medium="film"] .rail-badge {
    background: var(--medium-film);
}

.rail-btn[data-popover="pop-medium"][data-medium="anime"] {
    border-color: var(--medium-anime);
    color: var(--medium-anime);
}

.rail-btn[data-popover="pop-medium"][data-medium="anime"] .rail-badge {
    background: var(--medium-anime);
}

.rail-btn[data-popover="pop-medium"][data-medium="book"] {
    border-color: var(--medium-book);
    color: var(--medium-book);
}

.rail-btn[data-popover="pop-medium"][data-medium="book"] .rail-badge {
    background: var(--medium-book);
}

.rating-gloss {
    display: block;
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-top: 2px;
}

.filter-autocomplete-wrapper {
    position: relative;
}

.autocomplete-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 4px;
    /* Opaque, unlike the panels: this list now opens over the results bar, and
       the rail's own backdrop-filter caps the blur so anything behind it would
       otherwise read straight through the option text. Same colour a raised
       panel resolves to over the canvas, painted rather than composited. */
    background: linear-gradient(var(--panel-fill-raised), var(--panel-fill-raised)), var(--canvas);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-sm);
    max-height: 260px;
    overflow-y: auto;
    z-index: 200;
    display: none;
    box-shadow: var(--panel-lift-high);
}

.autocomplete-dropdown.open {
    display: block;
}

.autocomplete-item {
    padding: 9px 12px;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.9rem;
    border-bottom: var(--border) solid var(--panel-border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-shadow: inset 0 0 0 0 var(--accent-secondary);
    transition: background-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        padding-left var(--motion-hover) var(--ease-standard);
}

.autocomplete-item:last-child {
    border-bottom: none;
}

/* A list row cannot lift without disturbing the rows around it, so the hover
   payload here is an accent edge sliding in from the left. */
.autocomplete-item:hover,
.autocomplete-item.ac-highlighted {
    background: var(--accent-secondary-dim);
    color: var(--text-primary);
    box-shadow: inset 3px 0 0 0 var(--accent-secondary);
    padding-left: 16px;
}

.autocomplete-item em {
    color: var(--accent-secondary);
    font-style: normal;
    font-weight: 700;
}

/* ── Form elements ────────────────────────────────────────────────────────── */
select,
input[type="text"] {
    background: var(--panel-fill-sunken);
    color: var(--text-primary);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    font-size: 0.9rem;
    font-family: inherit;
    transition: border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

select:focus,
input[type="text"]:focus {
    border-color: var(--accent-primary);
}

/* The popup list is native chrome: `color-scheme: dark` in tokens.css is what
   stops the OS painting it white, and this keeps each row on the canvas black
   rather than the browser's own dark grey. */
select option {
    background: var(--canvas);
    color: var(--text-primary);
}

.genre-filter {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    background: var(--panel-fill-sunken);
    border-radius: var(--radius-sm);
    padding: var(--space-2);
    max-height: 260px;
    overflow-y: auto;
}

.genre-checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    background: var(--panel-fill-sunken);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
    cursor: pointer;
    font-size: 0.85rem;
    transition: transform var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.genre-checkbox:hover {
    transform: translateY(-2px);
    border-color: var(--panel-border-bright);
}

.genre-checkbox.selected {
    border-color: var(--accent-secondary);
    background: var(--accent-secondary-dim);
}

.genre-checkbox input {
    margin: 0;
    accent-color: var(--accent-secondary);
}

.genre-checkbox label {
    margin: 0;
    cursor: pointer;
    color: var(--text-primary);
    font-weight: normal;
}

/* ── Active filters ───────────────────────────────────────────────────────── */
.active-filters {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
}

.active-filters-label {
    color: var(--text-secondary);
    font-size: 0.85rem;
    white-space: nowrap;
}

.active-filters-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    flex: 1;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--accent-secondary-dim);
    color: var(--accent-secondary);
    border: var(--border) solid var(--accent-secondary);
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    font-size: 0.85rem;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

.filter-chip:hover {
    background: var(--accent-secondary);
    color: var(--text-on-accent);
    transform: translateY(-2px);
    box-shadow: var(--panel-lift-high);
}

.chip-remove {
    font-size: 1rem;
    line-height: 1;
    opacity: 0.7;
}

.filter-chip:hover .chip-remove {
    opacity: 1;
}

.clear-all-btn {
    background: transparent;
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 6px 16px;
    border-radius: var(--radius-pill);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 600;
    font-family: inherit;
    white-space: nowrap;
    transition: transform var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

.clear-all-btn:hover {
    border-color: var(--panel-border-bright);
    color: var(--text-primary);
    transform: translateY(-2px);
}

/* ── View controls ────────────────────────────────────────────────────────── */
.view-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
}

.controls-right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.sort-controls {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.sort-controls label {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.view-toggle {
    display: flex;
    gap: 4px;
    background: var(--panel-fill-sunken);
    padding: 4px;
    border-radius: var(--radius-sm);
    border: var(--border) solid var(--panel-border);
}

.view-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 12px;
    background: transparent;
    color: var(--text-secondary);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.view-btn:hover {
    color: var(--text-primary);
    background: var(--panel-fill-raised);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.view-btn:active {
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.45);
}

.view-btn.active {
    background: var(--accent-primary);
    color: var(--text-on-accent);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
        0 0 14px rgba(36, 224, 122, 0.3);
}

.view-btn svg {
    width: 18px;
    height: 18px;
}

.results-count {
    color: var(--accent-primary);
    font-size: 1rem;
    font-weight: 600;
}

/* ── Books grid / list ────────────────────────────────────────────────────── */
.books-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-3);
}

.books-grid.inactive {
    display: none;
}

.books-list {
    display: none;
    flex-direction: column;
    gap: var(--space-2);
}

.books-list.active {
    display: flex;
}

/* ── Book card ────────────────────────────────────────────────────────────── */
.book-card {
    position: relative;
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
    padding: var(--space-3);
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.book-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--panel-lift-high);
    border-color: var(--panel-border-bright);
    background: var(--panel-fill-raised);
}

.book-header {
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
    margin-bottom: var(--space-2);
}

.book-cover-container {
    position: relative;
    flex-shrink: 0;
    width: 80px;
    height: 120px;
}

.book-cover {
    display: block;
    width: 80px;
    height: 120px;
    overflow: hidden;
    border-radius: var(--radius-sm);
    background: var(--panel-fill-sunken);
    cursor: pointer;
    /* Carries text on a coverless card, and a decoration set on the anchor is
       painted across every descendant however they style themselves. */
    text-decoration: none;
    transition: transform var(--motion-hover) var(--ease-standard);
}

.book-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--radius-sm);
}

.book-cover:hover {
    transform: scale(1.03);
}

/* 38 books reach The Canon with no cover, and every image that does exist is
   hotlinked from a sibling site, so a rename upstream breaks one too. Both cases
   land here: a typographic tile on the same footprint as the cover, set in the
   medium's hue, which keeps the grid's rhythm instead of leaving a hole in it. */
.cover-tile {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 100%;
    height: 100%;
    padding: 8px 5px;
    border-radius: var(--radius-sm);
    background:
        linear-gradient(160deg, rgba(255, 255, 255, 0.05), transparent 62%),
        var(--panel-fill-sunken);
    border: var(--border) solid var(--panel-border);
    overflow: hidden;
}

.cover-tile-title {
    flex: 0 1 auto;
    min-height: 0;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
    text-decoration: none;
    /* break-word rather than anywhere: only split a word that cannot fit on a
       line of its own, and show a hyphen when doing it, so a title reads as
       broken type rather than as a rendering fault. */
    overflow-wrap: break-word;
    hyphens: auto;
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.cover-tile-creator {
    flex: 0 1 auto;
    min-height: 0;
    color: var(--text-secondary);
    font-size: 0.68rem;
    line-height: 1.25;
    text-decoration: none;
    overflow-wrap: break-word;
    hyphens: auto;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.cover-tile[data-medium="film"] {
    border-color: color-mix(in srgb, var(--medium-film) 32%, var(--panel-border));
}

.cover-tile[data-medium="anime"] {
    border-color: color-mix(in srgb, var(--medium-anime) 32%, var(--panel-border));
}

.cover-tile[data-medium="book"] {
    border-color: color-mix(in srgb, var(--medium-book) 32%, var(--panel-border));
}

.cover-tile[data-medium="film"] .cover-tile-title { color: var(--medium-film); }
.cover-tile[data-medium="anime"] .cover-tile-title { color: var(--medium-anime); }
.cover-tile[data-medium="book"] .cover-tile-title { color: var(--medium-book); }

/* List rows and the discovery sheet reuse the tile at their own footprints. */
.list-cover .cover-tile {
    width: 60px;
    height: 90px;
    padding: 6px;
    gap: 3px;
}

.list-cover .cover-tile-title {
    font-size: 0.68rem;
    -webkit-line-clamp: 4;
}

.list-cover .cover-tile-creator {
    font-size: 0.62rem;
    -webkit-line-clamp: 1;
}

.featured-cover-wrap .cover-tile {
    width: 110px;
    height: 165px;
    padding: 10px 11px;
}

.featured-cover-wrap .cover-tile-title {
    font-size: 0.88rem;
    -webkit-line-clamp: 5;
}

.page-count {
    position: absolute;
    bottom: -4px;
    right: -4px;
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    font-family: var(--font-mono);
}

.book-info {
    flex: 1;
    min-width: 0;
    overflow-wrap: break-word;
}

.book-title {
    display: block;
    color: var(--text-primary);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    margin-bottom: 4px;
    transition: color var(--motion-hover) var(--ease-standard);
}

.book-title:hover {
    color: var(--accent-primary);
}

.book-author {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin-bottom: var(--space-1);
}

.author-link {
    cursor: pointer;
}

.author-link:hover {
    color: var(--accent-primary);
    text-decoration: underline;
}

.badge-clickable {
    cursor: pointer;
    user-select: none;
}

.detail-badge.badge-clickable:hover {
    color: var(--accent-primary);
    border-color: var(--accent-primary);
    background: var(--accent-primary-dim);
    transform: translateY(-2px);
}

.list-meta-clickable:hover {
    color: var(--accent-primary);
    text-decoration: underline;
}

.rating-badge.badge-clickable {
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        filter var(--motion-hover) var(--ease-standard);
}

.rating-badge.badge-clickable:hover {
    transform: translateY(-2px);
    filter: brightness(1.12);
    box-shadow: 0 4px 14px rgba(245, 197, 24, 0.35);
}

.book-details {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}

.detail-badge {
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 3px 10px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    font-weight: 500;
    transition: color var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard);
}

.detail-badge.age-badge {
    color: var(--accent-tertiary);
    border-color: var(--accent-tertiary);
}

/* Medium badge. Every card carries one, at rest, in the medium's own hue: it is
   what keeps a grid of films, anime and books legible before a word of it is
   read. Outline plus a filled dot rather than a solid pill, so it identifies the
   card without outshouting the three stars beside it. */
.medium-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    font-size: 0.78rem;
    border: var(--border) solid currentColor;
    border-radius: var(--radius-pill);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.medium-badge::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.medium-badge[data-medium="film"] {
    color: var(--medium-film);
    background: color-mix(in srgb, var(--medium-film) 13%, transparent);
}

.medium-badge[data-medium="anime"] {
    color: var(--medium-anime);
    background: color-mix(in srgb, var(--medium-anime) 13%, transparent);
}

.medium-badge[data-medium="book"] {
    color: var(--medium-book);
    background: color-mix(in srgb, var(--medium-book) 13%, transparent);
}

/* ── Rating: the star scale ───────────────────────────────────────────────── */
/* The tier names are storage and never reach a reader. One <symbol id="star-mark">
   per page carries the path; starsHtml() in app.js is the only thing that writes
   the markup, always STAR_MAX marks wide with the unearned ones hollow, so one
   star and three stars are the same object at two fills rather than two objects
   of different widths. */
.svg-sprite {
    display: none;
}

.star-rating {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    color: var(--accent-curator);
    line-height: 0;
}

.star-rating .star {
    flex: none;
    width: 16px;
    height: 16px;
}

.star-rating .star--on {
    fill: currentColor;
    filter: drop-shadow(0 0 5px rgba(245, 197, 24, 0.5));
}

.star-rating .star--off {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    opacity: 0.4;
}

.star-rating--chip .star {
    width: 13px;
    height: 13px;
}

.rating-badge {
    display: inline-flex;
    align-items: center;
    padding: 4px 9px;
    border-radius: var(--radius-pill);
    background: var(--accent-curator-dim);
    border: var(--border) solid color-mix(in srgb, var(--accent-curator) 45%, transparent);
}

/* Three stars gets to shout: it is the smallest tier by a long way. */
.rating-badge:has(.star-rating[data-stars="3"]) {
    border-color: var(--accent-curator);
    box-shadow: 0 0 16px rgba(245, 197, 24, 0.4);
}

/* ── Genre tags / blurb ─────────────────────────────────── */
.genre-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}

.genre-tag {
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 3px 12px;
    border-radius: var(--radius-pill);
    font-size: 0.85rem;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.genre-tag:hover {
    color: var(--accent-tertiary);
    border-color: var(--accent-tertiary);
    background: var(--accent-tertiary-dim);
    transform: translateY(-2px);
    box-shadow: 0 4px 14px rgba(79, 195, 255, 0.28);
}

.genre-tag:active {
    transform: translateY(0) scale(0.97);
}

.genre-tag.active-subgenre {
    background: var(--accent-tertiary);
    color: var(--text-on-accent);
    font-weight: 600;
    border-color: var(--accent-tertiary);
}

.book-blurb {
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.6;
}

/* ── Recommendations ──────────────────────────────────────────────────────── */
.recommendations-section {
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: var(--border) solid var(--panel-border);
}

.recommendations-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-sm);
    padding: 10px 16px;
    font-size: 0.85rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

.recommendations-toggle:hover {
    border-color: var(--accent-quaternary);
    color: var(--accent-quaternary);
    background: var(--accent-quaternary-dim);
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgba(255, 95, 210, 0.25);
}

.recommendations-toggle:active {
    transform: translateY(0) scale(0.99);
}

.recommendations-toggle.expanded {
    background: var(--accent-quaternary-dim);
    border-color: var(--accent-quaternary);
    color: var(--accent-quaternary);
}

.toggle-arrow {
    transition: transform var(--motion-hover) var(--ease-standard);
}

.recommendations-toggle.expanded .toggle-arrow {
    transform: rotate(180deg);
}

.recommendations {
    margin-top: var(--space-2);
    background: var(--panel-fill-sunken);
    border-radius: var(--radius-sm);
    padding: var(--space-2);
    border: var(--border) solid var(--panel-border);
}

.recommendations.collapsed {
    display: none;
}

.recommendations-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.recommendation-item {
    background: var(--panel-fill);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    border: var(--border) solid var(--panel-border);
    border-left: 3px solid var(--accent-quaternary);
    transition: background-color var(--motion-hover) var(--ease-standard),
        border-left-width var(--motion-hover) var(--ease-standard),
        transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard);
}

.recommendation-item:hover {
    background: var(--panel-fill-raised);
    border-left-width: 6px;
    transform: translateX(3px);
    box-shadow: var(--panel-lift);
}

.recommendation-title {
    display: block;
    color: var(--text-primary);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 4px;
}

.recommendation-title:hover {
    color: var(--accent-quaternary);
}

.recommendation-author {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-bottom: 4px;
}

.recommendation-meta {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-bottom: 4px;
}

.recommendation-reason {
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-style: italic;
}

.view-all-similar {
    display: block;
    width: 100%;
    text-align: center;
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border: none;
    border-top: var(--border) solid var(--panel-border);
    background: none;
    color: var(--accent-quaternary);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    transition: color var(--motion-hover) var(--ease-standard),
        letter-spacing var(--motion-hover) var(--ease-standard),
        text-shadow var(--motion-hover) var(--ease-standard);
}

.view-all-similar:hover {
    text-decoration: underline;
    letter-spacing: 0.03em;
    text-shadow: 0 0 14px rgba(255, 95, 210, 0.6);
}

/* ── List view ────────────────────────────────────────────────────────────── */
.list-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
    padding: var(--space-2);
    transition: transform var(--motion-hover) var(--ease-standard),
        box-shadow var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard);
}

.list-item:hover {
    transform: translateY(-2px);
    box-shadow: var(--panel-lift-high);
    border-color: var(--panel-border-bright);
    background: var(--panel-fill-raised);
}

.list-cover {
    flex-shrink: 0;
}

.list-cover a,
.featured-cover-wrap a {
    display: block;
    text-decoration: none;
}

.list-cover img {
    width: 60px;
    height: 90px;
    object-fit: cover;
    border-radius: var(--radius-sm);
}

.list-info {
    flex: 1;
    min-width: 0;
}

.list-title {
    font-weight: 700;
    font-size: 1rem;
    margin-bottom: 4px;
}

.list-title a {
    color: var(--text-primary);
    text-decoration: none;
}

.list-title a:hover {
    color: var(--accent-primary);
}

.list-meta {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-bottom: var(--space-1);
}

.list-genres {
    margin-bottom: var(--space-1);
}

.list-blurb {
    color: var(--text-secondary);
    font-size: 0.85rem;
    line-height: 1.5;
}

/* ── Empty state ──────────────────────────────────────────────────────────── */
/* No working data to protect here, so this is where the atmosphere goes: a warm
   accent bloom behind a crafted icon, on the deepest glass on the page. */
.empty-state {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    overflow: hidden;
    padding: var(--space-8) var(--space-3);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--panel-lift), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.empty-state::before {
    content: '';
    position: absolute;
    inset: -40% 20% 40%;
    pointer-events: none;
    background: radial-gradient(50% 60% at 50% 60%, rgba(245, 197, 24, 0.16), transparent 70%);
}

.empty-icon {
    position: relative;
    margin-bottom: var(--space-3);
    filter: drop-shadow(0 6px 18px rgba(245, 197, 24, 0.4));
}

.empty-state h3 {
    position: relative;
    color: var(--text-primary);
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-bottom: var(--space-1);
}

.empty-state p {
    position: relative;
    color: var(--text-secondary);
    font-size: 0.95rem;
    max-width: 42ch;
    margin-bottom: var(--space-3);
}

.empty-state .btn {
    position: relative;
}

/* ── Loading state: skeleton cards, not a bare spinner ────────────────────── */
/* A skeleton shows the shape of what is coming (Doherty / Labor Illusion) and
   keeps the layout from jumping when the real cards land. */
.loading-state {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-3);
}

.skeleton-card {
    display: flex;
    gap: var(--space-2);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-md);
    box-shadow: var(--panel-lift);
    padding: var(--space-3);
}

.skeleton-cover {
    flex-shrink: 0;
    width: 80px;
    height: 120px;
    border-radius: var(--radius-sm);
}

.skeleton-lines {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: 4px;
}

.skeleton-line {
    height: 12px;
    border-radius: var(--radius-pill);
}

.skeleton-line.w-80 { width: 80%; }
.skeleton-line.w-55 { width: 55%; }
.skeleton-line.w-40 { width: 40%; }
.skeleton-line.w-95 { width: 95%; }

/* One shared sweep: a genuine "work in progress" indicator, so it is the
   permitted case for continuous motion. Reduced-motion flattens it to the base
   fill via the global rule in tokens.css. */
.skeleton-cover,
.skeleton-line {
    background: linear-gradient(
        100deg,
        var(--panel-fill-sunken) 30%,
        color-mix(in srgb, var(--accent-primary) 14%, var(--panel-fill-sunken)) 50%,
        var(--panel-fill-sunken) 70%
    );
    background-size: 300% 100%;
    animation: skeleton-sweep 1.6s var(--ease-standard) infinite;
}

@keyframes skeleton-sweep {
    from { background-position: 180% 0; }
    to   { background-position: -80% 0; }
}

@media (max-width: 768px) {
    .loading-state {
        grid-template-columns: 1fr;
    }
}

/* ── No-JS fallback ───────────────────────────────────────────────────────── */
.noscript-panel {
    max-width: 72ch;
    margin: var(--space-6) auto;
    padding: var(--space-4);
    background: var(--panel-fill);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--panel-lift);
    color: var(--text-secondary);
}

.noscript-panel h2 {
    color: var(--accent-primary);
    font-size: 1.6rem;
    letter-spacing: -0.02em;
    margin-bottom: var(--space-2);
}

.noscript-panel h3 {
    color: var(--accent-tertiary);
    font-size: 1.1rem;
    margin: var(--space-3) 0 var(--space-1);
}

.noscript-panel p {
    margin-bottom: var(--space-2);
}

.noscript-panel ul {
    padding-left: var(--space-3);
    line-height: 1.9;
}

.noscript-panel a {
    color: var(--accent-primary);
}

/* Error framed as a recoverable action rather than a dead end. */
.load-error {
    grid-column: 1 / -1;
    text-align: center;
    padding: var(--space-6) var(--space-3);
    color: var(--accent-quaternary);
    font-weight: 600;
}

/* ── Discovery sheet ──────────────────────────────────────────────────────── */
.discovery-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 1001;
}

.discovery-backdrop.mobile-open {
    display: block;
}

.discovery-sheet {
    display: none;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -46%) scale(0.98);
    width: min(480px, calc(100vw - 32px));
    max-height: min(80vh, 640px);
    overflow-y: auto;
    z-index: 1002;
    padding: var(--space-3);
    opacity: 0;
    background: var(--panel-fill-raised);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border) solid var(--accent-quaternary);
    border-radius: var(--radius-lg);
    box-shadow: var(--panel-lift-high);
    transition: opacity var(--motion-base) var(--ease-standard),
        transform var(--motion-base) var(--ease-entrance);
}

.discovery-sheet.mobile-open {
    display: block;
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.discovery-sheet-header {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}

.discovery-sheet-label {
    flex: 1;
    color: var(--accent-quaternary);
    font-weight: 700;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.discovery-sheet-close {
    flex-shrink: 0;
    padding: 4px;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    line-height: 0;
    transition: color var(--motion-hover) var(--ease-standard),
        transform var(--motion-hover) var(--ease-standard);
}

.discovery-sheet-close:hover {
    color: var(--text-primary);
    transform: scale(1.15) rotate(90deg);
}

.discovery-sheet-close:active {
    transform: scale(0.94) rotate(90deg);
}

.refresh-btn {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: transparent;
    border: var(--border) solid var(--accent-quaternary);
    color: var(--accent-quaternary);
    border-radius: 50%;
    cursor: pointer;
    transition: transform var(--motion-hover) var(--ease-standard),
        background-color var(--motion-hover) var(--ease-standard),
        color var(--motion-hover) var(--ease-standard);
}

/* The glyph here is a crafted colour icon rather than a currentColor outline, so
   hover lifts and blooms the surround instead of flooding the button with the
   accent (which would bury a pink icon in a pink fill). */
.refresh-btn:hover {
    background: var(--accent-quaternary-dim);
    transform: translateY(-2px) rotate(-25deg);
    box-shadow: var(--panel-lift), 0 0 20px rgba(255, 95, 210, 0.45);
}

.refresh-btn:active {
    transform: translateY(0) scale(0.94) rotate(-25deg);
}

.refresh-btn.spinning svg {
    animation: spin 0.5s ease;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* ── Featured book (discovery sheet content, rendered by renderFeaturedBook) ─ */
.featured-book-card {
    display: flex;
    gap: var(--space-2);
}

.featured-cover-wrap {
    flex-shrink: 0;
}

.featured-cover {
    width: 110px;
    height: auto;
    display: block;
    object-fit: contain;
    border-radius: var(--radius-sm);
    box-shadow: var(--panel-lift);
}

.featured-no-cover {
    width: 110px;
    height: 165px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--panel-fill-sunken);
    border: var(--border) solid var(--panel-border);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.featured-info {
    flex: 1;
    min-width: 0;
}

.featured-title {
    display: block;
    color: var(--text-primary);
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1.3;
    text-decoration: none;
    margin-bottom: 4px;
    transition: color var(--motion-hover) var(--ease-standard);
}

.featured-title:hover {
    color: var(--accent-quaternary);
}

.featured-author {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin-bottom: var(--space-1);
}

.featured-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-1);
}

.featured-badge {
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 3px 10px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    font-weight: 500;
    transition: color var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard);
}

.featured-badge.badge-clickable:hover {
    color: var(--accent-quaternary);
    border-color: var(--accent-quaternary);
}

.featured-genres {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-1);
}

.featured-genre {
    background: var(--panel-fill-sunken);
    color: var(--text-secondary);
    border: var(--border) solid var(--panel-border);
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    font-size: 0.85rem;
    cursor: pointer;
    transition: color var(--motion-hover) var(--ease-standard),
        border-color var(--motion-hover) var(--ease-standard);
}

.featured-genre:hover {
    color: var(--accent-quaternary);
    border-color: var(--accent-quaternary);
}

.featured-blurb {
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.5;
    margin-bottom: var(--space-2);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.featured-actions {
    display: flex;
    gap: var(--space-1);
}

/* ── Responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
    .books-grid {
        grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    }
}

@media (max-width: 768px) {
    .hero {
        padding: var(--space-4) var(--space-2) var(--space-3);
    }

    /* Only row one scrolls sideways. Row two wraps to full-width fields instead,
       because an overflow container would clip the similar-to dropdown. */
    .rail-row--primary {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        padding: 2px 0;
    }

    .rail-btn {
        scroll-snap-align: start;
        flex: 0 0 auto;
    }

    .rail-row--refine {
        flex-wrap: wrap;
        gap: var(--space-2);
    }

    .rail-inline-field {
        flex: 1 1 100%;
    }

    /* Stacked, each label sizes to its own text, so the four controls would
       start at four different x positions. One label column fixes that. */
    .rail-inline-field label {
        flex: 0 0 88px;
    }

    .rail-inline-field select,
    .rail-inline-field input[type="text"] {
        flex: 1;
    }

    /* --wide keeps its own min-width off the media query, so it has to be
       named here too or the wide panels sit 460px across a 390px viewport. */
    .filter-popover,
    .filter-popover--wide {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        min-width: 0;
        max-width: none;
        max-height: 80vh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }

    .view-controls {
        flex-direction: column;
        align-items: stretch;
    }

    .controls-right {
        justify-content: space-between;
    }

    .active-filters {
        flex-direction: column;
        align-items: flex-start;
    }

    .active-filters-list {
        width: 100%;
    }

    .clear-all-btn {
        width: 100%;
        text-align: center;
    }

    .books-grid {
        grid-template-columns: 1fr;
    }

    .book-header {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }

    .book-cover-container,
    .book-cover {
        width: 100px;
        height: 150px;
    }

    .book-details,
    .genre-tags {
        justify-content: center;
    }
}

@media (max-width: 480px) {
    .container {
        padding: var(--space-2);
    }

    .books-grid {
        grid-template-columns: 1fr;
    }
}

/* ── Touch fallback: region colour shown at rest, not gated on hover ────────── */
@media (hover: none) {
    .genre-tag {
        color: var(--accent-tertiary);
        border-color: var(--accent-tertiary);
        background: var(--accent-tertiary-dim);
    }

    .recommendations-toggle {
        border-color: var(--accent-quaternary);
        color: var(--accent-quaternary);
    }

    .detail-badge.badge-clickable {
        color: var(--accent-primary);
        border-color: color-mix(in srgb, var(--accent-primary) 55%, transparent);
    }

    .recommendation-item {
        border-left-width: 6px;
    }

    /* Cards cannot lift on hover here, so their edge carries the identity at rest. */
    .book-card,
    .list-item {
        border-color: color-mix(in srgb, var(--accent-primary) 18%, var(--panel-border));
    }
}

/* Utility: must win any display-property tie against a same-specificity component
   rule declared earlier in this file (e.g. .rail-badge), so it stays last. Elements
   that toggle visibility via inline style (not just this class) are unaffected —
   inline style already outranks any non-!important stylesheet rule regardless of
   position. */
.js-hidden {
    display: none;
}
