/* =====================================================
   book-reviews.css — Catalyst Magazine
   "The Stacks" — premium STEM book-review vertical.
   Built with Impeccable v3.0.6 + UI/UX Pro Max + Taste:
     • OKLCH-style tinted neutrals (no pure #000/#fff)
     • Slate monochrome with a single committed wine accent
       (gold is reserved for ai-expo per CLAUDE.md)
     • 44px+ touch targets, :focus-visible everywhere
     • prefers-reduced-motion fully honored
     • min-h-100dvh on hero to avoid iOS Safari jump
   ===================================================== */

body[data-page="book-reviews"] {
    --ink:          #0e1117;     /* slate-tinted near-black */
    --ink-deep:     #06080c;
    --ink-soft:     #181d28;
    --ink-line:     rgba(247,244,237,0.10);
    --paper:        #f7f4ed;     /* warm cream */
    --paper-off:    #efe9da;
    --paper-line:   #e2dccb;
    --text:         #1a1d24;
    --text-muted:   #4a4f5c;
    --text-subtle:  #7a808d;
    --accent:       #7a1f2b;     /* bookmark wine — the committed accent */
    --accent-soft:  #c4525e;
    --accent-deep:  #4a0f17;
    --on-dark-text: #efe9da;
    --on-dark-muted:rgba(239,233,218,0.62);
    --on-dark-sub:  rgba(239,233,218,0.35);

    background: var(--paper);
    color: var(--text);
    font-family: 'Inter', system-ui, sans-serif;
    overflow-x: hidden;
}

/* The shared site header sits on cream here; nudge its contrast pieces. */
body[data-page="book-reviews"] .header {
    background: rgba(247,244,237,0.85);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--paper-line);
}

/* =================================================================
   GLOBAL — Reveal-on-scroll (matches ai-expo pattern, retuned)
   ================================================================= */
.br-reveal {
    opacity: 0;
    transform: translateY(28px);
    transition:
        opacity .75s cubic-bezier(.16,1,.3,1),
        transform .75s cubic-bezier(.16,1,.3,1);
    will-change: transform, opacity;
}
.br-reveal.in { opacity: 1; transform: none; }
.br-d1 { transition-delay: .08s; }
.br-d2 { transition-delay: .18s; }
.br-d3 { transition-delay: .30s; }
.br-d4 { transition-delay: .44s; }

@media (prefers-reduced-motion: reduce) {
    .br-reveal { opacity: 1; transform: none; transition: none; }
    .br-orb, .br-marquee-track, .br-stack-book,
    .br-hero-glyph, .br-spine-spark { animation: none !important; }
    * { scroll-behavior: auto !important; }
}

/* =================================================================
   HERO — "The Stacks"
   ================================================================= */
.br-hero {
    position: relative;
    min-height: 100dvh;            /* iOS-safe (Taste rule) */
    display: flex;
    align-items: center;
    overflow: hidden;
    background: var(--ink);
    color: var(--on-dark-text);
    /* Top padding clears the fixed header (~80px) plus a small breathing
       gap; bottom keeps the section from feeling cramped at the marquee. */
    padding: 104px 0 96px;
    isolation: isolate;
}

/* Ambient orbs — slow drift, brand-tinted (no AI purple). */
.br-orb {
    position: absolute;
    border-radius: 50%;
    filter: blur(80px);
    opacity: .35;
    pointer-events: none;
    z-index: 0;
    animation: br-drift 22s ease-in-out infinite alternate;
}
.br-orb-1 { width: 520px; height: 520px; top: -120px;  left: -120px;
            background: radial-gradient(circle, rgba(122,31,43,.65), transparent 70%); }
.br-orb-2 { width: 460px; height: 460px; bottom: -140px; right: -100px;
            background: radial-gradient(circle, rgba(196,82,94,.45), transparent 70%);
            animation-duration: 28s; animation-direction: alternate-reverse; }
.br-orb-3 { width: 340px; height: 340px; top: 38%;  right: 22%;
            background: radial-gradient(circle, rgba(239,233,218,.18), transparent 70%);
            animation-duration: 34s; }
@keyframes br-drift {
    0%   { transform: translate(0,0) scale(1); }
    100% { transform: translate(40px, -30px) scale(1.06); }
}

/* Subtle marbled-paper noise overlay (premium feel, very subtle). */
.br-hero-grain {
    position: absolute; inset: 0;
    background-image:
        radial-gradient(circle at 20% 30%, rgba(239,233,218,.04) 0, transparent 1px),
        radial-gradient(circle at 70% 65%, rgba(239,233,218,.05) 0, transparent 1.5px),
        radial-gradient(circle at 45% 80%, rgba(239,233,218,.03) 0, transparent 1px);
    background-size: 6px 6px, 9px 9px, 11px 11px;
    opacity: .8;
    z-index: 1;
    pointer-events: none;
    mix-blend-mode: screen;
}

.br-hero-inner {
    position: relative;
    z-index: 2;
    width: 100%;
    max-width: 1320px;
    margin: 0 auto;
    padding: 0 32px;
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 72px;
    align-items: center;
}
@media (max-width: 960px) {
    .br-hero { padding: 88px 0 72px; }
    .br-hero-inner { grid-template-columns: 1fr; gap: 48px; padding: 0 24px; }
}

/* Editorial eyebrow with bracket lines (matches ai-expo aesthetic). */
.br-hero-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    font-family: 'Inter', sans-serif;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .28em;
    text-transform: uppercase;
    color: var(--accent-soft);
    margin-bottom: 28px;
}
.br-hero-eyebrow::before,
.br-hero-eyebrow::after {
    content: '';
    height: 1px; width: 36px;
    background: linear-gradient(90deg, transparent, var(--accent-soft), transparent);
}

.br-hero-title {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 700;
    /* Reduced from clamp(48, 7.4vw, 110) — the previous setting peaked at
       110px on desktop which felt aggressive next to the book stack. The
       new ceiling of 84px keeps the editorial weight without shouting. */
    font-size: clamp(40px, 5.8vw, 84px);
    line-height: 0.98;
    letter-spacing: -0.02em;
    color: var(--on-dark-text);
    margin: 0 0 24px;
}
.br-hero-title em {
    font-style: italic;
    font-weight: 500;
    color: var(--accent-soft);
    display: inline-block;
    padding-right: 0.04em;
}

.br-hero-kicker {
    max-width: 56ch;
    font-size: clamp(15px, 1.1vw, 17.5px);
    line-height: 1.7;
    color: var(--on-dark-muted);
    margin: 0 0 36px;
}

.br-hero-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 28px 40px;
    border-top: 1px solid var(--ink-line);
    padding-top: 28px;
    margin-top: 8px;
}
.br-hero-meta-item .br-hero-meta-label {
    font-size: 11px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--on-dark-sub);
    margin-bottom: 6px;
}
.br-hero-meta-item .br-hero-meta-value {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 22px;
    color: var(--on-dark-text);
}

/* ---- Hero stack visual (three tilted "books") ----
   Scroll-spread: as the user scrolls the hero, JS sets
   --br-spread (0 → 1) on .br-hero-stack. At 0 the books
   are stacked close together; at 1 they fan outward and
   scale up dramatically (the "blow up" effect).
   Each book also has a subtle idle float, applied via a
   nested wrapper so the spread + float multiply cleanly. */
