/* =============================================================================
   SudaHub — Book Club: Premieres (docs/BOOKCLUB.md §3, §11)
   Phase 3. Reuses .tile/.tile-hero/.badge/.stale-chip/.skeleton from
   primitives.css and CLAUDE.md's token set — nothing here is a new colour
   or radius, only Premieres-specific layout and the feed-id/hero-value/
   corner-bracket treatments that were previously rates.css's (removed in
   Book Club Phase 2) and now belong to this screen instead.
   ========================================================================== */

/* ================= FEED ID (§11: "structural, like the old FX-01") ================= */
.premiere-feed-id {
    font-family: var(--font-mono);
    font-size: var(--fs-caption);
    font-weight: 600;
    letter-spacing: 0.12em;
    color: var(--text-secondary);
}
[lang="ar"] .premiere-feed-id { letter-spacing: 0; }

/* ================= CORNER BRACKETS (§3.1, §10: hero tile only, four marks) ================= */
.corner-bracket { position: absolute; width: 12px; height: 12px; pointer-events: none; }
.corner-bracket-tl { inset-block-start: 12px; inset-inline-start: 12px; border-block-start: 1px solid var(--line-strong); border-inline-start: 1px solid var(--line-strong); }
.corner-bracket-tr { inset-block-start: 12px; inset-inline-end: 12px; border-block-start: 1px solid var(--line-strong); border-inline-end: 1px solid var(--line-strong); }
.corner-bracket-bl { inset-block-end: 12px; inset-inline-start: 12px; border-block-end: 1px solid var(--line-strong); border-inline-start: 1px solid var(--line-strong); }
.corner-bracket-br { inset-block-end: 12px; inset-inline-end: 12px; border-block-end: 1px solid var(--line-strong); border-inline-end: 1px solid var(--line-strong); }

/* ================= BOARD ================= */
.premiere-board-title {
    font-family: var(--font-label);
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin-block-end: 12px;
}
[lang="en"] .premiere-board-title { text-transform: uppercase; }
[lang="ar"] .premiere-board-title { letter-spacing: 0; }

.premiere-board-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}
@media (min-width: 640px) {
    .premiere-board-grid { grid-template-columns: repeat(2, 1fr); }
    /* The soonest premiere (always the first tile — the query already
       orders by effective_at) takes the 2x2 hero slot; the rest fall into
       normal grid flow at 1x1, exactly like Rates' bento grid did (§3.1). */
    .premiere-board-grid > .premiere-tile-hero { grid-column: span 2; grid-row: span 2; }
}
@media (min-width: 1024px) {
    .premiere-board-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ================= TILE ================= */
.premiere-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
}
.premiere-tile-clickarea {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 100%;
    text-align: start;
    background: none;
    border: none;
    padding: var(--space-6);
    cursor: pointer;
    color: inherit;
    font: inherit;
}
.premiere-tile-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

.premiere-tile-body { display: flex; gap: 12px; align-items: flex-start; }
.premiere-tile-cover {
    flex-shrink: 0;
    width: 48px;
    aspect-ratio: 2 / 3;
    border-radius: var(--r-sm);
    overflow: hidden;
    border: 1px solid var(--line-subtle);
    background: var(--surface-sunken);
}
.premiere-tile-hero .premiere-tile-cover { width: 72px; }
.premiere-tile-cover-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.premiere-tile-cover-fallback { width: 100%; height: 100%; background: linear-gradient(155deg, var(--surface-sunken), var(--surface-raised)); }

.premiere-tile-info { min-width: 0; flex: 1; }
.premiere-tile-book-title { font-weight: 700; font-size: var(--fs-body); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.premiere-tile-hero .premiere-tile-book-title { font-size: var(--fs-title-s); }
.premiere-tile-chapter { font-family: var(--font-label); font-size: var(--fs-caption); color: var(--text-secondary); margin-block-start: 2px; }
.premiere-tile-author { font-size: var(--fs-label); color: var(--text-muted); margin-block-start: 2px; }

/* ================= COUNTDOWN (§3.1: tabular mono, no animation on the digits themselves) ================= */
.premiere-countdown { padding-block-start: 4px; }
.premiere-countdown-value {
    display: block;
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--fs-title-l);
    line-height: 28px;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}
.premiere-countdown-hero .premiere-countdown-value {
    font-size: var(--fs-hero);
    line-height: 1.1;
}
@media (min-width: 640px) {
    .premiere-countdown-hero .premiere-countdown-value { font-size: var(--fs-hero); line-height: 60px; }
}
/* §3.1: "Under 60 seconds... seconds get larger." The only state change on
   the digits themselves — still no flip/odometer/scale animation (§14). */