.br-hero-stack {
    position: relative;
    aspect-ratio: 4 / 5;
    width: 100%;
    max-width: 520px;
    margin-left: auto;
    /* Sit just below the floating header so the top book doesn't get clipped
       by the nav bar. The negative margin used to be -56px (pulled the stack
       under the header); now we let it sit at the natural flex-centered
       position with a small positive offset on top. */
    margin-top: 32px;
    perspective: 1600px;
    --br-spread: 0;            /* updated by JS on scroll */
    --br-glow: 0;              /* updated by JS on scroll */
    --br-orbit: 0deg;          /* updated by JS on scroll */
    --br-orbit-reverse: 0deg;  /* updated by JS on scroll */
    --br-tilt-x: 0deg;         /* updated by JS from pointer/scroll */
    --br-tilt-y: 0deg;         /* updated by JS from pointer/scroll */
    --br-scan-x: -70%;         /* updated by JS on scroll */
    isolation: isolate;
    transform-style: preserve-3d;
    transform: rotateX(var(--br-tilt-x)) rotateY(var(--br-tilt-y));
    transition: transform .16s linear;
    will-change: transform;
}
.br-hero-stack::before,
.br-hero-stack::after {
    content: '';
    position: absolute;
    inset: -10%;
    border-radius: 24px;
    pointer-events: none;
    transform-style: preserve-3d;
}
.br-hero-stack::before {
    z-index: -2;
    background:
        linear-gradient(90deg, rgb(239 233 218 / .08) 1px, transparent 1px),
        linear-gradient(0deg, rgb(239 233 218 / .06) 1px, transparent 1px);
    background-size: 42px 42px;
    opacity: calc(.08 + var(--br-glow) * .2);
    transform: translateZ(-120px) rotate(var(--br-orbit)) scale(calc(.92 + var(--br-spread) * .08));
    -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 0 42%, transparent 73%);
    mask-image: radial-gradient(circle at 50% 50%, #000 0 42%, transparent 73%);
}
.br-hero-stack::after {
    z-index: -1;
    inset: -18%;
    background:
        conic-gradient(
            from var(--br-orbit),
            transparent 0deg,
            rgb(239 233 218 / .16) 38deg,
            rgb(196 82 94 / .2) 74deg,
            transparent 118deg,
            transparent 360deg
        );
    filter: blur(20px);
    opacity: calc(.1 + var(--br-glow) * .35);
    transform: translateZ(-80px) rotate(var(--br-orbit-reverse)) scale(calc(.92 + var(--br-spread) * .12));
}
.br-stack-book {
    position: absolute;
    /* Lock every slot to the same ~2:3 ratio (100:145 ≈ 0.69, matching the
       average of the three cover scans) so all three books share identical
       proportions and the placeholder is exactly the same shape as the image
       that fills it. Per-book size + anchor are set on .br-stack-book-N
       below using width/top/left. */
    aspect-ratio: 100 / 145;
    border-radius: 4px;
    box-shadow:
        0 30px 60px -20px rgba(0,0,0,.55),
        0 0 0 1px rgba(239,233,218,.06) inset;
    overflow: hidden;
    /* Outer transform: spread + scale driven by scroll progress.
       Inner ::before/::after stay aligned because we wrap the
       float on the host element itself with calc() values. */
    transform:
        translate3d(
            calc(var(--br-spread) * var(--tx, 0px)),
            calc(var(--br-spread) * var(--ty, 0px)),
            calc(var(--br-spread) * var(--tz, 0px))
        )
        rotateX(calc(var(--br-spread) * var(--rx, 0deg)))
        rotateY(calc(var(--br-spread) * var(--ry, 0deg)))
        rotateZ(calc(var(--r, 0deg) + var(--br-spread) * var(--rs, 0deg)))
        scale(calc(1 + var(--br-spread) * var(--sc, 0.25)));
    transform-origin: center center;
    transform-style: preserve-3d;
    filter:
        saturate(calc(1 + var(--br-glow) * .18))
        contrast(calc(1 + var(--br-glow) * .08));
    transition: box-shadow .4s ease, filter .4s ease, background-color .35s ease;
    will-change: transform, filter;
}
/* Once the cover image has loaded, drop the tinted placeholder gradient on
   the parent so there's no halo of fake-book color peeking around the real
   artwork. The transition above gives the swap a soft handoff. */
.br-stack-book[data-loaded="true"] {
    background: transparent !important;
}
.br-hero-stack[data-spread="1"] .br-stack-book {
    box-shadow:
        0 60px 120px -20px rgba(0,0,0,.7),
        0 24px 48px -26px rgba(196,82,94,.65),
        0 0 0 1px rgba(239,233,218,.10) inset;
}
.br-stack-book::before {
    /* spine highlight + gloss sweep + scanline. Sits ABOVE the cover image
       (z-index: 2) so the parallax glints still read on the real artwork. */
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    background:
        linear-gradient(90deg, rgba(0,0,0,.42) 0 10px, rgba(255,255,255,.06) 11px, transparent 36px),
        linear-gradient(115deg, transparent 0 34%, rgba(255,255,255,.14) 46%, transparent 58%),
        repeating-linear-gradient(0deg, transparent 0 11px, rgb(239 233 218 / .035) 12px, transparent 13px);
    background-size: auto, 220% 100%, auto;
    background-position: 0 0, var(--br-scan-x) 0, 0 0;
    opacity: calc(.55 + var(--br-glow) * .3);
    mix-blend-mode: screen;
    pointer-events: none;
}

/* Cover artwork. The img sits over the gradient placeholder; when it
   finishes loading we add .is-loaded which fades it in AND we set
   data-loaded="true" on the parent so the gradient gets cleared (see
   the .br-stack-book[data-loaded] rule above). On slow connections /
   image errors, the placeholder stays put indefinitely — graceful
   degradation for low-bandwidth users. */
.br-stack-book-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* The parent is locked to 4:5 (same as the WebP), so neither cover nor
       contain is needed — `fill` paints corner-to-corner with no crop and
       no letterbox. Defensive object-fit: cover stays as a fallback in case
       a future cover ships at a slightly different ratio. */
    object-fit: cover;
    object-position: center;
    z-index: 1;
    opacity: 0;
    transition: opacity .6s cubic-bezier(.16, 1, .3, 1);
    /* Hint at GPU compositing — same layer the parent already lives on
       thanks to transform-style: preserve-3d above. */
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    /* Slight contrast bump to match the dramatic shadow stack on the parent. */
    filter: saturate(1.04) contrast(1.02);
}
.br-stack-book-img.is-loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
    .br-stack-book-img { transition: none; }
}

/* Per-book base position, rest rotation, and spread vector.
   Each slot is sized by `width` only — `aspect-ratio: 4 / 5` on the
   base class gives the height automatically so the slot is always the
   same shape as the cover image inside it (no halo of gradient). top/left
   anchor the slot inside the .br-hero-stack box; the rest stays the same.
   --tx/--ty/--tz: how far it travels when fully blown up.
   --rs:           extra rotation added at full spread.
   --sc:           extra scale added at full spread (0.25 = +25%).
   The background gradients are tinted to the dominant tone of each cover
   so the load-in transition reads as "ghost → real art", and they get
   cleared once data-loaded="true" lands on the slot. */
/* All three slots share the same WIDTH (and therefore — because of the
   aspect-ratio rule on .br-stack-book — the same HEIGHT). Only the top/left
   anchor + base rotation differ, so the books look like three identical
   editions stacked at different angles instead of three differently-sized
   props. */