.premiere-countdown.is-promoted .cd-sec { font-size: 1.3em; color: var(--accent); }

.premiere-countdown-caption {
    display: block;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    margin-block-start: 2px;
}
[lang="en"] .premiere-countdown-caption { text-transform: uppercase; }
[lang="ar"] .premiere-countdown-caption { letter-spacing: 0; }

.premiere-tile-datetime { font-family: var(--font-label); font-size: var(--fs-caption); color: var(--text-secondary); margin-block-start: 4px; }
.premiere-tile-status-line { font-family: var(--font-label); font-size: var(--fs-body-s); font-weight: 700; color: var(--accent); padding-block-start: 4px; }

/* ================= MILESTONE (§3.4) — solid --accent fill on
   --surface-sunken, never the brand gradient (gradient budget is already
   spent on the countdown's corner brackets on this same tile). ================= */
.premiere-milestone { padding-block-start: 12px; }
.premiere-milestone-track {
    height: 6px;
    border-radius: var(--r-full);
    background: var(--surface-sunken);
    overflow: hidden;
}
.premiere-milestone-fill {
    height: 100%;
    background: var(--accent);
    border-radius: var(--r-full);
    transition: width var(--dur-enter) var(--ease-out);
}
.premiere-milestone-count {
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
    margin-block-start: 4px;
}
.premiere-milestone-caption {
    font-family: var(--font-label);
    font-size: var(--fs-meta);
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}
[lang="en"] .premiere-milestone-caption { text-transform: uppercase; }
[lang="ar"] .premiere-milestone-caption { letter-spacing: 0; }

/* ================= TEASER (§3.5) — a solid block at the text baseline,
   never a blur (blur invites people to try to un-blur it). ================= */
.premiere-tile-teaser { font-size: var(--fs-body-s); line-height: 1.6; color: var(--text-secondary); padding-block-start: 10px; }
.premiere-teaser-redacted {
    display: inline-block;
    height: 0.85em;
    background: var(--surface-sunken);
    border-radius: 2px;
    vertical-align: text-bottom;
    margin-inline: 1px;
}

/* ================= ACTIONS ================= */
.premiere-tile-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 0 var(--space-6) var(--space-6);
}
.premiere-tile-actions .btn { flex: 1; min-width: 120px; }

/* ================= EMPTY BOARD ================= */
.premiere-board .empty-state { padding-block: 64px; }

/* ================= PREMIERE ROOM (§3.2) — keeps the app's normal chrome/
   theme, unlike the reader's deliberate brand-free exception (§7.4). ================= */
.premiere-room-modal {
    position: fixed;
    inset: 0;
    z-index: 150;
    display: flex;
    flex-direction: column;
    background: var(--canvas);
    color: var(--text-primary);
}
.premiere-room-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-block-end: 1px solid var(--line);
    flex-shrink: 0;
}
.premiere-room-header-text { flex: 1; min-width: 0; text-align: center; }
#premiere-room-title { font-size: var(--fs-body-s); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.premiere-room-header .premiere-feed-id { display: block; margin-block-end: 2px; }

.premiere-room-body { flex: 1; overflow-y: auto; padding: 20px 16px 40px; max-width: 720px; margin: 0 auto; width: 100%; position: relative; }

/* ---- Cover backdrop ----
   Anchored to the countdown block, NOT to the room body, and bled out to the
   body's padding edges with negative insets. A first attempt gave it a fixed
   320px height from the top of the room; measurement showed the chapter prose
   starting at ~150px and therefore sitting on top of artwork. Sizing it to the
   header block means it ends where the header ends no matter what the content
   below is — there is no height to guess wrong.

   The mask does the fade rather than a gradient overlay, so the backdrop
   dissolves into whatever the page background is in either theme — no scrim
   colour to keep in sync with two palettes. `inset-inline` keeps the bleed
   mirrored under RTL. */
.premiere-room-backdrop {
    position: absolute;
    inset-block-start: -20px;   /* up into .premiere-room-body's top padding */
    inset-block-end: -8px;      /* a short tail past the block's own rule */
    inset-inline: -16px;        /* out to the body's side padding */
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 55%, transparent 100%);
    mask-image: linear-gradient(to bottom, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 55%, transparent 100%);
}
.premiere-room-backdrop img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Low enough that the large type above it keeps its contrast whatever the
       artwork is doing underneath. */
    opacity: 0.22;
    filter: saturate(0.85);
}
/* The block is the backdrop's positioning context; its own children sit above
   it. .premiere-room-lower is raised too so nothing can slide underneath. */
.premiere-room-countdown-block { position: relative; }
.premiere-room-countdown-block > *:not(.premiere-room-backdrop) { position: relative; z-index: 1; }
.premiere-room-lower { position: relative; z-index: 1; }

/* The backdrop is decoration, and §8's Reduce effects / low-data modes exist
   to drop exactly this kind of thing — it is a full-size image download whose
   only job is atmosphere. */
[data-reduce-effects="true"] .premiere-room-backdrop,
[data-low-data="true"] .premiere-room-backdrop { display: none; }

.premiere-room-countdown-block {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-block-end: 20px;
    border-block-end: 1px solid var(--line-subtle);
    margin-block-end: 20px;
}
.premiere-room-cover { width: 64px; flex-shrink: 0; }

/* `min-width: 0` is the whole fix for the room's horizontal scroll.
   A flex item defaults to `min-width: auto`, which means it refuses to
   shrink below its content — and the book title's own `-webkit-line-clamp: 2`
   can never engage, because the parent just grows to fit the title on one
   line instead. On a 375px phone a long title pushed this row to 510px, and
   since .premiere-room-body sets `overflow-y: auto` (which computes
   overflow-x to `auto`, not `visible`), the whole room became swipeable
   sideways. Letting this box shrink lets the clamp do its job. */
.premiere-room-book-meta { flex: 1 1 auto; min-width: 0; }
.premiere-room-countdown-block .premiere-countdown { flex: 1; text-align: end; padding-block-start: 0; }
.premiere-room-countdown-block .premiere-tile-status-line { flex: 1; text-align: end; }
[dir="rtl"] .premiere-room-countdown-block .premiere-countdown,
[dir="rtl"] .premiere-room-countdown-block .premiere-tile-status-line { text-align: start; }

.premiere-room-notice {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    text-align: center;
    padding: 32px 16px;
    color: var(--text-secondary);
    font-size: var(--fs-body-s);
}

.premiere-room-chapter-loading { display: flex; flex-direction: column; gap: 10px; }

/* Arabic reading text follows CLAUDE.md §3's weight-500/1.85-line-height
   rule for body copy — a chapter is exactly that, even read inline here
   rather than through the full paginated Library reader. */
.premiere-room-chapter-text { font-size: var(--fs-title-s); line-height: 1.8; }
.premiere-room-chapter-text[lang="ar"] { font-weight: 500; line-height: 1.85; }
.premiere-room-chapter-text p { margin-block-end: 1.2em; }

/* ================= WAITING ROOM CHAT (§3.2, §9) ================= */
.premiere-chat {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-block-start: 24px;
    margin-block-start: 8px;
    border-block-start: 1px solid var(--line-subtle);
}

.premiere-chat-messages {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 320px;
    overflow-y: auto;
    padding-inline-end: 4px;
}
.premiere-chat-empty { text-align: center; font-size: var(--fs-body-s); color: var(--text-muted); padding-block: 24px; }

.premiere-chat-row {
    align-self: flex-start;
    max-width: 85%;
    background: var(--surface);
    border: 1px solid var(--line-subtle);
    border-radius: var(--r-md);
    padding: 8px 12px;
}
/* Own messages lean to the reading-end side, like a normal chat bubble
   layout — flips automatically under RTL since it's a flex/align rule,
   not a physical left/right one. */
.premiere-chat-row.is-own { align-self: flex-end; background: var(--surface-raised); }
.premiere-chat-row.is-author { border-color: var(--accent); }
.premiere-chat-row.is-pending { opacity: 0.7; border-style: dashed; }
.premiere-chat-author-badge { margin-block-end: 4px; }
.premiere-chat-body { font-size: var(--fs-body); line-height: 1.5; overflow-wrap: break-word; }
/* m.dir holds this specific message's own detected direction ('ltr'/'rtl'),
   set per-message (§5.4: "detect the dominant script and set dir on the
   message bubble, not the container") — not the app's active UI language,
   so this can't key off [lang="ar"]. */
.premiere-chat-row[dir="rtl"] .premiere-chat-body { font-weight: 500; line-height: 1.7; }
.premiere-chat-row-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-block-start: 4px; }
.premiere-chat-pending-note { font-family: var(--font-label); font-size: var(--fs-meta); color: var(--warning); }
.premiere-chat-report-btn {
    background: none; border: none; cursor: pointer;
    color: var(--text-muted); font-size: var(--fs-label); line-height: 1; padding: 2px;
}
.premiere-chat-report-btn:hover { color: var(--danger); }