.br-stack-book-1 {
    /* Back of the stack — upper-left, tilted left. */
    width: 62%;
    top: 0%;
    left: 6%;
    background: linear-gradient(155deg, #0f1a36 0%, #1e3270 55%, #0a142a 100%);
    --r: -7deg;
    --tx: -120px; --ty: -60px; --tz: 80px;
    --rs: -10deg; --rx: 7deg; --ry: -18deg; --sc: .32;
}
.br-stack-book-2 {
    /* Front of the stack — lower-center, cream cover leads the eye. */
    width: 62%;
    top: 22%;
    left: 18%;
    background: linear-gradient(155deg, #ece4d2 0%, #d8cdb3 55%, #b6a98a 100%);
    --r: -2deg;
    --tx: 30px; --ty: 130px; --tz: 110px;
    --rs: -6deg; --rx: 12deg; --ry: 7deg; --sc: .36;
    z-index: 3;
}
.br-stack-book-3 {
    /* Middle of the stack — pushed further right so a clear band of the
       green cover sticks out past the cream book in front of it. */
    width: 62%;
    top: 6%;
    left: 48%;
    background: linear-gradient(155deg, #142a1f 0%, #1f4233 55%, #0a1b13 100%);
    --r: 4deg;
    --tx: 130px; --ty: -90px; --tz: 60px;
    --rs: 14deg; --rx: -5deg; --ry: 15deg; --sc: .28;
    z-index: 2;
}
.br-stack-book-1 { z-index: 1; }

@media (max-width: 960px) {
    .br-hero-stack { max-width: 360px; margin: 0 auto; }
    /* Smaller travel on mobile so the books don't leave the viewport */
    .br-stack-book-1 { --tx: -70px;  --ty: -40px; --tz: 40px; --sc: .22; }
    .br-stack-book-2 { --tx: 60px;   --ty: -55px; --tz: 30px; --sc: .20; }
    .br-stack-book-3 { --tx: 20px;   --ty: 80px;  --tz: 60px; --sc: .26; }
    /* Pull book-3 back in a bit so it doesn't bleed off the right side of
       the narrower mobile stack while still peeking out behind the cream
       cover. */
    .br-stack-book-3 { left: 42%; }
}

@media (prefers-reduced-motion: reduce) {
    /* Honor user preference: skip the scroll-spread entirely. */
    .br-hero-stack { transform: none; }
    .br-hero-stack::before,
    .br-hero-stack::after { display: none; }
    .br-stack-book { transform: rotate(var(--r, 0deg)); }
}

/* =================================================================
   SECTION SCAFFOLDING
   ================================================================= */
.br-section { padding: 100px 0; position: relative; }
.br-container { max-width: 1320px; margin: 0 auto; padding: 0 32px; }
@media (max-width: 720px) {
    .br-section { padding: 72px 0; }
    .br-container { padding: 0 22px; }
}
.br-section-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-size: 11px;
    letter-spacing: .28em;
    text-transform: uppercase;
    color: var(--accent);
    font-weight: 600;
    margin-bottom: 18px;
}
.br-section-eyebrow::before {
    content: '';
    width: 28px; height: 1px;
    background: var(--accent);
}
.br-section-title {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 600;
    font-size: clamp(34px, 4.4vw, 60px);
    line-height: 1.04;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0 0 18px;
}
.br-section-title em { font-style: italic; color: var(--accent); }
.br-section-lede {
    max-width: 60ch;
    font-size: 17px;
    line-height: 1.7;
    color: var(--text-muted);
    margin: 0 0 48px;
}

/* =================================================================
   FEATURED REVIEW — split-screen spotlight
   ================================================================= */
.br-featured {
    background: var(--paper);
    border-top: 1px solid var(--paper-line);
    border-bottom: 1px solid var(--paper-line);
}
.br-featured-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: 80px;
    align-items: center;
}
@media (max-width: 960px) {
    .br-featured-grid { grid-template-columns: 1fr; gap: 48px; }
}
.br-featured-cover {
    position: relative;
    /* Slightly taller than 3:4 (closer to typical hardback proportions)
       so paperback scans don't show top/bottom padding. */
    aspect-ratio: 2 / 3;
    border-radius: 6px;
    overflow: hidden;
    /* Paper-tinted backing so any letterbox bars from a non-2:3 cover
       image (square paperback scan, wide hardcover) blend into the page
       instead of showing as black bars around the book. */
    background: var(--paper);
    box-shadow:
        0 40px 60px -20px rgba(14,17,23,.32),
        0 0 0 1px var(--paper-line);
    transform: rotate(-2.4deg);
    transition: transform .8s cubic-bezier(.16,1,.3,1);
}
.br-featured-cover:hover { transform: rotate(0) scale(1.015); }
.br-featured-cover img {
    width: 100%; height: 100%;
    /* contain (not cover) so the WHOLE book jacket is visible — never
       crops title or spine. */
    object-fit: contain;
    display: block;
    image-rendering: -webkit-optimize-contrast;
}
/* Spine shadow only makes sense when the cover fills the frame
   (object-fit: cover). With contain we drop it to avoid the
   shadow floating over empty background. */
.br-featured-cover::after { display: none; }
.br-featured-body {
    padding-right: 8px;
}
.br-featured-tag {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: rgba(122,31,43,.08);
    border: 1px solid rgba(122,31,43,.18);
    color: var(--accent);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    padding: 8px 14px;
    border-radius: 999px;
    margin-bottom: 24px;
}
.br-featured-title {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 700;
    font-size: clamp(34px, 4.6vw, 56px);
    line-height: 1.04;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0 0 14px;
}
.br-featured-author {
    font-style: italic;
    font-size: 18px;
    color: var(--text-muted);
    margin: 0 0 24px;
}
.br-featured-dek {
    font-size: 18px;
    line-height: 1.7;
    color: var(--text);
    margin: 0 0 32px;
    max-width: 56ch;
}
.br-featured-byline {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-top: 24px;
    border-top: 1px solid var(--paper-line);
    margin-bottom: 32px;
}
.br-featured-byline strong {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
}
.br-featured-byline span {
    font-size: 13px;
    color: var(--text-subtle);
}

/* Rating dial */
.br-rating {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-bottom: 36px;
}
.br-rating-dial {
    position: relative;
    width: 76px; height: 76px;
    border-radius: 50%;
    background: conic-gradient(var(--accent) calc(var(--score,0) * 1%), var(--paper-line) 0);
}
.br-rating-dial::before {
    content: '';
    position: absolute; inset: 6px;
    border-radius: 50%;
    background: var(--paper);
}
.br-rating-dial-value {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -55%);
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 26px;
    font-weight: 700;
    line-height: 1;
    color: var(--ink);
    z-index: 1;
    white-space: nowrap;
}
.br-rating-label {
    font-size: 12px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--accent);
    font-weight: 600;
}

.br-featured-cta {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: var(--ink);
    color: var(--on-dark-text);
    padding: 16px 28px;
    border-radius: 999px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: .04em;
    text-decoration: none;
    transition: transform .25s ease, box-shadow .25s ease, background .25s ease;
    min-height: 48px;       /* ≥44px touch target (Pro Max P2) */
}
.br-featured-cta:hover {
    background: var(--accent);
    transform: translateY(-2px);
    box-shadow: 0 16px 32px -12px rgba(122,31,43,.5);
}
.br-featured-cta svg { transition: transform .25s ease; }
.br-featured-cta:hover svg { transform: translateX(4px); }
.br-featured-cta:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* =================================================================
   MARQUEE — running titles ticker
   ================================================================= */
.br-marquee {
    background: var(--ink);
    color: var(--on-dark-text);
    padding: 14px 0;
    overflow: hidden;
    border-top: 1px solid var(--ink-line);
    border-bottom: 1px solid var(--ink-line);
    position: relative;
}
.br-marquee::before,
.br-marquee::after {
    content: '';
    position: absolute; top: 0; bottom: 0; width: 100px;
    z-index: 2; pointer-events: none;
}
.br-marquee::before { left: 0;  background: linear-gradient(90deg, var(--ink), transparent); }
.br-marquee::after  { right: 0; background: linear-gradient(270deg, var(--ink), transparent); }
.br-marquee-track {
    display: flex;
    gap: 44px;
    width: max-content;
    animation: br-marquee 42s linear infinite;
}
.br-marquee:hover .br-marquee-track { animation-play-state: paused; }
@keyframes br-marquee {
    0%   { transform: translateX(0); }
    100% { transform: translateX(-50%); }
}
.br-marquee-item {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    font-family: 'Playfair Display', Georgia, serif;
    font-style: italic;
    font-size: clamp(15px, 1.3vw, 19px);
    color: var(--on-dark-text);
    white-space: nowrap;
    line-height: 1;
}
.br-marquee-item::after {
    content: '';
    width: 4px; height: 4px;
    border-radius: 50%;
    background: var(--accent-soft);
    opacity: .7;
}