.premiere-chat-reactions { display: flex; gap: 8px; }
.premiere-reaction-btn {
    width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center;
    font-size: var(--fs-title);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-full);
    cursor: pointer;
    transition: transform var(--dur-micro) var(--ease-out);
}
.premiere-reaction-btn:active { transform: scale(0.9); }

.premiere-chat-reaction-layer {
    position: absolute;
    inset-inline: 0;
    inset-block-start: 0;
    height: 100%;
    pointer-events: none;
    overflow: hidden;
}
.premiere-reaction-float {
    position: absolute;
    inset-block-end: 40px;
    font-size: var(--fs-title-l);
    animation: premiere-reaction-rise 1.6s var(--ease-out) forwards;
}
@keyframes premiere-reaction-rise {
    0% { transform: translateY(0); opacity: 1; }
    100% { transform: translateY(-120px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .premiere-reaction-float { animation: none; opacity: 0; }
}
[data-reduce-effects="true"] .premiere-reaction-float { animation: none; opacity: 0; }

.premiere-chat-composer { display: flex; gap: 8px; }
.premiere-chat-composer .input { flex: 1; }

/* ================= BOOK CLUB SUB-NAV (§1: Premieres / Arena) ================= */

/* ================= ARENA (§4) — Phase 7: cycle + editor only ================= */
.arena-prompt-card { margin-block-end: 20px; }
.arena-prompt-head { display: flex; gap: 8px; margin-block-end: 12px; }
.arena-prompt-body { font-size: var(--fs-title-s); line-height: 1.7; }
.arena-prompt-body[dir="rtl"] { font-weight: 500; line-height: 1.85; }

.arena-editor { display: flex; flex-direction: column; gap: 10px; }
.arena-editor-head { display: flex; justify-content: flex-end; }
.arena-word-counter {
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
}
.arena-word-counter.is-warning { color: var(--warning); }
.arena-word-counter.is-danger { color: var(--danger); }

.arena-textarea { min-height: 160px; resize: vertical; font-size: var(--fs-body-l); line-height: 1.7; }
.arena-textarea[dir="rtl"] { font-weight: 500; line-height: 1.85; }

.arena-checklist { display: flex; flex-direction: column; gap: 6px; list-style: none; margin: 0; padding: 0; }
.arena-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-label);
    font-size: var(--fs-label);
    color: var(--text-muted);
}
.arena-check.is-ok { color: var(--text-secondary); }
.arena-check-mark { width: 14px; text-align: center; }
.arena-check.is-ok .arena-check-mark { color: var(--accent); }

.arena-frozen-note { font-size: var(--fs-body-s); color: var(--text-secondary); font-style: italic; }

/* ================= ARENA VOTING (§4.4) — text-only cards, no avatars/
   usernames/counts/timestamps: nothing that leaks identity or creates
   bandwagon pressure. Equal height, side by side at >=768px. No glass —
   they're in a list, per CLAUDE.md §6. ================= */
.arena-voting-panel { display: flex; flex-direction: column; gap: 16px; align-items: center; }
.arena-duel { display: flex; flex-direction: column; gap: 12px; width: 100%; }
@media (min-width: 768px) { .arena-duel { flex-direction: row; align-items: stretch; } }
.arena-duel-card {
    flex: 1;
    text-align: start;
    font-size: var(--fs-body-l);
    line-height: 1.7;
    padding: 20px;
    cursor: pointer;
    background: var(--surface);
}
.arena-duel-card[dir="rtl"] { font-weight: 500; line-height: 1.85; }
.arena-duel-skip { align-self: center; }

/* ================= RESULTS / LEADERBOARD (§4.5) ================= */
.arena-results-tabs { display: flex; gap: 8px; margin-block-end: 16px; }
.arena-leaderboard { display: flex; flex-direction: column; gap: 8px; }
.arena-leaderboard-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--line-subtle);
    border-radius: var(--r-md);
}
.arena-leaderboard-rank {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: var(--fs-body-s);
    color: var(--text-muted);
    min-width: 20px;
    font-variant-numeric: tabular-nums;
}
.arena-leaderboard-body { font-size: var(--fs-body); line-height: 1.6; flex: 1; }
.arena-leaderboard-body[dir="rtl"] { font-weight: 500; line-height: 1.75; }
.arena-following-note { font-size: var(--fs-label); color: var(--text-muted); text-align: center; margin-block-start: 16px; }

/* ================= BADGES (§4.6: "Credentials, not trophies" — mono,
   --surface-raised, no gradient/shine) ================= */
.arena-badge-list { display: flex; flex-wrap: wrap; gap: 8px; }
.arena-badge {
    display: inline-flex;
    align-items: center;
    font-family: var(--font-label);
    font-size: var(--fs-meta);
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 5px 10px;
    border-radius: var(--r-sm);
    background: var(--surface-raised);
    color: var(--text-secondary);
    border: 1px solid var(--line);
}
[lang="en"] .arena-badge { text-transform: uppercase; }
[lang="ar"] .arena-badge { letter-spacing: 0; }

/* ================= NOMINATIONS (§4.6, submission only) ================= */
.arena-nominate { margin-block-start: 24px; padding-block-start: 16px; border-block-start: 1px solid var(--line-subtle); }
.arena-nominate summary { cursor: pointer; font-weight: 700; font-size: var(--fs-body-s); color: var(--text-secondary); }
.arena-nominate-note { font-size: var(--fs-label); color: var(--text-muted); margin-block: 10px; line-height: 1.6; }
.arena-nominate-form { display: flex; flex-direction: column; gap: 10px; }
.arena-nominate-label {
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--text-muted);
}
[lang="en"] .arena-nominate-label { text-transform: uppercase; }
[lang="ar"] .arena-nominate-label { letter-spacing: 0; }
.arena-nominate-textarea { min-height: 90px; resize: vertical; }

/* ================= AUTHOR STUDIO (§12) ================= */
.author-studio-form { display: flex; flex-direction: column; gap: 10px; margin-block-end: 20px; }
.author-studio-zone-preview { display: flex; flex-wrap: wrap; gap: 8px; }
.author-studio-zone-chip {
    font-family: var(--font-label);
    font-size: var(--fs-caption);
    color: var(--text-secondary);
    background: var(--surface-sunken);
    padding: 4px 8px;
    border-radius: var(--r-sm);
}
.author-studio-queue-list { display: flex; flex-direction: column; gap: 10px; margin-block-end: 20px; }
.author-studio-queue-row { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.author-studio-milestone-summary { font-family: var(--font-label); font-size: var(--fs-caption); color: var(--text-secondary); }
.author-studio-milestone-builder { margin-block-end: 20px; }
.author-studio-warning { font-size: var(--fs-label); color: var(--warning); margin-block: 8px; line-height: 1.6; }
.author-studio-insights-note { font-size: var(--fs-label); color: var(--text-muted); line-height: 1.6; margin-block-start: 8px; }

/* ================= DROP CELEBRATION (§3.3) — the one sanctioned exception
   to CLAUDE.md's no-bounce rule. <=1200ms, once, on a real state
   transition only (js/premieres.js's playDropCelebration, called on
   'dropped' — never on a timer). Skipped entirely under reduced motion /
   Reduce Effects / low-data (checked in JS before this class is ever
   added), so nothing here needs its own reduced-motion override. */
.premiere-tile.is-celebrating { position: relative; overflow: hidden; }
.premiere-tile.is-celebrating::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--grad-brand);
    opacity: 0;
    mix-blend-mode: overlay;
    animation: premiere-drop-sweep 900ms var(--ease-out) forwards;
    pointer-events: none;
    z-index: 1;
}
@keyframes premiere-drop-sweep {
    0% { opacity: 0; transform: translateX(-100%); }
    35% { opacity: 0.9; }
    100% { opacity: 0; transform: translateX(100%); }
}
[dir="rtl"] .premiere-tile.is-celebrating::before { animation-name: premiere-drop-sweep-rtl; }
@keyframes premiere-drop-sweep-rtl {
    0% { opacity: 0; transform: translateX(100%); }
    35% { opacity: 0.9; }
    100% { opacity: 0; transform: translateX(-100%); }
}
.premiere-tile.is-celebrating .premiere-tile-clickarea::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 2;
    background-image:
        radial-gradient(3px 3px at 20% 30%, var(--brand-cyan), transparent),
        radial-gradient(3px 3px at 55% 15%, var(--brand-magenta), transparent),
        radial-gradient(3px 3px at 80% 40%, var(--brand-violet), transparent),
        radial-gradient(2px 2px at 35% 60%, var(--brand-blue), transparent),
        radial-gradient(2px 2px at 70% 70%, var(--brand-cyan), transparent);
    opacity: 0;
    animation: premiere-drop-particles 1100ms var(--ease-out) forwards;
}
@keyframes premiere-drop-particles {
    0% { opacity: 0; transform: scale(0.6) translateY(6px); }
    25% { opacity: 1; }
    100% { opacity: 0; transform: scale(1.15) translateY(-14px); }
}