/* =================================================================
   FILTER RAIL — search + discipline dropdown
   Reuses the .br-community-search + .br-community-filter primitives
   defined further down so the two toolbars stay visually identical.
   ================================================================= */
.br-rail-wrap {
    position: relative;
    z-index: 80;
    background: rgba(247,244,237,.92);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--paper-line);
    padding: 18px 0;
}
.br-rail {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    align-items: stretch;
}
.br-rail-search { width: 100%; min-width: 0; }
.br-rail-filter { flex: 0 0 auto; z-index: 90; }
.br-rail-filter[data-open="true"] { z-index: 240; }

@media (max-width: 560px) {
    .br-rail { grid-template-columns: 1fr; }
}

/* =================================================================
   REVIEWS GRID — asymmetric "spine" cards
   ================================================================= */
.br-feed {
    padding-top: 64px;
}
.br-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 36px 28px;
    align-items: stretch;
}
.br-card {
    grid-column: span 4;
    position: relative;
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
    height: 100%;
    transition: transform .5s cubic-bezier(.16,1,.3,1);
    opacity: 0;
    transform: translateY(20px);
}
.br-card.in-view { opacity: 1; transform: none; }
.br-card.wide { grid-column: span 6; }
.br-card:hover { transform: translateY(-6px); }
.br-card:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
    border-radius: 8px;
}
@media (max-width: 960px) {
    .br-grid { grid-template-columns: repeat(6, 1fr); }
    .br-card, .br-card.wide { grid-column: span 6; }
}

.br-card-media {
    position: relative;
    /* Book-jacket proportion: ~2:3. Paired with object-fit: contain on
       the <img> below means the whole cover is always visible — never
       cropped through the title or spine. */
    aspect-ratio: 2 / 3;
    border-radius: 4px;
    overflow: hidden;
    background:
        radial-gradient(circle at 50% 30%, rgba(239,233,218,.05), transparent 60%),
        var(--ink-soft);
    box-shadow:
        0 20px 40px -16px rgba(14,17,23,.32),
        0 0 0 1px rgba(14,17,23,.06);
    margin-bottom: 24px;
}
/* "Wide" variant — used for the asymmetric large tiles. Still keep the
   whole cover visible, just within a wider frame. */
.br-card.wide .br-card-media { aspect-ratio: 4 / 5; }

.br-card-media img {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: contain;
    transition: transform .8s cubic-bezier(.16,1,.3,1), opacity .4s ease;
    opacity: 0;
    image-rendering: -webkit-optimize-contrast;
}
.br-card-media img.loaded { opacity: 1; }
.br-card:hover .br-card-media img { transform: scale(1.04); }
/* Spine edge shadow only applies cleanly when the cover fills the
   frame edge-to-edge (object-fit: cover). With contain, the shadow
   could float over empty paper-tone background, so we omit it. The
   box-shadow on .br-card-media still gives the elevated-book feel. */
.br-card-media::after { display: none; }
.br-card.wide .br-card-media::after { display: none; }

.br-card-rating {
    background: var(--paper-off);
    color: var(--accent);
    border: 1px solid var(--paper-line);
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 16px;
    font-weight: 700;
    padding: 5px 9px;
    border-radius: 999px;
    line-height: 1;
    display: inline-flex; align-items: baseline; gap: 2px;
}
.br-card-rating small {
    font-size: 10px;
    opacity: .7;
    font-weight: 400;
    margin-left: 2px;
}
.br-card-genre {
    position: absolute;
    bottom: 14px; left: 14px;
    background: var(--paper);
    color: var(--ink);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .2em;
    text-transform: uppercase;
    padding: 6px 10px;
    border-radius: 999px;
}

.br-card-body {
    padding-right: 8px;
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
}
.br-card-kicker {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
}
.br-card-book {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 600;
    font-size: 22px;
    line-height: 1.18;
    letter-spacing: -.01em;
    color: var(--ink);
    margin: 0 0 6px;
    transition: color .25s ease;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.br-card:hover .br-card-book { color: var(--accent); }
.br-card-author {
    font-style: italic;
    font-size: 14px;
    color: var(--text-muted);
    margin: 0 0 14px;
}
.br-card-blurb {
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--text);
    margin: 0 0 18px;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.br-card-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 12px;
    color: var(--text-subtle);
    padding-top: 14px;
    margin-top: auto;
    border-top: 1px solid var(--paper-line);
}
.br-card-meta strong {
    font-weight: 600;
    color: var(--ink);
}
.br-card-meta .br-dot {
    width: 3px; height: 3px;
    border-radius: 50%;
    background: var(--text-subtle);
    display: inline-block;
}

/* Skeleton */
.br-card.skeleton .br-card-media { background: var(--paper-off); }
.br-card.skeleton .br-card-media::before {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
    animation: br-shimmer 1.6s ease-in-out infinite;
}
.br-sk-bar {
    height: 14px;
    background: var(--paper-off);
    border-radius: 4px;
    margin-bottom: 10px;
    position: relative;
    overflow: hidden;
}
.br-sk-bar::before {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.7), transparent);
    animation: br-shimmer 1.6s ease-in-out infinite;
}
.br-sk-bar.title { height: 24px; width: 80%; }
.br-sk-bar.short { width: 55%; }
@keyframes br-shimmer {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
}

/* Empty state */
.br-empty {
    grid-column: 1 / -1;
    text-align: center;
    padding: 80px 24px;
    color: var(--text-muted);
}
.br-empty-icon {
    width: 64px; height: 64px;
    margin: 0 auto 20px;
    color: var(--accent);
    opacity: .7;
}
.br-empty h3 {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 26px;
    color: var(--ink);
    margin: 0 0 10px;
}

/* Load more */
.br-loadmore-wrap {
    margin-top: 56px;
    display: flex;
    justify-content: center;
}
.br-loadmore {
    appearance: none;
    background: transparent;
    border: 1px solid var(--ink);
    color: var(--ink);
    padding: 16px 32px;
    border-radius: 999px;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: .04em;
    cursor: pointer;
    min-height: 48px;
    transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.br-loadmore:hover {
    background: var(--ink);
    color: var(--on-dark-text);
}
.br-loadmore:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* =================================================================
   PITCH — call for writers
   ================================================================= */
.br-pitch {
    background: var(--ink);
    color: var(--on-dark-text);
    text-align: center;
}
.br-pitch .br-section-title { color: var(--on-dark-text); }
.br-pitch .br-section-lede { color: var(--on-dark-muted); margin: 0 auto 36px; }
.br-pitch-cta {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: var(--accent);
    color: var(--on-dark-text);
    padding: 18px 32px;
    border-radius: 999px;
    text-decoration: none;
    font-weight: 600;
    font-size: 15px;
    letter-spacing: .04em;
    min-height: 48px;
    transition: transform .25s ease, box-shadow .25s ease, background .25s ease;
}
.br-pitch-cta:hover {
    background: var(--accent-soft);
    color: var(--ink);
    transform: translateY(-2px);
    box-shadow: 0 18px 36px -12px rgba(196,82,94,.45);
}
.br-pitch-cta:focus-visible {
    outline: 2px solid var(--accent-soft);
    outline-offset: 3px;
}

/* =================================================================
   COMMUNITY SECTION — "From the Catalyzers"
   Sits below the writer reviews; visually distinct (cream-on-cream
   with a subtle band) so readers know it's reader-submitted.
   ================================================================= */
.br-community {
    background: var(--paper-off);
    border-top: 1px solid var(--paper-line);
    border-bottom: 1px solid var(--paper-line);
    position: relative;
    overflow: visible;
}
.br-community .br-section-eyebrow { color: var(--accent); }
.br-community .br-section-title em { color: var(--accent); }

.br-community-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(230px, 310px);
    gap: 32px;
    align-items: center;
    margin-bottom: 42px;
}
@media (max-width: 960px) {
    .br-community-head { grid-template-columns: 1fr; gap: 32px; }
}

/* Lockup: stamp badge + lede. The stamp is a deliberate editorial mark —
   feels like a stamp on a postcard or a wax seal on a letter. */
.br-community-lockup {
    display: grid;
    grid-template-columns: 116px minmax(0, 1fr);
    gap: 30px;
    align-items: center;
}
.br-community-copy {
    min-width: 0;
}
.br-community-copy .br-section-title {
    white-space: nowrap;
    font-size: clamp(38px, 3.35vw, 54px);
    margin-bottom: 18px;
}
.br-community-lede {
    max-width: 68ch;
    margin: 0;
}
/* Mobile lockup — stack vertically with the stamp centered above the
   headline + lede so the whole block reads as a single editorial unit.
   Centering everything (eyebrow, title, lede) gives the reader-picks
   section a real "stamp at the top, message below" feel on phones. */
@media (max-width: 720px) {
    .br-community-lockup {
        grid-template-columns: 1fr;
        gap: 16px;
        justify-items: center;
        text-align: center;
    }
    .br-community-copy { text-align: center; }
    /* Eyebrow has an `::before` hairline; convert from inline-flex to
       a centered flex line so the hairline + text both center. */
    .br-community-copy .br-section-eyebrow {
        justify-content: center;
        letter-spacing: .22em;
    }
    .br-community-copy .br-section-title {
        white-space: normal;
        font-size: clamp(26px, 8.4vw, 40px);
        word-break: break-word;
        hyphens: auto;
        margin-left: auto;
        margin-right: auto;
    }
    .br-community-lede {
        max-width: 56ch;
        margin-left: auto;
        margin-right: auto;
    }
    /* Aside centers too — CTA + stats stack vertically below the lede. */
    .br-community-aside {
        justify-self: center;
        margin-left: auto;
        margin-right: auto;
    }
}
/* Very narrow phones — trim the eyebrow tracking + leading hairline so
   the line doesn't wrap onto two lines on iPhone-mini sizes. */
@media (max-width: 420px) {
    .br-community-copy .br-section-eyebrow {
        letter-spacing: .18em;
        gap: 10px;
        font-size: 10.5px;
    }
    .br-community-copy .br-section-eyebrow::before { width: 20px; }
    .br-community-copy .br-section-title {
        font-size: clamp(26px, 9vw, 36px);
    }
}

.br-community-stamp {
    position: relative;
    width: 116px;
    height: 116px;
    flex: 0 0 116px;
    display: grid;
    place-items: center;
    text-align: center;
    color: var(--accent);
    border: 2px solid var(--accent);
    border-radius: 50%;
    background:
        radial-gradient(circle at 50% 38%, rgba(255,255,255,.4), transparent 60%),
        var(--paper);
    transform: rotate(-6deg);
    box-shadow:
        inset 0 0 0 6px var(--paper-off),
        inset 0 0 0 7px var(--accent),
        0 12px 24px -16px rgba(122,31,43,.45);
    isolation: isolate;
}
.br-community-stamp::before {
    /* Dashed inner ring so it reads as a real stamp/seal, not just a circle. */
    content: '';
    position: absolute;
    inset: 14px;
    border: 1.5px dashed var(--accent);
    border-radius: 50%;
    opacity: .55;
}
.br-community-stamp-mark {
    position: absolute;
    top: 14px;
    font-size: 18px;
    line-height: 1;
    color: var(--accent);
    opacity: .85;
}
.br-community-stamp-label {
    font-family: 'Playfair Display', Georgia, serif;
    font-style: italic;
    font-weight: 600;
    font-size: 18px;
    line-height: 1.05;
    letter-spacing: -.005em;
    color: var(--accent);
    text-align: center;
}
@media (max-width: 720px) {
    .br-community-stamp { width: 84px; height: 84px; flex: 0 0 84px; }
    .br-community-stamp::before { inset: 9px; }
    .br-community-stamp-label { font-size: 12px; }
    .br-community-stamp-mark { top: 9px; font-size: 12px; }
}
@media (max-width: 420px) {
    .br-community-stamp { width: 72px; height: 72px; flex: 0 0 72px; transform: rotate(-4deg); }
    .br-community-stamp::before { inset: 7px; }
    .br-community-stamp-label { font-size: 10.5px; }
    .br-community-stamp-mark { top: 7px; font-size: 11px; }
}

/* Aside: submit CTA + stats. Stacks below on narrow screens. */
.br-community-aside {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
    justify-content: center;
    width: 100%;
    max-width: 310px;
    justify-self: end;
    background: rgba(255,255,255,.46);
    border: 1px solid var(--paper-line);
    border-radius: 20px;
    padding: 12px;
    box-shadow: 0 18px 42px -30px rgba(14,17,23,.28);
}
@media (max-width: 960px) {
    .br-community-aside { justify-self: start; }
}

.br-submit-cta {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    appearance: none;
    background: var(--accent);
    color: var(--on-dark-text);
    border: 0;
    width: 100%;
    justify-content: center;
    padding: 15px 22px;
    border-radius: 999px;
    font: inherit;
    font-weight: 600;
    font-size: 14px;
    letter-spacing: .02em;
    cursor: pointer;
    min-height: 46px;
    transition: transform .25s ease, box-shadow .25s ease, background .25s ease;
}
.br-submit-cta:hover {
    background: var(--accent-deep);
    transform: translateY(-2px);
    box-shadow: 0 18px 36px -12px rgba(122,31,43,.45);
}
.br-submit-cta:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}

/* Stats strip: editorial key/value pairs separated by a hairline. The
   second column has to fit "MOST-LOVED SHELF" (≈18ch with letter-
   spacing), so we give the whole strip a roomier max-width and let
   each cell keep generous inline padding. */
.br-community-stats {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
    margin: 0;
    padding: 0;
    width: 100%;
    max-width: 310px;
    background: var(--paper);
    border: 1px solid var(--paper-line);
    border-radius: 14px;
    overflow: hidden;
}
.br-community-stats > div {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 16px 26px;
    min-width: 0;
}
.br-community-stats > div + div {
    border-left: 0;
    border-top: 1px solid var(--paper-line);
}
.br-community-stats dt {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--text-sub);
    margin: 0;
    white-space: nowrap;
}
.br-community-stats dd {
    margin: 0;
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 22px;
    font-weight: 600;
    line-height: 1;
    color: var(--ink);
    letter-spacing: -.01em;
    /* The "top genre" value can run long ("Computer Science"); allow soft
       break without forcing a smaller font for the count column. */
    word-break: break-word;
}
@media (max-width: 720px) {
    .br-community-stats { max-width: 100%; }
    /* Center the dt/dd pairs on mobile so the stats card matches the
       overall centered alignment of the lockup above. */
    .br-community-stats > div {
        padding: 14px 18px;
        align-items: center;
        text-align: center;
    }
    .br-community-stats dt {
        font-size: 10px;
        letter-spacing: .16em;
        /* On narrow phones "MOST-LOVED SHELF" was the prime overflow vector;
           let it wrap rather than force a 155px nowrap line. */
        white-space: normal;
    }
    .br-community-stats dd { font-size: 20px; }
}
@media (max-width: 420px) {
    .br-community-aside { padding: 10px; border-radius: 16px; }
    .br-community-stats { border-radius: 12px; }
    .br-community-stats > div { padding: 12px 14px; }
    .br-community-stats dd { font-size: 18px; }
    .br-submit-cta { padding: 14px 18px; font-size: 13.5px; }
}