/* ================= THE CLUB SCREEN (RESKIN §2.4) =================
   One scrolling screen: hero premiere, arena, waiting room, more rooms.
   Replaces the console's Premieres/Arena sub-nav + board grid. */
.club-section { display: flex; flex-direction: column; gap: var(--space-4); }
.club-section:empty { display: none; }

.club-section-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.club-section-title {
    margin: 0;
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-label);
    color: var(--color-neutral-100);
    white-space: nowrap;
}
/* The mockup's section rule: a hairline that fades OUT across the row.
   Uses a logical gradient direction so it fades away from the title in
   both writing directions. */
.club-section-rule {
    flex: 1;
    height: 1px;
    background: linear-gradient(to right, var(--color-neutral-800), transparent);
}
[dir="rtl"] .club-section-rule {
    background: linear-gradient(to left, var(--color-neutral-800), transparent);
}

/* ---------- Hero premiere ---------- */
.club-hero {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-6);
    border-radius: var(--radius-md);
    overflow: hidden;
    /* The one saturated surface on this screen — the mockup's deck-section
       indigo, which is a FILL, never interface colour (§3.1). */
    background: linear-gradient(135deg, var(--color-accent-900) 0%, var(--color-surface) 70%);
    box-shadow: var(--shadow-md);
}
.club-hero-eyebrow {
    margin: 0;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    letter-spacing: var(--tracking-wide);
    color: var(--color-accent-300);
}
[lang="en"] .club-hero-eyebrow { text-transform: uppercase; }
.club-hero-title {
    margin: 0;
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-title-l);
    line-height: var(--lh-snug);
    letter-spacing: var(--tracking-heading);
    color: var(--color-neutral-100);
    text-wrap: pretty;
}
.club-hero-meta {
    margin: 0;
    font-size: var(--fs-label);
    color: var(--color-neutral-300);
}
.club-hero-progress {
    height: 4px;
    margin-block-start: var(--space-4);
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-text) 14%, transparent);
    overflow: hidden;
}
.club-hero-progress-fill {
    display: block;
    height: 100%;
    background: var(--color-accent);
}
.club-hero-progress-line {
    margin: 0;
    font-size: var(--fs-caption);
    color: var(--color-neutral-400);
}
.club-hero-countdown { margin-block-start: var(--space-3); }
.club-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-block-start: var(--space-4);
}

/* ---------- More open waiting rooms ---------- */
.club-room-rail {
    display: flex;
    gap: var(--space-4);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-block-end: var(--space-2);
    scrollbar-width: none;
}
.club-room-rail::-webkit-scrollbar { display: none; }

.club-room-card {
    flex: none;
    width: 118px;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: 0;
    border: none;
    background: transparent;
    color: var(--color-text);
    cursor: pointer;
    text-align: start;
}
.club-room-cover {
    position: relative;
    display: flex;
    align-items: flex-end;
    height: 160px;
    padding: var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-neutral-800);
    background: linear-gradient(160deg, var(--color-accent-800), var(--color-accent-900));
    overflow: hidden;
}
.club-room-cover img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.club-room-cover-title {
    position: relative;
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-label);
    line-height: var(--lh-snug);
    color: var(--color-neutral-100);
    /* Sits over artwork when a cover exists, so it needs its own scrim
       rather than relying on the gradient behind it. */
    text-shadow: 0 1px 3px rgba(var(--scrim-rgb), 0.9);
}
.club-room-author {
    font-size: var(--fs-meta);
    color: var(--color-neutral-400);
}
.club-room-status {
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    letter-spacing: var(--tracking-label);
    color: var(--color-accent-200);
}
[lang="en"] .club-room-status { text-transform: uppercase; }

/* The club screen's own container layout. Previously the console's
   `.app-content-region.space-y-5` supplied the rhythm between panels; the
   club now builds several sections into ONE container, so the spacing has
   to live here or every section runs into the next. */
#bookclubContainer {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
}

/* The empty/notice block was sized for a full-height modal room. Inside the
   club's stacked sections that 32px block padding reads as a hole. */
.club-section .premiere-room-notice,
#arenaPanel .premiere-room-notice {
    padding: var(--space-6) var(--space-4);
}

/* "Suggest a prompt" is a <details>; without this it renders as a raw
   disclosure triangle flush against the section above it. */