/* Toolbar: search bar + status line, sat above the grid */
.br-community-toolbar {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 28px;
    position: relative;
    z-index: 40;
}
.br-community-toolbar[hidden] { display: none; }

.br-community-controls {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    align-items: stretch;
}
@media (max-width: 560px) {
    .br-community-controls { grid-template-columns: 1fr; }
}

.br-community-search {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    background: var(--paper);
    border: 1px solid var(--paper-line);
    border-radius: 999px;
    padding: 6px 14px 6px 18px;
    transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.br-community-search:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(122,31,43,.12);
    background: #fff;
}
.br-community-search > svg {
    flex: 0 0 auto;
    color: var(--text-sub);
}
.br-community-search input {
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 12px 0;
    font: inherit;
    font-size: 15px;
    color: var(--ink);
    outline: none;
}
.br-community-search input::placeholder {
    color: var(--text-sub);
    opacity: .85;
}
.br-community-search input::-webkit-search-decoration,
.br-community-search input::-webkit-search-cancel-button { display: none; }

.br-community-search-clear {
    appearance: none;
    background: var(--paper-off);
    border: 1px solid var(--paper-line);
    color: var(--text-sub);
    width: 30px; height: 30px;
    border-radius: 50%;
    display: grid; place-items: center;
    cursor: pointer;
    flex: 0 0 auto;
    transition: background .15s ease, color .15s ease, transform .15s ease;
}
.br-community-search-clear:hover {
    background: var(--accent);
    color: var(--on-dark-text);
    transform: scale(1.04);
}
.br-community-search-clear:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Discipline filter — sits beside the search bar so readers can narrow
   by shelf. Trigger is the styled "pill"; the menu below is a custom
   one rendered by JS (br-shelf-menu) because native <option> styling
   is locked down by the OS and looks rough next to the rest of the UI. */
.br-community-filter {
    position: relative;
    z-index: 45;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: var(--paper);
    border: 1px solid var(--paper-line);
    border-radius: 999px;
    padding: 6px 16px 6px 22px;
    cursor: pointer;
    transition: border-color .2s ease, box-shadow .2s ease, background .2s ease, transform .15s ease;
    user-select: none;
}
.br-community-filter:hover {
    background: #fff;
    border-color: var(--paper-line);
    transform: translateY(-1px);
}
.br-community-filter:focus-within,
.br-community-filter[data-open="true"] {
    z-index: 220;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(122,31,43,.12);
    background: #fff;
}
.br-community-filter-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--text-sub);
    pointer-events: none;
}
.br-community-filter select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background: transparent;
    border: 0;
    padding: 12px 28px 12px 0;
    font: inherit;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ink);
    outline: none;
    cursor: pointer;
    /* No native dropdown arrow — we draw our own caret below. */
    background-image: none;
    /* When the custom menu is active, hide the native one but keep the
       <select> focusable for keyboard users + form a11y semantics. */
}
.br-community-filter select:focus { outline: none; }
.br-community-filter select::-ms-expand { display: none; }

/* When JS is enabled, we render a custom menu and route clicks through
   the wrapper, so the native dropdown should never actually open. The
   pointer-events:none on the select keeps clicks falling through to the
   wrapper handler; the select stays focusable via the custom trigger. */
.br-community-filter[data-enhanced="true"] select {
    pointer-events: none;
}

.br-community-filter-caret {
    position: absolute;
    right: 18px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-sub);
    pointer-events: none;
    transition: transform .25s cubic-bezier(.34,1.56,.64,1), color .2s ease;
}
.br-community-filter:focus-within .br-community-filter-caret,
.br-community-filter[data-open="true"] .br-community-filter-caret {
    color: var(--accent);
    transform: translateY(-50%) rotate(-180deg);
}

/* Custom dropdown menu — replaces the native <option> list. Animates
   in with a soft scale + fade, and respects prefers-reduced-motion. */
.br-shelf-menu {
    position: absolute;
    z-index: 1000;
    top: calc(100% + 8px);
    right: 0;
    min-width: 240px;
    background: var(--paper);
    border: 1px solid var(--paper-line);
    border-radius: 16px;
    padding: 8px;
    box-shadow:
        0 1px 2px rgba(15,23,42,.04),
        0 20px 40px -16px rgba(15,23,42,.18);
    transform-origin: top right;
    opacity: 0;
    transform: scale(.96) translateY(-4px);
    pointer-events: none;
    transition: opacity .18s ease, transform .22s cubic-bezier(.16,1,.3,1);
}
.br-shelf-menu[data-open="true"] {
    opacity: 1;
    transform: scale(1) translateY(0);
    pointer-events: auto;
}
.br-shelf-menu[hidden] { display: none; }

.br-shelf-option {
    appearance: none;
    width: 100%;
    background: transparent;
    border: 0;
    text-align: left;
    padding: 11px 14px;
    border-radius: 10px;
    font: inherit;
    font-size: 14.5px;
    font-weight: 500;
    color: var(--text-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    transition: background .12s ease, color .12s ease;
}
.br-shelf-option:hover,
.br-shelf-option:focus-visible {
    background: var(--paper-off);
    color: var(--ink);
    outline: none;
}
.br-shelf-option[aria-selected="true"] {
    color: var(--accent);
    font-weight: 600;
    background: rgba(122,31,43,.06);
}
.br-shelf-option-check {
    width: 16px;
    height: 16px;
    color: var(--accent);
    opacity: 0;
    transition: opacity .15s ease;
}
.br-shelf-option[aria-selected="true"] .br-shelf-option-check { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .br-community-filter,
    .br-community-filter-caret,
    .br-shelf-menu { transition: none; }
}

.br-community-status {
    margin: 0 0 0 18px;
    font-size: 13px;
    color: var(--text-sub);
    font-weight: 500;
    min-height: 1em;
}
.br-community-status:empty { display: none; }

/* "Reader pick" badge on community cards so it's obvious where each came from. */
.br-card-pick {
    background: var(--accent);
    color: var(--on-dark-text);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    padding: 6px 10px;
    border-radius: 999px;
    display: inline-flex; align-items: center; gap: 6px;
}
.br-card-pick svg { width: 11px; height: 11px; }

/* =================================================================
   AGGREGATE CARD — community feed
   Used when 2+ reader reviews share the same book. The card replaces
   the usual <a> wrapper with a <div> (the cover is still a link to the
   lead review). A stack-of-papers ::before behind the cover hints
   visually that there's more than one review inside, and an expand
   button reveals the individual reviews stacked below.
   ================================================================= */
.br-card-aggregate {
    /* mirror .br-card defaults so layout + grid behavior is identical */
    position: relative;
    display: block;
    text-decoration: none;
    color: inherit;
    background: var(--paper);
    border: 1px solid var(--paper-line);
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 18px 36px -24px rgba(15,23,42,.22);
    transition: transform .35s cubic-bezier(.16,1,.3,1),
                box-shadow .35s ease,
                border-color .25s ease;
    opacity: 0;
    transform: translateY(14px);
}
.br-card-aggregate.in-view { opacity: 1; transform: none; }
.br-card-aggregate:hover {
    transform: translateY(-4px);
    border-color: var(--accent);
    box-shadow: 0 24px 48px -22px rgba(122,31,43,.28);
}
.br-card-aggregate.wide { grid-column: span 6; }
.br-card-aggregate-media {
    position: relative;
    display: block;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    background: var(--paper-off);
}
.br-card-aggregate.wide .br-card-aggregate-media { aspect-ratio: 4 / 5; }
.br-card-aggregate-media img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity .4s ease, transform .6s ease;
}
.br-card-aggregate-media img.loaded { opacity: 1; }
.br-card-aggregate:hover .br-card-aggregate-media img { transform: scale(1.04); }
/* Stacked-papers hint — three offset shadow planes peeking out from
   behind the cover, signalling "there are more reviews inside". */
.br-card-aggregate-stack {
    position: absolute;
    inset: 6px 0 0 0;
    pointer-events: none;
    z-index: 0;
}
.br-card-aggregate-stack span {
    position: absolute;
    inset: 4px 8px 0 8px;
    border-radius: 6px 6px 0 0;
    background: var(--paper-line);
    transform-origin: center bottom;
}
.br-card-aggregate-stack span:nth-child(1) { transform: translateY(-6px) rotate(-1.4deg); opacity: .55; }
.br-card-aggregate-stack span:nth-child(2) { transform: translateY(-10px) rotate(1deg);    opacity: .35; }
.br-card-aggregate-stack span:nth-child(3) { transform: translateY(-14px) rotate(-.6deg);  opacity: .22; }

.br-card-aggregate .br-card-body {
    padding: 20px 22px 22px;
}
.br-card-aggregate-note {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
    margin: 8px 0 14px;
}
.br-card-aggregate-note strong {
    color: var(--ink);
    font-weight: 700;
}

/* Expand/collapse button */
.br-aggregate-toggle {
    appearance: none;
    background: var(--paper-off);
    border: 1px solid var(--paper-line);
    color: var(--ink);
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 14px;
    border-radius: 10px;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .01em;
    cursor: pointer;
    transition: background .2s ease, border-color .2s ease, color .2s ease;
    min-height: 40px;
}
.br-aggregate-toggle:hover {
    background: var(--paper);
    border-color: var(--accent);
    color: var(--accent);
}
.br-aggregate-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}
.br-aggregate-toggle-caret {
    width: 14px;
    height: 14px;
    transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
    flex: 0 0 auto;
}
.br-aggregate-toggle[aria-expanded="true"] .br-aggregate-toggle-caret {
    transform: rotate(-180deg);
}

/* Individual reviews list (shown when expanded) */
.br-aggregate-reviews {
    list-style: none;
    padding: 0;
    margin: 12px 0 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.br-aggregate-reviews[hidden] { display: none; }
.br-aggregate-review {
    border-top: 1px solid var(--paper-line);
    padding-top: 14px;
}
.br-aggregate-review:first-child { border-top: 0; padding-top: 4px; }
.br-aggregate-review-head {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.br-aggregate-review-rating {
    display: inline-flex;
    align-items: baseline;
    padding: 4px 10px;
    background: rgba(122, 31, 43, 0.08);
    border: 1px solid rgba(122, 31, 43, 0.18);
    color: var(--accent-deep);
    border-radius: 999px;
    font-weight: 700;
    font-size: 12px;
    line-height: 1;
}
.br-aggregate-review-rating-num {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 15px;
    font-weight: 700;
}
.br-aggregate-review-rating small {
    font-size: 10px;
    font-weight: 500;
    margin-left: 2px;
    opacity: .8;
}
.br-aggregate-review-byline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 12.5px;
    color: var(--text-muted);
}
.br-aggregate-review-byline strong {
    color: var(--ink);
    font-weight: 600;
}
.br-aggregate-review-blurb {
    margin: 8px 0 6px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-muted);
    /* Keep it tight — one short paragraph; the "read full review" link
       below opens the standalone article page if the reader wants more. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.br-aggregate-review-link {
    display: inline-flex;
    align-items: center;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
    border-bottom: 1px solid rgba(122,31,43,.3);
    padding-bottom: 1px;
    transition: border-color .2s, color .2s;
}
.br-aggregate-review-link:hover {
    color: var(--accent-deep);
    border-bottom-color: var(--accent-deep);
}

/* =================================================================
   SUBMISSION MODAL — public form
   ================================================================= */
.br-modal-backdrop {
    position: fixed; inset: 0;
    background: rgba(14,17,23,.62);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 1000;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
    opacity: 0;
    transition: opacity .3s ease;
}
.br-modal-backdrop.is-open {
    display: flex;
    opacity: 1;
}
.br-modal {
    background: var(--paper);
    border-radius: 16px;
    width: 100%;
    max-width: 620px;
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    box-shadow: 0 40px 80px -20px rgba(0,0,0,.55);
    transform: translateY(20px) scale(.98);
    transition: transform .35s cubic-bezier(.16,1,.3,1);
    position: relative;
}
.br-modal-backdrop.is-open .br-modal {
    transform: none;
}
.br-modal-head {
    padding: 32px 32px 16px;
    border-bottom: 1px solid var(--paper-line);
    position: sticky; top: 0;
    background: var(--paper);
    border-radius: 16px 16px 0 0;
    z-index: 1;
}
.br-modal-eyebrow {
    font-size: 11px;
    letter-spacing: .26em;
    text-transform: uppercase;
    color: var(--accent);
    font-weight: 600;
    margin-bottom: 8px;
}
.br-modal-title {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 28px;
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 6px;
    letter-spacing: -.01em;
    line-height: 1.15;
}
.br-modal-sub {
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1.5;
    margin: 0;
}
.br-modal-close {
    position: absolute;
    top: 18px; right: 18px;
    appearance: none;
    background: var(--paper-off);
    border: 0;
    width: 36px; height: 36px;
    border-radius: 50%;
    cursor: pointer;
    color: var(--text);
    display: grid; place-items: center;
    transition: background .2s ease;
}
.br-modal-close:hover { background: var(--paper-line); }
.br-modal-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.br-modal-body {
    padding: 24px 32px 32px;
}
.br-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px 18px;
    /* Each row sizes to its natural content. The rating card was
       previously much taller than a text input, which created visible
       gaps; it's now a compact single-row control (see .br-rating-slider
       below) so cells in the same row are the same height naturally,
       without us forcing a min-height floor that produced dead space
       in the other cells. */
    align-items: start;
}
.br-form-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.br-form-field.full { grid-column: 1 / -1; }
.br-form-field label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.br-form-field label .req { color: var(--accent); }
.br-form-field input,
.br-form-field textarea,
.br-form-field select {
    appearance: none;
    background: var(--paper-off);
    border: 1px solid var(--paper-line);
    border-radius: 10px;
    padding: 12px 14px;
    font: inherit;
    font-size: 15px;
    color: var(--ink);
    transition: border-color .2s, box-shadow .2s, background .2s;
    min-height: 48px;
}
.br-form-field textarea {
    min-height: 140px;
    resize: vertical;
    line-height: 1.6;
}
.br-form-field input:focus-visible,
.br-form-field textarea:focus-visible,
.br-form-field select:focus-visible {
    outline: none;
    background: var(--paper);
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(122,31,43,.12);
}
.br-form-field .hint {
    font-size: 12px;
    color: var(--text-subtle);
}

/* =================================================================
   RATING SLIDER — public submission form
   Compact single-row control sized to match the height of an adjacent
   text input, so the form grid keeps clean even-row geometry. Inside
   the pill: a star-overlay track (filled by width %) on the left, the
   slider thumb riding on top, and a numeric readout on the right.
   The flavor label ("Strongly recommend", etc.) lives in the hint
   slot beneath the pill, mirroring how text-input hints render.
   Form handler still reads the hidden #br-rating input.
   ================================================================= */
.br-rating-slider {
    display: flex;
    align-items: center;
    gap: 12px;
    /* Match the visual chrome AND height of the sibling text inputs
       (.br-form-field input) so the rating cell is a true peer in the
       grid — same paper-off background, same border, same radius, and
       same 48px minimum height. */
    padding: 6px 14px;
    background: var(--paper-off);
    border: 1px solid var(--paper-line);
    border-radius: 10px;
    min-height: 48px;
    transition: border-color .2s, box-shadow .2s, background .2s;
}
.br-rating-slider:focus-within {
    background: var(--paper);
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(122,31,43,.12);
}
/* Star track — a thin row of stars that fills with accent color from
   left as the value rises. Positioned UNDER the slider thumb so the
   star bar reads as the track itself, not as a separate widget. */