.arena-nominate {
    margin-block-start: 0;
    padding-block-start: var(--space-6);
}
.arena-nominate summary {
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-body-s);
    color: var(--color-neutral-300);
    list-style: none;
}
.arena-nominate summary::-webkit-details-marker { display: none; }
.arena-nominate summary::before {
    content: '+';
    display: inline-block;
    inline-size: 1em;
    color: var(--color-accent);
}
.arena-nominate[open] summary::before { content: '−'; }

/* ---------- Club section tabs ----------
   The mockup's pill-tab group (the one it uses for the Shelf), centred.
   Logical properties only, so the pair mirrors under RTL on its own. */
.club-tabs {
    display: flex;
    align-self: center;
    gap: var(--space-1);
    padding: 3px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-neutral-900);
    background: var(--color-surface);
}
.club-tab {
    min-height: 34px;
    padding-inline: var(--space-6);
    border: none;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--color-neutral-500);
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-label);
    letter-spacing: var(--tracking-tight);
    cursor: pointer;
    transition: background var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.club-tab.is-active {
    background: var(--color-accent-900);
    color: var(--color-accent-200);
}
.club-tab:not(.is-active):hover { color: var(--color-neutral-300); }

/* Phase 8 audit: the Author Studio title borrowed .premiere-feed-id, which
   is correctly MONO because a feed id is a Latin code. But this element
   holds a TRANSLATED title, so in Arabic it rendered in a face with no
   Arabic glyphs. Same class, two jobs — split. */
.premiere-modal-eyebrow {
    font-family: var(--font-label);
    font-size: var(--fs-caption);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--tracking-label);
    color: var(--color-neutral-400);
}
[lang="en"] .premiere-modal-eyebrow { text-transform: uppercase; }

/* ---------- Club premiere widgets (2×2) ---------- */
.club-widget-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}
.club-widget {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-height: 168px;
    padding: var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-neutral-900);
    background: linear-gradient(150deg, var(--color-accent-800), var(--color-accent-900));
    color: var(--color-neutral-100);
    text-align: start;
    cursor: pointer;
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}
.club-widget:hover { border-color: var(--color-accent-700); }
/* Cover art sits behind the text with its own scrim, so a light cover can
   never swallow the title. */
.club-widget-art { position: absolute; inset: 0; }
.club-widget-art img { width: 100%; height: 100%; object-fit: cover; opacity: 0.5; }
.club-widget-art::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(var(--scrim-rgb), 0.25), rgba(var(--scrim-rgb), 0.88));
}
.club-widget-eyebrow {
    position: relative;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    letter-spacing: var(--tracking-label);
    color: var(--color-accent-200);
}
[lang="en"] .club-widget-eyebrow { text-transform: uppercase; }
.club-widget-title {
    position: relative;
    flex: 1;
    font-family: var(--font-ui);
    font-weight: var(--fw-medium);
    font-size: var(--fs-body-s);
    line-height: var(--lh-snug);
    text-wrap: pretty;
}
.club-widget-countdown {
    position: relative;
    font-family: var(--font-mono);
    font-size: var(--fs-body-s);
    font-weight: var(--fw-medium);
    color: var(--color-neutral-100);
}
.club-widget-status {
    position: relative;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    letter-spacing: var(--tracking-label);
    color: var(--color-accent-200);
}
[lang="en"] .club-widget-status { text-transform: uppercase; }

/* ================= DISCUSSION ROOM: identity + prompt ================= */

/* Sets the room's purpose before the first message. Without it a room with two
   messages in it reads as an empty chat rather than an invitation. */
.premiere-chat-prompt {
    margin: 0 0 var(--space-4);
    font-size: var(--fs-body-s);
    line-height: var(--lh-body);
    color: var(--color-neutral-300);
    text-align: center;
    text-wrap: balance;
}

/* Rows become avatar + bubble. `align-items: flex-start` so the avatar sits
   against the first line of a long message rather than floating at its
   centre. */
.premiere-chat-row {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
}
.premiere-chat-bubble { flex: 1; min-width: 0; }

.premiere-chat-avatar {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: 0;
    /* Hue comes from the user id, so a person keeps the same colour forever.
       Fixed S/L keeps every avatar at the same weight — no reader's initials
       shout louder than another's. */
    background: hsl(var(--avatar-hue, 260) 42% 34%);
    color: #fff;
}