.br-rating-slider-track {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    height: 36px;
}
/* Visible progress rail behind the stars/thumb. A thin 4px line
   centered vertically in the 36px hit-area, painted via ::before so
   it's a real element we can style independently from the stars
   layer above. Two stacked gradients give us the faded baseline
   plus the accent fill (driven by --br-pct from JS). */
.br-rating-slider-track::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 4px;
    transform: translateY(-50%);
    border-radius: 999px;
    background:
        linear-gradient(
            to right,
            var(--accent) 0%,
            var(--accent) calc(var(--br-pct, 0) * 1%),
            rgba(15, 23, 42, 0.14) calc(var(--br-pct, 0) * 1%),
            rgba(15, 23, 42, 0.14) 100%
        );
    z-index: 0;
    pointer-events: none;
}
.br-rating-slider-stars {
    /* The stars row spans the full track width. Both base (faded)
       and fill (accent) layers are laid out at the SAME size with
       5 stars distributed via flex `space-around` — so each star
       sits at the same physical pixel position in both layers.
       The fill layer is clipped from the right via clip-path:inset
       at the current rating %, naturally hiding any unfilled stars.
       (clip-path beats overflow:hidden + width:% here because the
       flex layout doesn't reflow when clipped — the spans stay at
       their full-width positions.) */
    position: absolute;
    inset: 0;
    pointer-events: none;
    line-height: 1;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 22px;
    user-select: none;
    z-index: 0;
}
.br-rating-slider-stars-base,
.br-rating-slider-stars-fill {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: space-around;
    padding: 0 8px;
    white-space: nowrap;
}
.br-rating-slider-stars-base {
    color: rgba(15, 23, 42, 0.18);
}
.br-rating-slider-stars-fill {
    color: var(--accent);
    /* Clip from the right edge based on --br-pct (set by JS). At
       0% rating, inset 0 100% 0 0 fully clips the fill; at 100%
       rating, inset 0 0 0 0 shows everything. */
    clip-path: inset(0 calc(100% - var(--br-pct, 0) * 1%) 0 0);
    transition: clip-path .12s ease-out;
    /* width prop is no longer used for clipping, but we keep it at
       100% so the inner flex layout matches the base exactly. */
    width: 100%;
}
.br-rating-slider-stars span {
    flex: 0 0 auto;
}

/* Slider sits ON TOP of the stars — transparent track so the stars
   show through, thumb visible. Reset all the inherited form-field
   defaults that would otherwise paint a pill over the stars. */
.br-rating-slider-input,
.br-form-field .br-rating-slider-input {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    min-height: 0;
    border-radius: 0;
    outline: none;
    cursor: pointer;
    z-index: 1; /* above the .br-rating-slider-stars */
}

/* WebKit / Blink — runnable-track is sized to MATCH the visual rail
   (4px) so the thumb's center auto-aligns with the rail. The whole
   <input> is 36px tall and absolutely-positioned over the track for
   a comfortable hit-area; the visible track inside it is only 4px. */
.br-rating-slider-input::-webkit-slider-runnable-track {
    height: 4px;
    background: transparent;
    border: 0;
}
.br-rating-slider-input::-webkit-slider-thumb {
    appearance: none;
    -webkit-appearance: none;
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--paper);
    border: 2px solid var(--accent);
    box-shadow: 0 3px 8px -2px rgba(122, 31, 43, .55);
    cursor: grab;
    /* Center the 18px thumb on the 4px track: (4 - 18) / 2 = -7. */
    margin-top: -7px;
    transition: transform .12s ease, box-shadow .12s ease;
}
.br-rating-slider-input::-moz-range-track {
    height: 4px;
    background: transparent;
    border: 0;
}
.br-rating-slider-input::-moz-range-thumb {
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--paper);
    border: 2px solid var(--accent);
    box-shadow: 0 3px 8px -2px rgba(122, 31, 43, .55);
    cursor: grab;
}
/* Firefox renders a tiny progress fill from 0 → thumb by default; the
   stars + rail already convey progress, so hide Firefox's stripe. */
.br-rating-slider-input::-moz-range-progress {
    height: 4px;
    background: transparent;
}
.br-rating-slider-input:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 4px rgba(122, 31, 43, .22);
}
.br-rating-slider-input:focus-visible::-moz-range-thumb {
    box-shadow: 0 0 0 4px rgba(122, 31, 43, .22);
}
.br-rating-slider-input:active::-webkit-slider-thumb { cursor: grabbing; transform: scale(1.1); }
.br-rating-slider-input:active::-moz-range-thumb     { cursor: grabbing; transform: scale(1.1); }

/* Numeric readout on the right end of the pill — "4.2 / 5". */
.br-rating-slider-value {
    flex: 0 0 auto;
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 600;
    font-size: 16px;
    color: var(--ink);
    line-height: 1;
    min-width: 56px;
    text-align: right;
    white-space: nowrap;
}
.br-rating-slider[data-value="0"] .br-rating-slider-value {
    font-family: inherit;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-subtle);
}
.br-rating-slider-value small {
    font-size: 11px;
    font-weight: 400;
    color: var(--text-subtle);
    margin-left: 2px;
}

/* Flavor sits in the hint slot below the pill — same typography as
   the other hints in the form so the cell visually matches a text
   input + hint stack. */
.br-rating-slider-flavor {
    color: var(--text-subtle);
    font-style: normal;
    min-height: 1.2em;
}
.br-rating-slider:not([data-value="0"]) + .br-rating-slider-flavor {
    color: var(--accent-deep);
    font-style: italic;
    font-weight: 500;
}
@media (prefers-reduced-motion: reduce) {
    .br-rating-slider-stars-fill,
    .br-rating-slider-input::-webkit-slider-thumb { transition: none; }
}
.br-form-error {
    background: rgba(122,31,43,.08);
    border: 1px solid rgba(122,31,43,.22);
    color: var(--accent-deep);
    padding: 12px 14px;
    border-radius: 10px;
    font-size: 14px;
    margin-bottom: 16px;
}
.br-form-success {
    text-align: center;
    padding: 20px 8px 8px;
}
.br-form-success-icon {
    width: 56px; height: 56px;
    margin: 0 auto 14px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--on-dark-text);
    display: grid; place-items: center;
}
.br-form-success h3 {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 24px;
    margin: 0 0 8px;
    color: var(--ink);
}
.br-form-success p {
    color: var(--text-muted);
    line-height: 1.6;
    margin: 0 auto 16px;
    max-width: 42ch;
}

.br-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding-top: 8px;
    margin-top: 8px;
    border-top: 1px solid var(--paper-line);
    padding-top: 18px;
}
.br-btn {
    appearance: none;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    padding: 13px 24px;
    font: inherit;
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    min-height: 46px;
    transition: background .2s ease, color .2s ease, border-color .2s ease, transform .2s ease;
}
.br-btn-ghost {
    color: var(--text);
    border-color: var(--paper-line);
}
.br-btn-ghost:hover { background: var(--paper-off); }
.br-btn-primary {
    background: var(--ink);
    color: var(--on-dark-text);
}
.br-btn-primary:hover { background: var(--accent); }
.br-btn-primary:disabled {
    background: var(--paper-line);
    color: var(--text-subtle);
    cursor: not-allowed;
}
.br-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (max-width: 540px) {
    .br-form-grid { grid-template-columns: 1fr; }
    .br-modal-head { padding: 24px 22px 14px; }
    .br-modal-body { padding: 18px 22px 24px; }
    .br-modal-actions { flex-direction: column-reverse; }
    .br-modal-actions .br-btn { width: 100%; }
}