.premiere-chat-name {
    margin: 0 0 2px;
    font-family: var(--font-label);
    font-size: var(--fs-micro);
    letter-spacing: var(--tracking-label);
    color: var(--color-neutral-400);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* Never letter-space Arabic (§3) — the script is connected. */
[lang="ar"] .premiere-chat-name { letter-spacing: 0; }

/* Own messages read as a reply to the room, not as another stranger: the row
   mirrors so the avatar sits on the reading-end side. */
.premiere-chat-row.is-own { flex-direction: row-reverse; }
.premiere-chat-row.is-own .premiere-chat-name { justify-content: flex-end; }
.premiere-chat-row.is-own .premiere-chat-body,
.premiere-chat-row.is-own .premiere-chat-name { text-align: end; }

/* ================= FAST PASS =================
   It was `.btn .btn-secondary .btn-sm` — the same quiet chip as "Cancel". This
   is the one paid action in the app, so it gets weight the surrounding
   controls do not, without becoming the loudest thing on the screen (§6's
   gradient budget: this IS the one gradient element in the room). */
.premiere-fastpass-btn {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px;                     /* §9 hit area, regardless of density */
    padding-inline: var(--space-6);
    border-radius: var(--radius-pill);
    border: 1px solid color-mix(in srgb, var(--color-accent) 55%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--color-accent) 26%, transparent),
        color-mix(in srgb, var(--color-accent) 10%, transparent));
    color: var(--color-accent-100, var(--text-primary));
    cursor: pointer;
    transition: transform var(--dur-micro) var(--ease-out),
                border-color var(--dur-base) var(--ease-out),
                box-shadow var(--dur-base) var(--ease-out);
}

/* The label was inheriting the button's UI font at button size, which read as
   a form control rather than an offer. Label face, tracked, sized to sit
   beside the countdown's mono without competing with it. */
.premiere-fastpass-label {
    font-family: var(--font-label);
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    line-height: 1;
}
[lang="en"] .premiere-fastpass-label { text-transform: uppercase; }
/* Arabic is connected and must never be tracked or uppercased (§3). */
[lang="ar"] .premiere-fastpass-label { letter-spacing: 0; text-transform: none; }

.premiere-fastpass-btn:hover {
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 14%, transparent);
}
.premiere-fastpass-btn:active { transform: scale(0.97); }
.premiere-fastpass-btn:disabled { cursor: default; }

/* A single sheen that crosses the button once on press. Deliberately ONE pass,
   not a loop: §10 forbids ambient shimmer, and a permanent shine on a paid
   button is the visual language of a slot machine. Inline-direction aware, so
   it travels the reading direction in both scripts. */
.premiere-fastpass-btn::after {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: -60%;
    width: 45%;
    z-index: -1;
    background: linear-gradient(90deg, transparent,
        color-mix(in srgb, var(--color-accent) 45%, transparent), transparent);
    opacity: 0;
}
[dir="rtl"] .premiere-fastpass-btn::after { transform: scaleX(-1); }

@keyframes fastpass-sheen {
    0%   { opacity: 0;   transform: translateX(0); }
    12%  { opacity: 1; }
    100% { opacity: 0;   transform: translateX(360%); }
}
[dir="rtl"] .premiere-fastpass-btn.is-working::after,
[dir="rtl"] .premiere-fastpass-btn.is-unlocked::after { animation-direction: reverse; }

.premiere-fastpass-btn.is-working::after {
    animation: fastpass-sheen 900ms var(--ease-out) infinite;
}
/* Settled state: the border and fill commit, and the sheen makes one last
   pass. This fires on success, so it reads as confirmation, not decoration. */
@keyframes fastpass-settle {
    0%   { transform: scale(0.97); }
    45%  { transform: scale(1.03); }
    100% { transform: scale(1); }
}
.premiere-fastpass-btn.is-unlocked {
    animation: fastpass-settle 420ms var(--ease-out) 1;
    border-color: var(--color-accent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--color-accent) 40%, transparent),
        color-mix(in srgb, var(--color-accent) 18%, transparent));
}
.premiere-fastpass-btn.is-unlocked::after {
    animation: fastpass-sheen 620ms var(--ease-out) 1;
}

/* Motion is a courtesy. With it suppressed the button must still show its
   states through colour and the disabled attribute alone (§6). */
@media (prefers-reduced-motion: reduce) {
    .premiere-fastpass-btn,
    .premiere-fastpass-btn::after { animation: none !important; transition: none; }
}
[data-reduce-effects="true"] .premiere-fastpass-btn,
[data-reduce-effects="true"] .premiere-fastpass-btn::after { animation: none !important; }
