/* =========================================================
   NovelSite — "Reading Room After Midnight"
   A dim, lamplit reading-room theme: deep ink surfaces, warm
   gold for actions and coins, rose for hearts and highlights.
   Signature device: a folded dog-ear corner + colored "spine"
   edge on every novel cover, and ribbon-shaped tags for badges.
   ========================================================= */

@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,600;0,9..144,700;1,9..144,500&family=Manrope:wght@400;500;600;700;800&display=swap');

:root {
    /* Ink & surfaces */
    --dark: #15121F;
    --bg: #1B1730;
    --card-bg: #241F3B;
    --card-bg-2: #2C2648;
    --border: #362F52;

    /* Text */
    --text: #F1ECE4;
    --muted: #A79FC0;

    /* Accents */
    --primary: #E8607C;   /* rose — CTAs, likes, premium */
    --gold: #E8A33D;      /* lamplight gold — coins, ratings, signature */
    --success-text: #6FC495;
    --success-bg: rgba(111, 196, 149, 0.14);
    --error-text: #FF8A93;
    --error-bg: rgba(232, 96, 107, 0.14);

    /* Type */
    --font-display: 'Fraunces', Georgia, serif;
    --font-body: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    /* Admin panel — compact, data-dense design tokens */
    --admin-radius: 8px;
    --admin-radius-sm: 5px;
    --admin-gap: 10px;
    --admin-pad-x: 10px;
    --admin-pad-y: 7px;
    --admin-font-size: 12.5px;
    --admin-shadow: 0 1px 2px rgba(0,0,0,0.25);
    --admin-shadow-raised: 0 4px 16px rgba(0,0,0,0.35);
}

/* ---------------------------------------------------------
   Site-wide Day/Night mode — dark ("Reading Room After
   Midnight") is the default signature look; this is the
   alternative a visitor can switch to, applied via a class on
   <body> so every existing component automatically re-themes
   through the same CSS variables it already uses.
   --------------------------------------------------------- */
body.light-mode {
    --dark: #2B2B3A;
    --bg: #FAF7F1;
    --card-bg: #FFFFFF;
    --card-bg-2: #F5F1E8;
    --border: #E0DCD0;
    --text: #2B2620;
    --muted: #6B6478;
    --gold: #C6841F;
    --success-text: #2F8F5C;
    --success-bg: rgba(47, 143, 92, 0.1);
    --error-text: #C6303B;
    --error-bg: rgba(198, 48, 59, 0.08);
}

/* Header and footer specifically keep their dark-mode look even
   while the rest of the site is in light mode — but only on
   mobile, where this was asked for; desktop's light mode is
   unaffected, and dark mode itself is unaffected everywhere, since
   this only ever overrides the LIGHT-mode variable values. Every
   button and link inside these two elements already colors itself
   via these same var() names, so re-declaring the values here is
   all that's needed — nothing about the buttons/links themselves
   has to change. */
@media (max-width: 780px) {
    body.light-mode .site-header,
    body.light-mode .site-footer {
        --dark: #15121F;
        --bg: #1B1730;
        --card-bg: #241F3B;
        --card-bg-2: #2C2648;
        --border: #362F52;
        --text: #F1ECE4;
        --muted: #A79FC0;
        --gold: #E8A33D;
        --success-text: #6FC495;
        --success-bg: rgba(111, 196, 149, 0.14);
        --error-text: #FF8A93;
        --error-bg: rgba(232, 96, 107, 0.14);
    }
}

* { box-sizing: border-box; margin: 0; padding: 0; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
    * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

html {
    /* overflow-x: hidden was here to fix the back-to-top button
       getting pushed off-screen on mobile — but ANY non-visible
       overflow value on an ancestor also disables position:sticky
       for every descendant, including the site header, which is
       exactly why it stopped sticking on scroll. The original bug's
       actual source (pasted chapter images with no max-width, long
       unbroken words/URLs) was fixed properly at the content level
       since then, so this broad safety net is no longer needed and
       was doing more harm than good. */
    width: 100%;
}

body {
    font-family: var(--font-body);
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    width: 100%;
}

a { color: inherit; text-decoration: none; }

.container {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 20px;
}
/* Admin/author pages need much more horizontal room than the
   reading-focused pages (a sidebar plus wide data tables) — this
   widened container is what actually fixes tables needing to
   scroll sideways on desktop. Deliberately no max-width cap at all
   now (rather than a wider-but-still-capped value) so the header
   bar and the sidebar+content area both genuinely span the full
   viewport on any screen size, not just up to some fixed point.
   $adminSectionPage (includes/header.php) already covers both
   /admin/ and /author/ paths, so this applies identically to both
   without needing separate handling. */
.admin-page-container {
    max-width: none;
}
/* The <main> wrapper specifically (not the header-inner bar above
   it, which keeps its own normal side padding) — this is what
   actually wraps the sidebar (includes/admin_nav.php's
   .admin-layout), so removing its padding here is what makes the
   sidebar sit flush against the true left edge of the browser
   window, with nothing pushing it inward. */
main.admin-page-container {
    padding: 0;
}

/* ---------------------------------------------------------
   Header
   --------------------------------------------------------- */
.sitewide-banner {
    background: var(--gold);
    color: #1B1730;
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    padding: 9px 20px;
}
.sitewide-banner-inner { max-width: 1100px; margin: 0 auto; }

.site-header {
    background: rgba(21, 18, 31, 0.85);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    color: #fff;
    position: sticky;
    top: 0;
    z-index: 10;
    border-bottom: 1px solid var(--border);
}
.site-header::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(232,163,61,0.5), transparent);
}
.header-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px;
    flex-wrap: wrap;
    gap: 10px;
    max-width: 1100px;
    margin: 0 auto;
    position: relative;
}
#theme-mode-toggle {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 15px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: border-color 0.15s ease, transform 0.15s ease;
}
#theme-mode-toggle:hover { border-color: var(--gold); transform: scale(1.08); }

.logo {
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: 700;
    font-style: italic;
    color: var(--gold);
    text-decoration: none;
    letter-spacing: 0.3px;
    text-shadow: 0 0 20px rgba(232,163,61,0.25);
    flex-shrink: 0;
}
.logo-img { max-height: 40px; display: block; }
.site-header nav { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }

/* Browse-links dropdown (desktop only) — replaces the old
   permanent second header row with Browse/Categories/Advanced
   Search/Pricing/Leaderboard behind a single toggle instead. The
   same links stay inside #site-nav for mobile's hamburger panel;
   .nav-primary-link just hides those specific duplicates from the
   desktop dropdown so they don't show twice. */
.site-header nav .nav-primary-link { display: none; }
/* .mobile-nav-columns / -col-left / -col-right collapse to
   display:contents on desktop, so their children (the left column's
   nav-primary-link items, already hidden above; the right column's
   Gossip/Login/Sign Up) flow exactly as if they were direct children
   of #site-nav itself — the same plain single-row layout as before
   this two-column mobile rework. The divider between them has no
   reason to exist there at all. */
.mobile-nav-columns, .mobile-nav-col-left, .mobile-nav-col-right { display: contents; }
.mobile-nav-divider { display: none; }
.nav-links-dropdown { position: relative; flex-shrink: 0; }
.nav-links-toggle {
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: #d8d3e6;
    font-size: 13.5px;
    font-weight: 600;
    padding: 8px 14px;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease;
}
.nav-links-toggle:hover, .nav-links-panel.open ~ .nav-links-toggle { border-color: var(--gold); color: var(--gold); }
.nav-links-panel {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    min-width: 200px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.28);
    padding: 8px;
    z-index: 60;
    flex-direction: column;
    gap: 2px;
}
.nav-links-panel.open { display: flex; }
.nav-links-panel a {
    color: var(--text);
    text-decoration: none;
    font-size: 13.5px;
    font-weight: 500;
    padding: 9px 12px;
    border-radius: 5px;
    transition: background 0.15s ease, color 0.15s ease;
}
.nav-links-panel a:hover { background: var(--card-bg-2); color: var(--gold); }
.site-header nav a {
    color: #d8d3e6;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    transition: color 0.15s ease;
    position: relative;
}
.site-header nav a:hover { color: var(--gold); }
.coins { color: var(--gold) !important; font-weight: 700; font-size: 14px; text-decoration: none; }
.online-count-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: rgba(111,196,149,0.12);
    border: 1px solid rgba(111,196,149,0.3);
    color: var(--success-text) !important;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 12.5px !important;
    font-weight: 700 !important;
    text-decoration: none;
    transition: border-color 0.15s ease;
}
.online-count-badge:hover { border-color: var(--success-text); }
.username { color: #fff !important; font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.header-avatar { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; }

.nav-btn {
    padding: 7px 16px;
    border-radius: 6px;
    font-weight: 700 !important;
    font-size: 13px !important;
    color: #fff !important;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.nav-btn:hover { transform: translateY(-1px); }
.nav-btn-login { background: var(--success-text); color: #0e2116 !important; }
.nav-btn-logout, .nav-btn-signup { background: var(--primary); }
.nav-btn-login:hover { background: #5cb583; box-shadow: 0 4px 14px rgba(111,196,149,0.35); }
.nav-btn-logout:hover, .nav-btn-signup:hover { background: #d94f6a; box-shadow: 0 4px 14px rgba(232,96,124,0.35); }
.nav-btn-gossip { background: var(--gold); color: #1B1730 !important; }
.nav-btn-gossip:hover { background: #f2b457; box-shadow: 0 4px 14px rgba(232,163,61,0.35); }
.nav-btn-account { background: #7C9CE0; color: #1B1730 !important; }
.nav-btn-account:hover { background: #93AEE8; box-shadow: 0 4px 14px rgba(124,156,224,0.35); }
/* Mobile-menu only — desktop already has its own "My Account" access
   point (the avatar + username link, .username, in the main nav row);
   showing a second one here too on desktop would just be a duplicate.
   Turned back on for mobile specifically, right by that same
   .username-hiding rule for the same reason, in the mobile nav media
   query further down. */
.nav-btn-account { display: none; }

main { min-height: 70vh; padding: 34px 0; }

h1 { font-family: var(--font-display); font-weight: 700; font-size: 32px; letter-spacing: 0.2px; }
h2 { font-family: var(--font-display); font-weight: 600; font-size: 22px; }

/* ---------------------------------------------------------
   Hero (homepage) — soft atmospheric glow behind the heading
   --------------------------------------------------------- */
.hero {
    padding: 44px 0 8px;
    animation: heroRise 0.6s ease both;
    position: relative;
}
.hero::before {
    content: '';
    position: absolute;
    top: -60px;
    left: -10%;
    width: 480px;
    height: 320px;
    background: radial-gradient(ellipse at center, rgba(232,163,61,0.14), transparent 70%);
    pointer-events: none;
    z-index: -1;
}
@keyframes heroRise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}
.hero-eyebrow {
    display: inline-block;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 14px;
}
.hero h1 {
    font-size: 44px;
    line-height: 1.15;
    max-width: 620px;
    margin-bottom: 10px;
}
.hero h1 em { color: var(--primary); font-style: italic; }
.hero-sub {
    color: var(--muted);
    font-size: 16px;
    max-width: 520px;
    margin-bottom: 24px;
}

/* ---------------------------------------------------------
   Story Studio homepage promo — a reader's invitation to
   become the author, sitting just under the hero. Echoes the
   novel-card's colored spine edge and the hero's own glow so it
   reads as part of this site rather than a bolted-on banner.
   --------------------------------------------------------- */
.studio-promo {
    margin: 8px 0 36px;
    padding: 36px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-left: 4px solid var(--primary);
    border-radius: 2px 4px 4px 2px;
    position: relative;
    overflow: hidden;
}
.studio-promo::before {
    content: '';
    position: absolute;
    top: -80px;
    right: -60px;
    width: 380px;
    height: 380px;
    background: radial-gradient(ellipse at center, rgba(232,96,124,0.12), transparent 70%);
    pointer-events: none;
}
.studio-promo-inner {
    display: flex;
    align-items: center;
    gap: 48px;
    position: relative;
}
.studio-promo-text { flex: 1.1; min-width: 280px; }
.studio-promo-text h2 {
    font-family: var(--font-display);
    font-size: 28px;
    line-height: 1.25;
    max-width: 460px;
    margin-bottom: 12px;
}
.studio-promo-text p {
    color: var(--muted);
    font-size: 15px;
    line-height: 1.6;
    max-width: 460px;
    margin-bottom: 22px;
}
.studio-promo-cta { background: var(--primary); box-shadow: 0 2px 8px rgba(232,96,124,0.2); }
.studio-promo-cta:hover { background: #EE7B93; box-shadow: 0 6px 16px rgba(232,96,124,0.35); }
.studio-promo-manuscript {
    flex: 1;
    min-width: 260px;
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 22px 24px;
}
.studio-promo-manuscript-title {
    display: block;
    font-family: var(--font-display);
    font-size: 15px;
    color: var(--gold);
    margin-bottom: 10px;
}
.studio-promo-manuscript p {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 15.5px;
    line-height: 1.75;
    color: var(--text);
}
.studio-promo-cursor {
    display: inline-block;
    width: 2px;
    height: 16px;
    margin-left: 2px;
    background: var(--gold);
    vertical-align: text-bottom;
    animation: studioCursorBlink 1s step-end infinite;
}
@keyframes studioCursorBlink { 50% { opacity: 0; } }
@media (max-width: 780px) {
    .studio-promo { padding: 24px; }
    .studio-promo-inner { flex-direction: column; align-items: stretch; gap: 24px; }
    .studio-promo-text h2 { font-size: 23px; max-width: none; }
    .studio-promo-text p { max-width: none; }
}

/* ---------------------------------------------------------
   Story Studio — creation flow (ai_studio_create.php). A
   tabbed 3-step wizard (only one step's card visible at a time)
   with a live progress bar above it. Reuses the site's existing
   .tab-bar/.tab-btn/.tab-panel system (same one novel.php's
   Chapters/Comments tabs use) rather than inventing a parallel
   one, plus a numbered badge per tab and back/next navigation
   scoped to .studio-panel so nothing else that already uses
   .chapter-ai-card or .tab-panel elsewhere is affected.
   --------------------------------------------------------- */
.studio-hero {
    text-align: center;
    max-width: 560px;
    margin: 8px auto 28px;
}
.studio-hero h1 {
    font-family: var(--font-display);
    font-size: 32px;
    margin-bottom: 8px;
}
.studio-hero p {
    color: var(--muted);
    font-size: 15px;
}
.studio-guide-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-left: 4px solid #7C9CE0;
    border-radius: 2px 8px 8px 2px;
    padding: 18px 20px;
    margin-bottom: 20px;
}
.studio-guide-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
}
.studio-guide-card h2 {
    font-family: var(--font-display);
    font-size: 17px;
    margin: 0;
}
.studio-guide-steps {
    margin: 14px 0 12px;
    padding-left: 22px;
}
.studio-guide-steps li {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text);
    margin-bottom: 10px;
}
.studio-guide-steps li:last-child { margin-bottom: 0; }
.studio-guide-card.collapsed #studio-guide-body { display: none; }
.studio-progress-wrap { margin-bottom: 18px; }
.studio-progress-track {
    height: 8px;
    border-radius: 5px;
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    overflow: hidden;
}
.studio-progress-fill {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, var(--gold), var(--primary));
    border-radius: 5px;
    transition: width 0.4s ease;
}
.studio-progress-label {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
}
.studio-tab-bar { margin-bottom: 0; }
.studio-tab { display: flex; align-items: center; gap: 8px; }
.studio-tab-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12px;
    flex-shrink: 0;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.studio-tab.active .studio-tab-num { background: var(--gold); border-color: var(--gold); color: #1B1730; }
/* A completed-but-not-currently-open step's number turns into a
   checkmark (toggled via JS in updateTabNumbers(), which adds this
   exact class) — same green already used for success messages
   site-wide, so "done" reads consistently wherever it appears. */
.studio-tab-num.done { background: var(--success-bg); border-color: var(--success-text); color: var(--success-text); }
.studio-panel { border-top-left-radius: 0; border-top-right-radius: 0; margin-top: 0; border-top: 1px solid var(--border); }
.studio-nav-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}
.studio-back-btn { background: var(--card-bg-2); color: var(--text); border: 1px solid var(--border); box-shadow: none; }
.studio-back-btn:hover { background: var(--card-bg-2); border-color: var(--gold); transform: none; box-shadow: none; }
.studio-idea-pill {
    border: 1px solid var(--border);
    background: var(--card-bg-2);
    color: var(--muted);
    border-radius: 20px;
    padding: 6px 14px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.studio-idea-pill:hover {
    border-color: var(--gold);
    color: var(--gold);
    transform: translateY(-1px);
}
/* A reader-added tag looks like the preset ones (same click-to-insert
   behavior) but with a dashed border, so it's clear at a glance which
   pills are their own vs. the built-in trending list. */
.studio-idea-pill--custom { border-style: dashed; }
.studio-textarea-lg { min-height: 150px; max-height: 340px; }
.studio-textarea-md { min-height: 96px; max-height: 220px; }
.studio-custom-idea-row {
    display: flex;
    gap: 8px;
    margin-bottom: 8px;
}
.studio-custom-idea-row input {
    flex: 1;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: #FAF7F1;
    color: #241F3B;
    font-family: var(--font-body);
    font-size: 13px;
}
.studio-custom-idea-row input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.studio-custom-idea-row input::placeholder { opacity: 0.5; }
.studio-custom-idea-row .admin-btn-sm { flex-shrink: 0; }
.studio-guide-text {
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 12px;
    line-height: 1.55;
    margin-bottom: 14px;
}
.studio-character-card {
    border-top: 2px solid var(--gold);
}
.studio-character-card:nth-of-type(2) { border-top-color: var(--primary); }
.studio-character-card:nth-of-type(n+3) { border-top-color: #7C9CE0; }
.studio-cta-row {
    text-align: center;
    margin-top: 16px;
}
.studio-cta-row .btn {
    font-size: 15.5px;
    padding: 13px 32px;
}
.studio-cta-note {
    color: var(--muted);
    font-size: 12px;
    margin-top: 10px;
}
@media (max-width: 600px) {
    .studio-hero h1 { font-size: 25px; }
    .studio-tab-bar .tab-btn { padding: 10px 12px; font-size: 13px; }
    .studio-nav-row { flex-direction: column-reverse; gap: 10px; align-items: stretch; }
    .studio-nav-row .btn, .studio-nav-row span { width: 100%; text-align: center; }
    .studio-nav-row span:empty { display: none; }
}

/* ---------------------------------------------------------
   Novel grid + card (signature: dog-ear fold + spine edge)
   --------------------------------------------------------- */
.novel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 22px;
    margin-top: 20px;
}
/* Homepage "per category" sections only (Romance, Fantasy, etc.) —
   a fixed 5 columns on desktop rather than the fluid auto-fill above,
   so a 5- or 6-novel category never leaves a single orphaned card
   wrapped alone onto its own row. Placed here, before the mobile
   media query further down, so that query's existing 2-column rule
   for .novel-grid still wins on mobile — this only overrides the
   desktop column count. */
.novel-grid--5col {
    grid-template-columns: repeat(5, 1fr);
}
@media (max-width: 780px) {
    /* Horizontal swipe carousel on mobile — desktop keeps the
       normal wrapping grid above untouched. */
    .more-like-this-grid {
        display: flex;
        overflow-x: auto;
        overflow-y: hidden;
        gap: 14px;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 6px;
    }
    .more-like-this-grid .novel-card {
        flex: 0 0 auto;
        width: 130px;
        scroll-snap-align: start;
    }
}
.novel-list-row {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 14px;
    margin-bottom: 8px;
}
.novel-list-thumb {
    width: 50px;
    height: 66px;
    object-fit: cover;
    border-radius: 4px;
    flex-shrink: 0;
}
.novel-list-thumb-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--card-bg-2);
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
}
.novel-list-info { flex: 1; min-width: 180px; }
.novel-list-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* "View More" toggle — hidden entirely on desktop, where every
   action button already shows inline as normal. display:contents on
   the extra-actions wrapper (desktop only) means it has no layout
   presence of its own — its children just flow directly into the
   parent's flex row, exactly as if this wrapper didn't exist. */
.novel-actions-more-btn { display: none; }
.novel-actions-extra { display: contents; }
.novel-card {
    position: relative;
    background: var(--card-bg);
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0,0,0,0.35);
    text-decoration: none;
    color: var(--text);
    display: block;
    transition: transform 0.22s ease, box-shadow 0.22s ease;
    /* A thin 1px reveal of the card's own background around the
       cover, so the image reads as gently inset rather than
       flush against the card edges — a soft frame, not a border. */
    padding: 2px 2px 0;
}
.novel-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 14px 30px rgba(232, 163, 61, 0.22);
}
/* Site logo watermark, bottom-right corner of the cover image
   itself — the actual DOM element (.novel-cover-watermark) is
   inserted by assets/js/cover-watermark.js, not by this rule alone,
   since an <img> can't host a visible ::before/::after and the
   cover's own height varies by its image's aspect ratio (no fixed
   height to position against from CSS alone). This rule only styles
   that inserted element; the JS decides where it goes. */
.novel-cover-wrap {
    position: relative;
    display: block;
    /* Prevents stretching to fill a taller flex row — .novel-detail
       (the individual novel page's hero layout) is display:flex with
       the browser's own default align-items:stretch, and unlike the
       plain <img> this wrapper replaces, a generic <div> DOES stretch
       to match its much-taller sibling (the title/info panel) under
       that default. That left this wrapper far taller than the cover
       image actually visible inside it, which is exactly why the
       watermark — positioned relative to the wrapper's own bottom
       edge — was appearing in the empty stretched space below the
       image instead of on the image itself. align-self overrides
       that default just for this element, keeping it sized to its
       own content (the image) regardless of its neighbor's height. */
    align-self: flex-start;
}
.novel-cover-watermark {
    position: absolute;
    right: 6px;
    bottom: 6px;
    width: 15%;
    max-width: 46px;
    min-width: 22px;
    aspect-ratio: 1 / 1;
    background-image: var(--site-logo-url, none);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    opacity: 0.5;
    pointer-events: none;
    z-index: 2;
}
.novel-cover {
    position: relative;
    width: 100%;
    /* No forced aspect-ratio here anymore — a square-format cover
       displays square, a horizontal one displays horizontal, each
       at its own actual uploaded shape. The text-only fallback
       below (no image uploaded) is the one case with nothing to
       derive a natural shape from, so it alone keeps a fixed ratio. */
    height: auto;
    background: linear-gradient(135deg, var(--primary), #6B4FA0);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 15px;
    text-align: center;
    padding: 2px;
}
img.novel-cover { display: block; }
div.novel-cover { aspect-ratio: 1/1; }
/* dog-ear fold — the signature */
.novel-cover::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0 22px 22px 0;
    border-color: transparent rgba(21,18,31,0.75) transparent transparent;
    filter: drop-shadow(-2px 2px 3px rgba(0,0,0,0.25));
}
.novel-info { padding: 12px 14px; }
.novel-title { font-family: var(--font-display); font-size: 15px; font-weight: 600; margin-bottom: 4px; line-height: 1.3; }
.novel-meta { font-size: var(--paragraph-font-size, 12px); color: var(--muted); }

/* ---------------------------------------------------------
   Breadcrumbs — Home > Novel > Chapter, etc. Button-style pills
   instead of plain underlined text links, used on the novel page,
   chapter page, and gossip topic page.
   --------------------------------------------------------- */
.breadcrumb { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; font-size: 13px; }
.breadcrumb a {
    background: var(--card-bg);
    border: 1px solid var(--border);
    padding: 5px 12px;
    border-radius: 6px;
    text-decoration: none;
    color: var(--text);
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.breadcrumb a:hover { background: var(--card-bg-2); border-color: var(--gold); color: var(--gold); }
.breadcrumb .breadcrumb-current {
    background: rgba(232,163,61,0.12);
    border: 1px solid var(--gold);
    padding: 5px 12px;
    border-radius: 6px;
    color: var(--gold);
    font-weight: 600;
}
.breadcrumb-sep { color: var(--muted); font-size: 11px; }
@media (max-width: 640px) {
    /* Smaller, tighter breadcrumb pills on mobile — the desktop
       sizing (13px text, 5px/12px padding) reads fine on a wide
       screen but crowds a phone width fast once there are 3 segments. */
    .breadcrumb { gap: 4px; font-size: 11.5px; }
    .breadcrumb a, .breadcrumb .breadcrumb-current { padding: 3px 8px; }
    /* .chapter-breadcrumb's own font-size rule (further down, applies
       everywhere, no media query) has equal CSS specificity to the
       .breadcrumb rule just above and comes later in the file — so on
       the chapter page specifically, it was silently winning the tie
       and overriding this mobile sizing entirely. Repeated here so it
       actually applies on that one page too. */
    .chapter-breadcrumb { font-size: 11.5px; }
}
/* A modest bump over the base .novel-meta size — this is the
   Home › Novel › Chapter breadcrumb line at the top of the chapter
   page, easy to under-read at the smaller default size. */
.chapter-breadcrumb { font-size: var(--paragraph-font-size, 14px); }
/* The "← Novel Title" link back to the novel page, just below the
   breadcrumb — same modest desktop bump, with a further increase on
   mobile specifically, since it's a primary navigation link readers
   tap often and the smaller default size makes it an easy miss to
   tap accurately on a phone screen. */
.chapter-back-to-novel { font-size: 14px; }
.chapter-back-to-novel a { display: inline-block; padding: 2px 0; }
@media (max-width: 780px) {
    .chapter-back-to-novel { font-size: 16px; }
}

/* ---------------------------------------------------------
   Categories
   --------------------------------------------------------- */
/* ---------------------------------------------------------
   Homepage Pricing section — Subscription / AI Tokens / Coins.
   A real grid instead of flexbox specifically so a 3rd card that
   wraps onto its own row (common: 2 fit per row, 1 left over, or
   AI features disabled leaving just 2 cards) sits at the same width
   as the others instead of flex's own default of stretching a lone
   wrapped item to fill the entire row.
   --------------------------------------------------------- */
.pricing-cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
    align-items: stretch;
}
.pricing-cards-grid .price-card { display: flex; flex-direction: column; }
.pricing-cards-grid .price-card > a.btn { margin-top: auto; align-self: flex-start; }

.category-section { margin-top: 28px; }
.category-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.category-pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    padding: 9px 20px 9px 22px;
    border-radius: 3px 20px 20px 3px;
    text-decoration: none;
    color: var(--text);
    font-weight: 600;
    font-size: 13px;
    transition: border-color 0.15s ease, color 0.15s ease, transform 0.2s ease, box-shadow 0.2s ease;
    /* Entrance animation — see .category-pill.in-view below. Starts
       invisible/settled-down and each pill rises into place with a
       slight stagger (nth-child delay), one deliberate moment as the
       section scrolls into view, not a constant idle animation. */
    opacity: 0;
    transform: translateY(10px);
}
.category-pill-icon { font-size: 15px; line-height: 1; }
.category-pill::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: var(--gold);
    border-radius: 3px 0 0 3px;
}
.category-pill:nth-child(3n+2)::before { background: var(--primary); }
.category-pill:nth-child(3n+3)::before { background: #7C9CE0; }
.category-pill:hover {
    border-color: var(--gold);
    color: var(--gold);
    transform: translateY(-3px) scale(1.03);
    box-shadow: 0 6px 16px rgba(232,163,61,0.2);
}
.category-pill:hover .category-pill-icon { animation: categoryIconPop 0.4s ease; }
@keyframes categoryIconPop {
    0% { transform: scale(1) rotate(0deg); }
    40% { transform: scale(1.3) rotate(-8deg); }
    100% { transform: scale(1) rotate(0deg); }
}
.category-pill--all { background: var(--dark); color: #fff; }
.category-pill--all::before { background: #fff; opacity: 0.6; }
.category-pill--all:hover { color: var(--gold); border-color: var(--gold); }

/* The actual reveal — a small IntersectionObserver in index.php adds
   .in-view to #home-category-grid the first time it scrolls into
   view, and this staggers each pill's rise-and-fade-in slightly
   after the last, left to right, rather than all of them landing at
   once. Runs once per page load, not every time it's scrolled past. */
.category-grid.in-view .category-pill { opacity: 1; transform: translateY(0); }
.category-grid.in-view .category-pill:nth-child(1) { transition-delay: 0.03s; }
.category-grid.in-view .category-pill:nth-child(2) { transition-delay: 0.06s; }
.category-grid.in-view .category-pill:nth-child(3) { transition-delay: 0.09s; }
.category-grid.in-view .category-pill:nth-child(4) { transition-delay: 0.12s; }
.category-grid.in-view .category-pill:nth-child(5) { transition-delay: 0.15s; }
.category-grid.in-view .category-pill:nth-child(6) { transition-delay: 0.18s; }
.category-grid.in-view .category-pill:nth-child(7) { transition-delay: 0.21s; }
.category-grid.in-view .category-pill:nth-child(8) { transition-delay: 0.24s; }
.category-grid.in-view .category-pill:nth-child(9) { transition-delay: 0.27s; }
.category-grid.in-view .category-pill:nth-child(10) { transition-delay: 0.3s; }
.category-grid.in-view .category-pill:nth-child(11) { transition-delay: 0.33s; }
/* Respects a reduced-motion preference by just showing the pills
   immediately rather than forcing the rise/fade on someone who's
   asked their system to minimize animation. */
@media (prefers-reduced-motion: reduce) {
    .category-pill { opacity: 1; transform: none; transition: none; }
}

/* ---------------------------------------------------------
   /categories page — icon-led cards, distinct from the small
   homepage pills above.
   --------------------------------------------------------- */
.category-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 16px;
    margin-top: 20px;
}
.category-icon-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 26px 12px 20px;
    text-decoration: none;
    color: var(--text);
    transition: border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
}
.category-icon-card:hover {
    border-color: var(--gold);
    transform: translateY(-4px);
    box-shadow: 0 8px 20px rgba(232,163,61,0.18);
}
.category-icon-card-icon { font-size: 34px; line-height: 1; margin-bottom: 4px; }
.category-icon-card-name { font-weight: 700; font-size: 14.5px; }
.category-icon-card-count { font-size: 12px; color: var(--muted); }

/* ---------------------------------------------------------
   Forms & cards
   --------------------------------------------------------- */
.form-card {
    max-width: 420px;
    margin: 40px auto;
    background: var(--card-bg);
    padding: 30px;
    border-radius: 10px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.35);
    border: 1px solid var(--border);
    border-top: 2px solid var(--gold);
    animation: formCardRise 0.3s ease both;
}

/* Reading Streak / Weekly Goal / Invite Friends / Wallet cards on
   the account page — 2 columns on desktop so they sit side by
   side instead of stacking one under another; back to a single
   column on narrow screens. Cards inside deliberately override
   .form-card's own max-width/auto-margin, which would otherwise
   cap each one at 420px and center it oddly within its grid cell
   instead of filling it. */
.account-stats-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    margin-top: 20px;
}
.account-stats-grid .form-card {
    max-width: none;
    margin: 0;
}
@media (max-width: 780px) {
    .account-stats-grid { grid-template-columns: 1fr; }
}

.add-novel-grid {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 28px;
    align-items: start;
}
@media (max-width: 800px) {
    .add-novel-grid { grid-template-columns: 1fr; }
}
@keyframes formCardRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.form-card h1 { font-size: 24px; margin-bottom: 20px; }

/* Dedicated to the AI reading-page sections (Continue With AI,
   Generate For Fun, Ask About This Story) — .form-card itself is
   built for centered, standalone forms (margin: 40px auto, capped
   at 420px, meant for a login/signup page), which is the wrong
   shape for content sections meant to sit in the normal reading
   flow, left-aligned and stacked one after another. Reusing it here
   caused the auto-centering and narrow cap to make each card read
   as visually nested inside the one before it rather than as a
   clean, separate section. This class fixes that: no auto-centering,
   a reading-column-appropriate width, a clear heading, and spacing
   that actually separates each card instead of letting them visually
   run together. */
.chapter-ai-card {
    max-width: 640px;
    margin: 18px 0 0;
    background: var(--card-bg);
    padding: 20px;
    border-radius: 10px;
    border: 1px solid var(--border);
    border-top: 2px solid var(--gold);
}
/* Same card look, but full width — for the one place this is used
   to match a genuinely full-width sibling (the novel page's Synopsis
   text above it) rather than sitting as its own compact widget like
   every other .chapter-ai-card usage (Continue With AI, Ask Baxter's
   AI, Story Studio steps) is deliberately meant to. */
.chapter-ai-card--full { max-width: none; }
.chapter-ai-card h3 {
    margin: 0 0 10px;
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
}
.chapter-ai-card .form-group { margin-bottom: 14px; }
.chapter-ai-card .form-group:last-child { margin-bottom: 0; }
.ai-trigger-row {
    display: flex;
    gap: 8px;
    margin-top: 16px;
}
.ai-trigger-row .btn { flex: 1; white-space: nowrap; }
/* These three buttons follow the 6 reading themes set in Reader
   Settings (light/dark/gray/sepia/night/forest), not the site's own
   separate light/dark mode toggle and not .btn's own default gold —
   --card-bg-2/--text/--border are the specific variables the reading
   theme system actually redefines per theme (see
   body.chapter-reading-page.theme-* above), so tying these buttons
   to those instead of .btn's own defaults is what makes them
   genuinely change color when the reader picks a different theme. */
.ai-trigger-row .btn {
    background: var(--card-bg-2);
    color: var(--text);
    border: 1px solid var(--border);
}
/* The forms inside these same three popups (word count/mode/how-many
   dropdowns, the question box, the character search) — same reading-
   theme variables as the trigger buttons above, scoped specifically
   to these three modals rather than every form site-wide, since a
   reading theme has no business changing what login or signup looks
   like elsewhere on the site. */
body.chapter-reading-page #continue-ai-modal .form-group input,
body.chapter-reading-page #continue-ai-modal .form-group select,
body.chapter-reading-page #ask-ai-modal .form-group input,
body.chapter-reading-page #ask-ai-modal .form-group select,
body.chapter-reading-page #characters-modal .modal-search {
    background: var(--card-bg-2);
    color: var(--text);
    border: 1px solid var(--border);
}
@media (max-width: 600px) {
    /* Stacked, not side-by-side, on a narrow phone screen — three
       buttons squeezed into one row there get too cramped to read
       or tap reliably. */
    .ai-trigger-row { flex-direction: column; }
}
@media (max-width: 600px) {
    /* Manage Novels, mobile only: just Manage Chapters and Edit
       Details show by default — export/import, hide/unhide, the
       comments button, and delete are real actions someone taps
       far less often, and cramming all seven onto a narrow phone
       screen made even the two everyday actions hard to find and
       tap accurately. "View More" reveals the rest in place; the
       toggle itself never appears on desktop, where there's already
       room for everything at once. */
    .novel-actions-more-btn {
        display: inline-flex;
        align-items: center;
        background: none;
        border: 1px solid var(--border);
        border-radius: var(--admin-radius-sm, 5px);
        color: var(--muted);
        font-size: 12px;
        font-weight: 700;
        padding: 6px 10px;
        cursor: pointer;
    }
    .novel-actions-more-btn:hover { color: var(--gold); border-color: var(--gold); }
    .novel-actions-extra { display: none; width: 100%; gap: 6px; flex-wrap: wrap; align-items: center; }
    .novel-actions-extra.expanded { display: flex; }
}
@media (max-width: 600px) {
    .chapter-ai-card { padding: 16px; margin-top: 14px; border-radius: 8px; }
    .chapter-ai-card h3 { font-size: 15px; }
    /* Ask About This Story's input+button row: side-by-side on
       desktop reads fine, but on a narrow phone screen a maxlength-
       300 text input squeezed next to a button overflows or gets
       too cramped to actually type in — stacked full-width rows
       instead. */
    .chapter-ai-card .form-group[style*="display:flex"] { flex-direction: column; }
    .chapter-ai-card .form-group[style*="display:flex"] input,
    .chapter-ai-card .form-group[style*="display:flex"] button { width: 100%; }
}

.form-group { margin-bottom: 16px; }
.form-group label { display: block; font-size: 13px; font-weight: 700; margin-bottom: 6px; color: var(--muted); }
.form-group input, .form-group select, .form-group textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 14px;
    background: #FAF7F1;
    color: #241F3B;
    font-family: var(--font-body);
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
    outline: 2px solid var(--gold);
    outline-offset: 1px;
}
.form-group input::placeholder, .form-group textarea::placeholder {
    opacity: 0.5;
}
/* Comment / reply / edit / gossip message boxes: the textarea-
   autogrow.js script grows these as you type, but the native
   corner-drag handle is kept for anyone who wants a specific size
   by hand — this just makes that handle bigger and easier to spot
   on a touch screen instead of the default hairline-thin one.
   ::-webkit-resizer only affects WebKit/Blink browsers (Chrome,
   Safari, Edge — effectively all mobile browsers); other browsers
   fall back to their own default handle, still fully functional. */
.js-autogrow {
    resize: vertical;
    overflow: hidden;
}
.js-autogrow::-webkit-resizer {
    /* Rose instead of gold — the gold used here previously blends
       into this exact page's gold card border and gold buttons
       right next to it (see the screenshot: an orange-bordered,
       cream textarea sitting under an orange "Post Comment" button —
       a gold handle all but disappears against that). Rose is the
       one accent color on this page it never blends with. */
    background-color: var(--primary);
    background-image: linear-gradient(135deg,
        transparent 0 30%, #FFFFFF 30% 42%,
        transparent 42% 58%, #FFFFFF 58% 70%,
        transparent 70% 86%, #FFFFFF 86% 98%,
        transparent 98%);
    background-size: 16px 16px;
    background-repeat: no-repeat;
    background-position: bottom right;
    border-radius: 0 0 5px 0;
}
/* The actual grabbable size of a textarea's resize corner is set by
   the browser itself, not fully overridable from CSS — this can
   only make what paints inside it bolder, not force the real hit
   area larger. Solid color fill (not thin stripes on a transparent
   background) is what actually reads as "a handle" rather than a
   decorative corner at small mobile sizes. */
@media (max-width: 600px) {
    .js-autogrow::-webkit-resizer {
        background-size: 20px 20px;
        border-radius: 0 0 6px 0;
    }
}
.btn {
    display: inline-block;
    background: var(--gold);
    color: #1B1730;
    border: none;
    padding: 11px 22px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
    font-family: var(--font-body);
    box-shadow: 0 2px 8px rgba(232,163,61,0.15);
}
.btn:hover { background: #F2B457; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(232,163,61,0.3); }
/* Secondary "View More" style toggle button — a muted variant of
   .btn for panels that shouldn't visually compete with the primary
   gold call-to-action buttons on the same page. .btn's default text
   color is tuned for a gold background, so it needs its own color
   (not just background) here, on hover too, or the text goes near-
   invisible against a dark button. */
.ai-extras-toggle-btn {
    background: var(--card-bg-2);
    color: var(--text);
    border: 1px solid var(--border);
    box-shadow: none;
}
.ai-extras-toggle-btn:hover {
    background: var(--card-bg-2);
    color: var(--gold);
    transform: none;
    box-shadow: none;
}
.btn:active { transform: translateY(0); }
.error-box {
    background: var(--error-bg);
    color: var(--error-text);
    padding: 10px 14px;
    border-radius: 6px;
    font-size: var(--paragraph-font-size, 13px);
    margin-bottom: 16px;
    border: 1px solid rgba(255,138,147,0.25);
}
.success-box {
    background: var(--success-bg);
    color: var(--success-text);
    padding: 10px 14px;
    border-radius: 6px;
    font-size: var(--paragraph-font-size, 13px);
    margin-bottom: 16px;
    border: 1px solid rgba(111,196,149,0.25);
}

/* ---------------------------------------------------------
   Wallet & Subscription page — summary card + "already
   subscribed" callout, so both read as proper sections instead
   of plain inline text.
   --------------------------------------------------------- */
.wallet-summary-card {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
    background: linear-gradient(135deg, rgba(232,163,61,0.14), rgba(232,96,124,0.1));
    border: 1px solid rgba(232,163,61,0.3);
    border-radius: 10px;
    padding: 20px 24px;
    margin-top: 16px;
}
.wallet-summary-item { flex: 1; min-width: 180px; }
.wallet-summary-label { display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--muted); margin-bottom: 6px; }
.wallet-summary-value { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--gold); }
.wallet-summary-unit { font-family: var(--font-body); font-size: 13px; font-weight: 500; color: var(--muted); margin-left: 6px; }

/* ---------------------------------------------------------
   Pricing page — intro message and the bottom call-to-action
   both get their own proper section instead of floating as
   plain inline text.
   --------------------------------------------------------- */
.pricing-intro-box {
    background: linear-gradient(135deg, rgba(232,163,61,0.14), rgba(232,96,124,0.1));
    border: 1px solid rgba(232,163,61,0.3);
    border-radius: 10px;
    padding: 16px 20px;
    margin-top: 16px;
}
.pricing-intro-box p { font-size: 14.5px; line-height: 1.6; margin: 0; }
.pricing-intro-box a { color: var(--gold); font-weight: 600; }

.pricing-cta-section {
    margin-top: 40px;
    padding: 28px 20px;
    text-align: center;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 10px;
}
.pricing-cta-section p { font-size: 15px; color: var(--muted); margin-bottom: 14px; }
.pricing-cta-section .btn { display: inline-block; }

.already-subscribed-box {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    background: var(--success-bg);
    border: 1px solid rgba(111,196,149,0.3);
    border-radius: 10px;
    padding: 18px 20px;
}
.already-subscribed-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--success-text);
    color: #0e2116;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    font-size: 16px;
}
.already-subscribed-box strong:first-child { display: block; font-size: 15px; margin-bottom: 4px; color: var(--success-text); }
.already-subscribed-box p { font-size: 13.5px; color: var(--text); line-height: 1.6; margin: 0; }

/* ---------------------------------------------------------
   Novel detail
   --------------------------------------------------------- */
/* A real 2-row grid, not stacked flex blocks — cover spans both rows
   in column 1, title/meta/rating sit in row 1 of column 2, and
   action buttons + share sit in row 2 of column 2, directly under
   the rating rather than under wherever the (much taller) cover
   happens to end. That mismatch — actions dropping to below the
   cover's bottom edge instead of right under the rating — is exactly
   what a stacked-flex version of this layout kept getting wrong. */
.novel-detail {
    display: grid;
    grid-template-columns: 320px 1fr;
    grid-template-rows: auto 1fr;
    column-gap: 28px;
    row-gap: 4px;
    margin-bottom: 30px;
}
.novel-detail .novel-cover { grid-row: 1 / 3; grid-column: 1; width: 320px; border-radius: 2px 4px 4px 2px; border-left: 4px solid var(--gold); }
/* cover-watermark.js wraps every .novel-cover in .novel-cover-wrap at
   runtime — once that happens, THAT wrapper is the actual direct
   grid child, not .novel-cover itself, so it needs the same grid
   placement or the cover silently falls out of the grid the moment
   the watermark script runs. */
.novel-detail .novel-cover-wrap { grid-row: 1 / 3; grid-column: 1; }
.novel-detail-info { grid-row: 1; grid-column: 2; min-width: 0; }
.novel-detail-info h1 { font-size: 34px; margin-bottom: 10px; }
/* Action buttons (Like/Favorite/Listen/Report) and the Share section
   both live here — a full-width block below the cover+title row,
   not squeezed into the narrow info column beside the cover. Was
   previously nested inside that column; moved out specifically so
   it can span the whole page width and, on mobile, actually start
   flush from the screen's left edge. */
/* Aligned with the info column (starts where the cover's 260px width
   + 28px gap ends), matching exactly where this content sat before
   it was pulled out into its own full-width block — that move was
   specifically for mobile (see the max-width:640px override below,
   which resets this back to 0 there); it shouldn't have changed how
   desktop looked at all. */
.novel-detail-actions { grid-row: 2; grid-column: 2; align-self: start; margin-top: 4px; }
.chapter-list { list-style: none; margin-top: 20px; }
/* A fixed, scrollable area for the chapter list on the novel
   page — so the page's overall height stays sane and predictable
   even with "100 per page" or "View All" selected, instead of the
   page potentially growing to list hundreds of chapters inline. */
.chapter-list-fixed-area {
    max-height: 620px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card-bg);
    padding: 10px;
}
.chapter-list-fixed-area::-webkit-scrollbar { width: 8px; }
.chapter-list-fixed-area::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.chapter-list-fixed-area::-webkit-scrollbar-thumb:hover { background: var(--gold); }
.chapter-list li {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 8px;
}
.chapter-list a:hover { color: var(--gold); }
/* A dedicated row style for forum topics — the shared .chapter-list
   class was designed for a single-line chapter title and never had
   real spacing for a title, a separate meta line, and admin action
   links stacked below it, which is why topics rendered cramped with
   everything running together on one line. */
.gossip-topic-row {
    display: block;
    padding: 14px 16px;
    text-decoration: none;
    color: inherit;
}
.gossip-topic-row:hover { background: var(--card-bg-2); }
.gossip-topic-title {
    display: block;
    font-size: 15px;
    font-weight: 700;
    margin-bottom: 6px;
}
.gossip-topic-meta {
    display: block;
    font-size: 12.5px;
}
.gossip-topic-admin-controls {
    display: flex;
    gap: 14px;
    padding: 0 16px 12px;
    font-size: 12px;
    border-top: 1px solid var(--border);
    margin-top: 2px;
    padding-top: 10px;
}
.lock {
    display: inline-block;
    color: #1B1730;
    background: var(--gold);
    font-size: 11px;
    font-weight: 700;
    padding: 3px 10px 3px 14px;
    border-radius: 2px 10px 10px 2px;
    position: relative;
    white-space: nowrap;
    margin-left: 8px;
}
.free-badge {
    display: inline-block;
    color: var(--success-text);
    background: none;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.3px;
    white-space: nowrap;
    margin-left: 8px;
}
.listen-icon { padding: 0 14px; font-size: 16px; text-decoration: none; flex-shrink: 0; transition: transform 0.15s ease; }
.listen-icon:hover { transform: scale(1.15); }

/* ---------------------------------------------------------
   Chapter reader
   --------------------------------------------------------- */
.reader-box {
    background: #FBF7EF;
    color: #2B2B3A;
    padding: 34px;
    border-radius: 10px;
    max-width: 100%;
    margin: 0 auto;
    font-size: 17px;
    line-height: 1.9;
    box-shadow: 0 4px 20px rgba(0,0,0,0.3);
    /* No overflow-x:hidden here — like html/body, it would silently
       break position:sticky for the toolbar below (any non-visible
       overflow on an ancestor disables sticky for descendants).
       The original overflow risk (a pasted image or long word
       spilling past the edge) is already handled at the content
       level by #reader-content's own max-width/word-wrap rules. */
}
.reader-box h1 { font-size: 23px; margin-bottom: 20px; color: #2B2B3A; }
.chapter-ad-slot { margin: 20px 0; text-align: center; overflow: hidden; }
#reader-content {
    /* Constrains whatever admin pastes into the chapter editor —
       an image with no width set, or one long unbroken word/URL,
       would otherwise overflow this box horizontally and spill
       past the right edge instead of resizing or wrapping to fit. */
    overflow-wrap: break-word;
    word-wrap: break-word;
    max-width: 100%;
}
#reader-content img, #reader-content video, #reader-content iframe {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 16px auto;
}
#reader-content table { max-width: 100%; display: block; overflow-x: auto; }
#reader-content p { margin-bottom: 1.1em; }
#reader-content p:last-child { margin-bottom: 0; }

/* Shared styling for any area that renders admin/author-authored
   rich-text HTML (Quill-generated) for display — static pages,
   novel synopses, and anywhere else editor content shows up
   read-only. Without this, headings render the same size as body
   text, paragraphs run together with no spacing, lists lose their
   bullets/numbers visually, and links look like plain text —
   exactly the "not good looking" complaint this fixes. */
.rich-content { line-height: 1.8; }
.rich-content h1, .rich-content h2, .rich-content h3,
.rich-content h4, .rich-content h5, .rich-content h6 {
    font-family: var(--font-display);
    margin: 1.2em 0 0.5em;
    line-height: 1.3;
    color: var(--text);
}
.rich-content h1 { font-size: 26px; }
.rich-content h2 { font-size: 22px; }
.rich-content h3 { font-size: 19px; }
.rich-content h4, .rich-content h5, .rich-content h6 { font-size: 16px; }
.rich-content p { margin-bottom: 1em; }
.rich-content p:last-child { margin-bottom: 0; }
.rich-content ul, .rich-content ol { margin: 0 0 1em; padding-left: 1.6em; }
.rich-content li { margin-bottom: 0.4em; }
.rich-content a { color: var(--gold); text-decoration: underline; }
.rich-content a:hover { color: var(--primary); }
.rich-content blockquote {
    margin: 1em 0;
    padding: 10px 18px;
    border-left: 3px solid var(--gold);
    background: var(--card-bg-2);
    color: var(--muted);
    font-style: italic;
}
.rich-content img { max-width: 100%; height: auto; border-radius: 6px; margin: 0.8em 0; display: block; }
.rich-content table { width: 100%; border-collapse: collapse; margin: 1em 0; }
.rich-content table td, .rich-content table th {
    border: 1px solid var(--border);
    padding: 8px 12px;
    text-align: left;
}
.rich-content table th { background: var(--card-bg-2); font-weight: 700; }
.rich-content strong { font-weight: 700; }
.rich-content em { font-style: italic; }
.reader-box .novel-meta a { color: var(--primary); text-decoration: none; }
.reader-nav {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    align-items: center;
    gap: 10px;
    margin-top: 30px;
}
.reader-nav .btn, .reader-nav .toolbar-btn {
    width: 100%;
    text-align: center;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
@media (max-width: 480px) {
    /* Very narrow phones — smaller text and padding so all three
       fit comfortably on the one line rather than getting cramped. */
    .reader-nav { gap: 6px; }
    .reader-nav .btn, .reader-nav .toolbar-btn { font-size: 12.5px; padding-left: 8px; padding-right: 8px; }
}
.reader-toolbar {
    display: flex;
    gap: 10px;
    margin-bottom: 18px;
    flex-wrap: wrap;
    position: sticky;
    top: var(--header-height, 64px);
    z-index: 8;
    background: #FBF7EF;
    padding: 10px 0;
    margin-top: -4px;
}
.toolbar-group-primary, .toolbar-group-secondary { display: contents; }

@media (max-width: 780px) {
    /* Mobile only — desktop keeps all 5 buttons together in the one
       sticky row above, completely untouched. On mobile: Like/
       Bookmark/Report stay in that same sticky-below-header bar as
       an even 3-column row, while Chapter List/Listen move out into
       their own bar fixed to the very bottom of the screen — both
       laid out to exactly fit the viewport width rather than wrap
       or overflow. */
    .toolbar-group-primary, .toolbar-group-secondary { display: flex; }
    .toolbar-group-secondary {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 8px;
        width: 100%;
    }
    .toolbar-group-secondary .toolbar-btn {
        width: 100%;
        justify-content: center;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .toolbar-group-primary {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 30;
        display: grid;
        grid-template-columns: repeat(5, 1fr);
        gap: 0;
        background: #FBF7EF;
        border-top: 1px solid rgba(0,0,0,0.12);
        box-shadow: 0 -4px 14px rgba(0,0,0,0.15);
        padding: 10px max(10px, env(safe-area-inset-left)) calc(10px + env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-right));
        transition: transform 0.2s ease;
    }
    .toolbar-group-primary.toolbar-hidden { transform: translateY(100%); }
    .toolbar-group-primary .toolbar-btn {
        width: 100%;
        justify-content: center;
        border-radius: 8px;
    }
    /* Icon-only — Prev/Chapter List/Next/Listen/Settings all fit in
       one row this way; text labels wouldn't fit five across at
       this width. */
    .toolbar-icon-btn { font-size: 30px; padding: 12px 0; }
    .toolbar-icon-btn .toolbar-btn-label { display: none; }
    /* Listen and Settings specifically: icon AND its name together,
       not one replacing the other the way Previous/Chapter List/Next
       do just below — stacked (icon above, label below) rather than
       side by side, since side-by-side text would just wrap awkwardly
       in a button this narrow; stacked fits cleanly at this width,
       same idea as a typical mobile app's bottom tab bar. */
    .toolbar-icon-plus-label {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        font-size: 16px;
        padding: 8px 2px;
        line-height: 1;
    }
    .toolbar-icon-plus-label .toolbar-btn-label { display: inline; font-size: 10.5px; margin-left: 0; font-weight: 600; }
    /* Previous/Chapter List/Next specifically show as text instead
       of an icon here, unlike Listen/Settings which stay icon-only —
       overrides the two rules just above, for these three buttons
       only. Kept compact (small font, no padding increase) so all
       five buttons still comfortably fit across in one row at this
       width, the same constraint the icon-only approach above was
       solving for in the first place. */
    .toolbar-text-on-mobile { font-size: 12px; padding: 10px 2px; }
    .toolbar-text-on-mobile .toolbar-btn-icon { display: none; }
    .toolbar-text-on-mobile .toolbar-btn-label { display: inline; }
    /* This bar's own Settings icon replaces the floating one on
       mobile — both exist in the DOM and open the identical panel
       (see the shared toggleSettingsPanel() function), so hiding
       one here is purely which button is visible, not a second,
       separate settings feature to keep in sync. */
    .settings-fab { display: none; }
    /* Reappears specifically once the bottom bar itself has hidden
       (near the footer — see the IntersectionObserver in
       chapter.php that toggles this body class) — the two states
       are mutually exclusive by design, so there's always exactly
       one way to reach Settings on screen at any given moment, never
       zero and never both at once. */
    body.mobile-bottom-bar-hidden .settings-fab { display: block; }
    /* The sticky top bar no longer needs to reserve space for the
       buttons that moved to the bottom bar, and the page itself
       needs bottom padding so the fixed bar never covers the last
       lines of the chapter or the reader-nav buttons beneath it. */
    .reader-toolbar { padding-bottom: 10px; }
    #reader-box { padding-bottom: 92px; }
    /* This page's own back-to-top button sits at exactly the same
       bottom-right corner the 5-icon bar's rightmost icon (Reading
       Settings) occupies, and above it (higher z-index) — silently
       intercepting every tap meant for that icon once scrolling
       makes the back-to-top button appear. Pushed up above the bar
       here, scoped to this page specifically via body.chapter-
       reading-page so every other page's back-to-top position is
       untouched. */
    body.chapter-reading-page #back-to-top-btn { bottom: 90px; }
    /* Rounded corners flush against the screen edge no longer make
       visual sense once #reader-full-bleed (chapter.php) removes
       everything inset around this card on mobile. */
    /* .container's own max-width/padding/centering is the entire
       reason anything inside it (including .reader-box) was ever
       constrained narrower than the screen in the first place —
       .site-header achieves its own full width the same way,
       simply by never being wrapped in .container at all. Removing
       those same three properties here, specifically for this page
       on mobile, means .container (and everything inside it,
       .reader-box included) is now genuinely, natively as wide as
       the screen — no calculated offset, no vw units, nothing that
       depends on guessing around a scrollbar. Scoped to
       #main-content specifically (the actual element this class
       applies to here — see includes/header.php) so no other page
       is affected. */
    body.chapter-reading-page #main-content.container {
        max-width: none;
        padding: 0;
        margin: 0;
    }
    /* The breadcrumb and the (conditionally-shown) scheduled-publish
       notice both sit directly inside #main-content, before
       .reader-box even starts — unlike .reader-box (its own 34px
       padding) and the comments section further down (.form-card's
       own independent padding), these two never had any padding of
       their own; they were only ever getting it by inheriting
       #main-content's, which the rule just above now removes
       entirely. Restored here specifically for just these two, so
       they don't end up flush against the screen edge the way
       #main-content's own content otherwise now correctly does. */
    body.chapter-reading-page .chapter-breadcrumb,
    body.chapter-reading-page #main-content > .error-box {
        padding-left: 20px;
        padding-right: 20px;
    }
    body.chapter-reading-page .reader-box { border-radius: 0; }
}
.toolbar-btn {
    background: #F0E9DA;
    border: 1px solid #E0D6C0;
    padding: 8px 14px;
    border-radius: 6px;
    font-size: 13px;
    cursor: pointer;
    color: #2B2B3A;
    font-family: var(--font-body);
    font-weight: 600;
}
.toolbar-btn:hover { background: #E5DAC4; }
/* The non-clickable <span> fallback shown instead of a real link
   when there's no previous/next chapter to go to (e.g. the very
   first or last chapter of a novel) — this rule was previously only
   defined inside the mobile media query above, so on desktop this
   fallback had no distinct styling at all and looked exactly like a
   real, active button despite doing nothing when clicked. Defined
   here, outside any media query, so the same visibly-disabled look
   applies consistently on every screen size. */
.toolbar-btn-disabled { opacity: 0.3; pointer-events: none; }
/* Desktop only (hidden on mobile within the 780px breakpoint above,
   where all 5 icons need to stay icon-only to fit one row) — gives
   the Listen/Previous/Chapter List/Next/Settings buttons a visible
   name alongside their icon, rather than relying on a hover tooltip
   alone to say what each one does. */
.toolbar-btn-label { margin-left: 5px; }

/* The locked-chapter preview — first several paragraphs read clean
   and fully visible, so a reader gets a genuine, undistorted taste
   of the chapter, with only the last stretch of it fading smoothly
   toward transparent right before the lock panel takes over. A mask
   gradient over the whole preview block does this in one continuous
   fade rather than needing to know exactly which paragraph is which
   — full opacity for roughly the first half to two-thirds of the
   preview, fading out over the remainder. */
.chapter-preview-fade {
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 96%);
    mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 96%);
}

/* Locked chapter panel — wax-seal styling */
.lock-panel {
    margin-top: 10px;
    padding: 34px 20px;
    text-align: center;
    background: linear-gradient(180deg, rgba(251,247,239,0) 0%, #F3ECDC 15%, #F3ECDC 100%);
    border-top: 1px solid #E0D6C0;
    border-radius: 0 0 10px 10px;
}
.lock-icon {
    font-size: 26px;
    width: 54px;
    height: 54px;
    line-height: 54px;
    border-radius: 50%;
    background: var(--primary);
    color: #fff;
    margin: 0 auto 14px;
    box-shadow: 0 3px 10px rgba(232,96,124,0.4);
}
.lock-title { font-family: var(--font-display); font-size: 19px; font-weight: 600; margin-bottom: 6px; color: #2B2B3A; }
.lock-sub { font-size: 14px; color: #6b6478; max-width: 420px; margin: 0 auto 18px; }
.lock-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.btn-outline { background: transparent; border: 1px solid var(--primary); color: var(--primary); }
.btn-outline:hover { background: var(--primary); color: #fff; }
.latest-chapter-notice {
    margin-top: 20px;
    padding: 16px;
    text-align: center;
    background: rgba(232,163,61,0.12);
    border: 1px solid rgba(180,130,30,0.3);
    border-radius: 8px;
    color: #2B2B3A;
}
/* The reader has separate Light/Dark/Gray reading themes — this
   notice's text color was hardcoded for the light paper theme
   only, making it unreadable (dark text on a dark background)
   whenever a reader picked Dark mode. Now it follows suit. */
.reader-box.theme-dark .latest-chapter-notice {
    background: rgba(232,163,61,0.16);
    border-color: rgba(232,163,61,0.4);
    color: #e4e4ef;
}
.reader-box.theme-gray .latest-chapter-notice {
    background: rgba(232,163,61,0.18);
    border-color: rgba(180,130,30,0.4);
    color: #262a2e;
}

/* ---------------------------------------------------------
   Batched import progress bar
   --------------------------------------------------------- */
.import-progress-bar-track {
    width: 100%;
    height: 16px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}
.import-progress-bar-fill {
    height: 100%;
    background: var(--gold);
    transition: width 0.2s ease;
}

/* Reading themes (user-selected — independent of site chrome) */
/* Reading themes extended to the whole page, not just the reading
   card — breadcrumb, comments, and the overall screen background
   now follow whichever of the 6 reading themes is active too (see
   chapter.php's applyTheme(), which now applies this same class to
   <body> as well as .reader-box). This is deliberately what
   controls appearance on this page — the site's separate day/night
   mode toggle (body.light-mode, above) is meant to have no effect
   here at all, and two classes (body.chapter-reading-page.theme-*)
   naturally outrank body.light-mode's one class in CSS specificity,
   which is what actually makes that true regardless of which order
   either was applied in. theme-light isn't listed separately since
   it matches this page's own already-default color values, so
   there's nothing to override for it. */
body.chapter-reading-page.theme-dark { --bg: #1e1e2b; --text: #e4e4ef; --card-bg: #17171f; --card-bg-2: #2a2a3a; --border: #333; --muted: #a79fc0; }
body.chapter-reading-page.theme-gray { --bg: #eef0f2; --text: #333; --card-bg: #dfe3e6; --card-bg-2: #e5e8ea; --border: #c8ccd0; --muted: #5a5f66; }
body.chapter-reading-page.theme-sepia { --bg: #f4ecd8; --text: #5b4636; --card-bg: #ebe0c4; --card-bg-2: #efe6d0; --border: #d9c9a3; --muted: #7a6551; }
body.chapter-reading-page.theme-night { --bg: #000000; --text: #cfcfd6; --card-bg: #141414; --card-bg-2: #0a0a0a; --border: #2a2a2a; --muted: #8a8a94; }
body.chapter-reading-page.theme-forest { --bg: #e9f0e6; --text: #33402f; --card-bg: #dde8d8; --card-bg-2: #e3ecdf; --border: #c3d4bc; --muted: #5a6b54; }
/* The site's own header and footer — not part of the reading area
   itself, so they're deliberately excluded from all of the above:
   re-declaring the standard, default values here specifically
   within these two elements is what stops them from inheriting
   whichever reading theme's colors down from <body>, keeping them
   looking exactly the same regardless of which of the 6 reading
   themes (or none) is currently active. */
body.chapter-reading-page .site-header,
body.chapter-reading-page .site-footer {
    --bg: #1B1730;
    --text: #F1ECE4;
    --card-bg: #241F3B;
    --card-bg-2: #2C2648;
    --border: #362F52;
    --muted: #A79FC0;
}

.reader-box.theme-dark { background: #1e1e2b; color: #e4e4ef; }
.reader-box.theme-dark h1, .reader-box.theme-dark .lock-title { color: #e4e4ef; }
.reader-box.theme-dark .lock-panel { background: linear-gradient(180deg, rgba(30,30,43,0) 0%, #17171f 15%, #17171f 100%); border-color: #333; }
.reader-box.theme-dark .lock-sub { color: #a79fc0; }
.reader-box.theme-dark .toolbar-btn { background: #2a2a3a; border-color: #3a3a4a; color: #e4e4ef; }
.reader-box.theme-dark .reader-toolbar { background: #1e1e2b; }
.reader-box.theme-gray { background: #eef0f2; color: #333; }
.reader-box.theme-gray .toolbar-btn { background: #dfe3e6; border-color: #c8ccd0; color: #333; }
.reader-box.theme-gray .reader-toolbar { background: #eef0f2; }

/* Sepia — classic warm e-reader tone, easy on the eyes for long
   sessions, familiar from Kindle/most reading apps. */
.reader-box.theme-sepia { background: #f4ecd8; color: #5b4636; }
.reader-box.theme-sepia h1, .reader-box.theme-sepia .lock-title { color: #4a3728; }
.reader-box.theme-sepia .lock-panel { background: linear-gradient(180deg, rgba(244,236,216,0) 0%, #f4ecd8 15%, #f4ecd8 100%); border-color: #d9c9a3; }
.reader-box.theme-sepia .lock-sub { color: #7a6551; }
.reader-box.theme-sepia .toolbar-btn { background: #ebe0c4; border-color: #d9c9a3; color: #5b4636; }
.reader-box.theme-sepia .reader-toolbar { background: #f4ecd8; }
.reader-box.theme-sepia .latest-chapter-notice { background: rgba(180,130,30,0.14); border-color: rgba(180,130,30,0.35); color: #4a3728; }

/* Night — near-pure black, for OLED screens and reading in the
   dark without any glow; noticeably darker than the Dark theme. */
.reader-box.theme-night { background: #000000; color: #cfcfd6; }
.reader-box.theme-night h1, .reader-box.theme-night .lock-title { color: #e8e8ee; }
.reader-box.theme-night .lock-panel { background: linear-gradient(180deg, rgba(0,0,0,0) 0%, #000 15%, #000 100%); border-color: #2a2a2a; }
.reader-box.theme-night .lock-sub { color: #8a8a94; }
.reader-box.theme-night .toolbar-btn { background: #141414; border-color: #2a2a2a; color: #cfcfd6; }
.reader-box.theme-night .reader-toolbar { background: #000000; }
.reader-box.theme-night .latest-chapter-notice { background: rgba(232,163,61,0.1); border-color: rgba(232,163,61,0.3); color: #d8d8de; }

/* Forest — soft green-tinted background, an alternative some
   readers find gentler on the eyes than plain white or gray. */
.reader-box.theme-forest { background: #e9f0e6; color: #33402f; }
.reader-box.theme-forest h1, .reader-box.theme-forest .lock-title { color: #2a3527; }
.reader-box.theme-forest .lock-panel { background: linear-gradient(180deg, rgba(233,240,230,0) 0%, #e9f0e6 15%, #e9f0e6 100%); border-color: #c3d4bc; }
.reader-box.theme-forest .lock-sub { color: #5a6b54; }
.reader-box.theme-forest .toolbar-btn { background: #dde8d8; border-color: #c3d4bc; color: #33402f; }
.reader-box.theme-forest .reader-toolbar { background: #e9f0e6; }
.reader-box.theme-forest .latest-chapter-notice { background: rgba(111,196,149,0.16); border-color: rgba(111,196,149,0.35); color: #2a3527; }

/* Mobile sticky bottom bar (Chapter List/Listen) — matches
   whichever reader theme is active rather than staying the
   default light cream color, which read as "just white" and
   out of place against a dark/night/gray reading background. */
@media (max-width: 780px) {
    .reader-box.theme-dark .toolbar-group-primary { background: #1e1e2b; border-top-color: #3a3a4a; }
    .reader-box.theme-gray .toolbar-group-primary { background: #eef0f2; }
    .reader-box.theme-sepia .toolbar-group-primary { background: #f4ecd8; border-top-color: #d9c9a3; }
    .reader-box.theme-night .toolbar-group-primary { background: #000000; border-top-color: #2a2a2a; }
    .reader-box.theme-forest .toolbar-group-primary { background: #e9f0e6; border-top-color: #c3d4bc; }
}
.reader-box.font-serif #reader-content { font-family: Georgia, 'Times New Roman', serif; }
.reader-box.font-sans #reader-content { font-family: Arial, Helvetica, sans-serif; }
.reader-box.font-georgia #reader-content { font-family: Georgia, serif; }
.reader-box.font-system #reader-content { font-family: var(--font-body); }

/* ---------------------------------------------------------
   Ratings, likes, favorites
   --------------------------------------------------------- */
.rating-row { display: flex; align-items: center; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.stars { font-size: 21px; cursor: pointer; }
.stars .star { color: #443a63; transition: color 0.15s ease, transform 0.15s ease; display: inline-block; }
.stars .star.filled { color: var(--gold); }
.stars .star:hover { color: var(--gold); transform: scale(1.15); }
.action-row { display: flex; gap: 10px; margin-top: 14px; flex-wrap: wrap; }
.action-btn {
    background: var(--card-bg);
    border: 1px solid var(--border);
    padding: 9px 16px;
    border-radius: 6px;
    font-size: 13px;
    cursor: pointer;
    color: var(--text);
    font-family: var(--font-body);
    font-weight: 600;
    text-decoration: none;
    display: inline-block;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.action-btn:hover { border-color: var(--primary); transform: translateY(-1px); box-shadow: 0 4px 12px rgba(232,96,124,0.15); }

.social-share-section {
    margin-top: 20px;
    max-width: 100%;
}
.social-share-heading {
    font-size: 15px;
    font-weight: 800;
    margin-bottom: 10px;
}
.social-share-icons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    max-width: 100%;
}
.social-share-icon {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
    transition: border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.social-share-icon span { line-height: 1; }
.social-share-icon:hover {
    background: var(--brand-color, var(--gold));
    color: #fff;
    border-color: var(--brand-color, var(--gold));
    transform: translateY(-2px);
}
.social-share-more-btn {
    display: inline-block;
    margin: 10px 0;
    background: none;
    border: none;
    color: var(--gold);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    padding: 0;
}
.social-share-more-btn:hover { text-decoration: underline; }
#social-share-secondary { margin-top: 2px; }

@media (max-width: 780px) {
    .social-share-icon { width: 42px; height: 42px; font-size: 14px; }
}

.continue-reading-box {
    margin-top: 18px;
    padding: 16px 18px;
    background: linear-gradient(135deg, rgba(232,163,61,0.14), rgba(232,96,124,0.1));
    border: 1px solid rgba(232,163,61,0.3);
    border-radius: 8px;
    transition: border-color 0.2s ease;
}
.continue-reading-box .novel-meta { color: var(--gold); font-weight: 700; }
.continue-reading-box:hover { border-color: rgba(232,163,61,0.55); }

.novel-reading-buttons { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }
.novel-reading-buttons .btn { font-size: 13px; }

.upcoming-chapter-banner {
    margin: 14px 0 0;
    padding: 12px 16px;
    background: linear-gradient(135deg, rgba(232,163,61,0.14), rgba(232,96,124,0.1));
    border: 1px solid rgba(232,163,61,0.3);
    border-radius: 8px;
    font-size: 13.5px;
    color: var(--text);
}
.upcoming-chapter-banner #upcoming-chapter-countdown { color: var(--gold); font-weight: 700; font-variant-numeric: tabular-nums; }

/* "Ways to Read" — shown on both desktop and mobile. */
.ways-to-read-mobile { margin-top: 36px; }

/* Password visibility toggle */
.password-field { position: relative; display: flex; }
.password-field .pw-input { flex: 1; padding-right: 44px; }
.pw-toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    cursor: pointer;
    font-size: 15px;
    padding: 4px 8px;
}

/* ---------------------------------------------------------
   Modal (chapter list, reader settings)
   --------------------------------------------------------- */
.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(10,8,18,0.75);
    backdrop-filter: blur(3px);
    z-index: 100;
    align-items: center;
    justify-content: center;
    padding: 20px;
    animation: modalFadeIn 0.15s ease;
}
@keyframes modalFadeIn { from { opacity: 0; } to { opacity: 1; } }
.modal-overlay.open { display: flex; }
.modal-box {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    max-width: 480px;
    width: 100%;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 20px 60px rgba(0,0,0,0.5);
    animation: modalRise 0.2s ease;
}
@keyframes modalRise { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.modal-header h3 { font-family: var(--font-display); font-size: 17px; }
/* Chapters list specifically, not every modal on the site — it
   holds a 5-column grid per row (title, NEW/lock badge, status,
   time, listen icon) that benefits from real room on a wide screen,
   unlike simpler dialogs (e.g. the report modal) that stay fine at
   the shared, narrower default. */
#chapter-list-modal .modal-box { max-width: 760px; }

/* Homepage popup — deliberately more decorative than the standard
   modal-box above, since this is a promotional/announcement
   moment rather than a functional dialog. */
.homepage-popup-box {
    position: relative;
    background: linear-gradient(160deg, var(--card-bg) 0%, var(--dark) 100%);
    border: 1px solid var(--gold);
    border-radius: 16px;
    max-width: 420px;
    width: 100%;
    padding: 36px 30px 30px;
    text-align: center;
    box-shadow: 0 24px 70px rgba(0,0,0,0.55), 0 0 0 1px rgba(232,163,61,0.15);
    animation: modalRise 0.25s ease;
}
.homepage-popup-close {
    position: absolute;
    top: 12px;
    right: 14px;
    background: none;
    border: none;
    color: var(--muted);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 4px;
    transition: color 0.15s ease;
}
.homepage-popup-close:hover { color: var(--gold); }
.homepage-popup-icon {
    font-size: 46px;
    margin-bottom: 12px;
    filter: drop-shadow(0 4px 12px rgba(232,163,61,0.4));
}
.homepage-popup-message {
    font-size: 15px;
    line-height: 1.7;
    color: var(--text);
}
.homepage-popup-got-it {
    margin-top: 22px;
    padding: 10px 32px;
    border-radius: 24px;
}
.modal-close { background: none; border: none; font-size: 22px; cursor: pointer; color: var(--muted); line-height: 1; }
.modal-search { margin: 14px 20px 0; padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; background: #FAF7F1; color: #241F3B; transition: box-shadow 0.15s ease; }
.modal-search:focus { outline: none; box-shadow: 0 0 0 3px rgba(232,163,61,0.35); }

/* Gallery picker — wider than the default modal so a desktop
   screen actually gets used well (more thumbnails visible at once,
   less scrolling to find an image), with its own more prominent
   search field. */
.gallery-picker-box {
    max-width: min(92vw, 1100px);
    max-height: 88vh;
}
.gallery-picker-search-wrap {
    position: relative;
    margin: 14px 20px 0;
}
.gallery-picker-search-wrap .gallery-picker-search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 14px;
    opacity: 0.6;
    pointer-events: none;
}
.gallery-picker-search {
    margin: 0;
    width: 100%;
    padding: 12px 14px 12px 36px;
    font-size: 15px;
}
.gallery-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    margin: 16px 20px;
    max-height: 65vh;
    overflow-y: auto;
}
.gallery-picker-thumb {
    padding: 0;
    border: 2px solid transparent;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    background: var(--card-bg-2);
    transition: border-color 0.15s ease, transform 0.15s ease;
    display: flex;
    flex-direction: column;
}
.gallery-picker-thumb:hover { border-color: var(--gold); transform: translateY(-2px); }
.gallery-picker-thumb-imgwrap {
    width: 100%;
    aspect-ratio: 4/3;
    background: var(--card-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
/* object-fit: contain — shows the WHOLE image at a large, readable
   size rather than cropping it to fill a fixed box, so admin can
   actually see what each image looks like before picking it. */
.gallery-picker-thumb img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; display: block; }
.gallery-picker-thumb-title {
    padding: 7px 9px;
    font-size: 11px;
    color: var(--muted);
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-top: 1px solid var(--border);
}
.gallery-picker-load-more-wrap { text-align: center; margin: 16px 20px 4px; }

@media (max-width: 780px) {
    .gallery-picker-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); margin: 14px; gap: 10px; }
}
.chapter-list-results { overflow-y: auto; padding: 10px 20px; flex: 1; }
.chapter-list-item.current { color: var(--gold); font-weight: 700; }

/* Chapter list rows — both the novel page's own list and the chapter
   reading page's Chapters modal share this exact structure, so a
   badge's presence or absence in one column never shifts anything
   in another. Nested grid: the outer row is [main content | listen
   icon], and the link itself is a 4-column grid of its own
   [title | unlock badge | status badge | time] so every row's
   columns land in the same place regardless of which optional
   badges that particular chapter actually has. */
.chapter-row { display: grid; grid-template-columns: 1fr 34px; align-items: center; }
.chapter-row-link {
    display: grid;
    grid-template-columns: 70% 15% 15%;
    align-items: center;
    gap: 8px;
    padding: 13px 16px;
    text-decoration: none;
    color: var(--text);
    font-size: 14px;
}
.chapter-row-link:hover { color: var(--gold); }
.chapter-row-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chapter-row-col { text-align: center; }
.chapter-row-badge { text-align: left; }
/* Plain icon + text, no pill background — scoped to this context
   only, so the lock badge elsewhere on the site (novel cards, the
   full locked-chapter notice) keeps its original gold pill style. */
.chapter-row-badge .lock {
    background: none;
    color: var(--gold);
    padding: 0;
    border-radius: 0;
    margin-left: 0;
}
@media (max-width: 560px) {
    /* Fixed, smaller pixel widths here rather than the same
       percentages as above — on a narrow phone screen, 15% can come
       out too tight for badge text like "🔒 50 coins" to fit without
       wrapping. With only these two small fixed columns left (the
       date/time column that used to sit here is gone entirely), the
       title still naturally ends up occupying the large majority of
       the row's width either way. */
    .chapter-row-link { grid-template-columns: 1fr 60px 55px; gap: 4px; font-size: 13px; }
    /* Forces exactly 2 columns on mobile instead of the auto-fill
       minmax(220px,...) pattern collapsing to 1 — 220px is simply
       wider than half of most phone screens, so auto-fill alone
       never gets a second column to fit. */
    .gallery-grid { grid-template-columns: repeat(2, 1fr) !important; gap: 10px !important; }
}

.pagination { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 14px 20px; border-top: 1px solid var(--border); justify-content: center; }
.page-btn { border: 1px solid var(--border); background: var(--card-bg); color: var(--text); border-radius: 4px; padding: 5px 11px; font-size: 12px; cursor: pointer; min-width: 30px; }
.page-btn.active { background: var(--gold); color: #1B1730; border-color: var(--gold); font-weight: 700; }
.page-btn-nav { font-weight: 600; }
.page-ellipsis { color: var(--muted); font-size: 12px; padding: 0 2px; user-select: none; }

/* Settings panel */
.settings-group { padding: 14px 20px; border-bottom: 1px solid var(--border); }
.settings-group label { display: block; font-size: 12px; font-weight: 700; color: var(--muted); margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; }
.settings-row { display: flex; gap: 8px; }
.settings-row.settings-row-wrap { flex-wrap: wrap; }
.settings-row.settings-row-wrap .settings-option { flex: 1 1 calc(33.333% - 6px); min-width: 80px; }
.settings-option { flex: 1; border: 1px solid var(--border); background: var(--card-bg); color: var(--text); border-radius: 6px; padding: 8px; font-size: 13px; cursor: pointer; }
.settings-option.active { background: var(--gold); color: #1B1730; border-color: var(--gold); font-weight: 700; }
.settings-select { width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; background: #FAF7F1; color: #241F3B; }

/* ---------------------------------------------------------
   Plans / pricing
   --------------------------------------------------------- */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; margin-top: 20px; }
.plan-card { background: var(--card-bg); border-radius: 10px; padding: 26px 20px; text-align: center; box-shadow: 0 2px 10px rgba(0,0,0,0.3); border: 2px solid var(--border); }
.plan-card.active-plan { border-color: var(--gold); }
.plan-name { font-family: var(--font-display); font-size: 17px; font-weight: 600; margin-bottom: 8px; }
.plan-price { font-size: 25px; font-weight: 800; color: var(--gold); margin-bottom: 4px; }
.plan-duration { font-size: 12px; color: var(--muted); margin-bottom: 16px; }

/* ---------------------------------------------------------
   Admin tables
   --------------------------------------------------------- */
table { color: var(--text); }
table thead tr { background: var(--dark) !important; }
table tbody tr { border-bottom: 1px solid var(--border) !important; }
table a { color: var(--gold); }

/* ---------------------------------------------------------
   Footer
   --------------------------------------------------------- */
/* ---------------------------------------------------------
   Homepage FAQ + Quick Contact — sit just above the footer.
   --------------------------------------------------------- */

/* Scroll-reveal — each major homepage section (AI, Ways to Read,
   FAQ, Quick Contact) fades and rises into place the first time it
   scrolls into view, rather than everything already being visible
   the instant the page loads. Deliberately excludes the hero (it's
   above the fold already, so animating it would just delay what
   the visitor sees first) and the dynamically-loaded ranking
   carousels (their own content is injected later by a separate
   script, so they need their own timing, not this one).
   prefers-reduced-motion gets the plain, immediately-visible
   version — motion here is a nice-to-have, never something that
   should fight someone's own accessibility setting. */
.scroll-reveal {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.7s ease, transform 0.7s ease;
}
.scroll-reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
    .scroll-reveal { opacity: 1; transform: none; transition: none; }
}

.faq-section, .quick-contact-section {
    max-width: 100%;
    padding: 0 20px;
}
/* FAQ + Quick Contact now render as one unified card (like the
   pricing cards above them) instead of two separate floating
   blocks, and the card itself carries the top/bottom margin — so
   spacing before the footer is always consistent instead of
   depending on margins from whichever section happens to render
   last. Mobile stacks FAQ above Quick Contact inside the same card,
   separated by a divider; desktop splits into two columns divided
   by a vertical rule instead. */
.home-faq-contact-grid {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-top: 2px solid var(--gold);
    border-radius: 14px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.35);
    padding: 32px 24px;
    margin: 48px 0 48px;
}
.home-faq-contact-grid .faq-section,
.home-faq-contact-grid .quick-contact-section {
    margin: 0;
    padding: 0;
    max-width: none;
}
.home-faq-contact-grid .quick-contact-section {
    margin-top: 28px;
    padding-top: 28px;
    border-top: 1px solid var(--border);
}
@media (min-width: 781px) {
    .home-faq-contact-grid {
        display: grid;
        grid-template-columns: 1.4fr 1fr;
        align-items: center;
        gap: 32px;
        padding: 36px 40px;
    }
    .home-faq-contact-grid.single-column {
        grid-template-columns: 1fr;
    }
    .home-faq-contact-grid .quick-contact-section {
        margin-top: 0;
        padding-top: 0;
        border-top: none;
        padding-left: 32px;
        border-left: 1px solid var(--border);
    }
    .home-faq-contact-grid.single-column .quick-contact-section {
        padding-left: 0;
        border-left: none;
    }
}
.faq-section-title { font-family: var(--font-display); font-size: 24px; margin-bottom: 18px; text-align: center; }
.faq-accordion {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    align-items: start;
}
@media (max-width: 780px) {
    .faq-accordion { grid-template-columns: 1fr; }
}
.faq-item { background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.faq-question {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    background: none;
    border: none;
    color: var(--text);
    text-align: left;
    padding: 14px 16px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    font-family: var(--font-body);
}
.faq-question:hover { color: var(--gold); }
.faq-toggle-icon { flex-shrink: 0; font-size: 18px; color: var(--gold); transition: transform 0.2s ease; }
.faq-item.open .faq-toggle-icon { transform: rotate(45deg); }
.faq-answer {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.25s ease, padding 0.25s ease;
    padding: 0 16px;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.7;
}
.faq-item.open .faq-answer { max-height: 500px; padding: 0 16px 16px; }

.quick-contact-section { text-align: center; }
.quick-contact-text { color: var(--muted); font-size: 14px; margin-bottom: 14px; }
.quick-contact-email {
    display: inline-block;
    background: var(--gold);
    color: #1B1730;
    font-weight: 700;
    padding: 12px 24px;
    border-radius: 6px;
    text-decoration: none;
    font-size: 15px;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    box-shadow: 0 2px 8px rgba(232,163,61,0.15);
}
.quick-contact-email:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(232,163,61,0.3); }

.site-footer { background: var(--dark); color: var(--muted); padding: 40px 0 0; font-size: 13px; border-top: 1px solid var(--border); }

.footer-columns {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 32px;
    padding-bottom: 30px;
    text-align: left;
}
.footer-col { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.footer-logo { display: inline-flex; align-items: center; gap: 10px; margin-bottom: 10px; text-decoration: none; }
.footer-logo-text { font-family: var(--font-display); font-size: 19px; font-weight: 700; color: #F1ECE4; }
.footer-logo .logo-img { height: 32px; width: auto; }
.footer-col-text { font-size: 13px; line-height: 1.7; color: #B8AFC9; max-width: 320px; }
.footer-col-heading {
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--gold);
    margin: 0 0 12px;
}
.footer-app-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 18px;
    border-radius: 24px;
    background: var(--gold);
    border: 1px solid var(--gold);
    color: #1B1730;
    text-decoration: none;
    font-size: 13px;
    font-weight: 700;
    transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.footer-app-btn:hover { background: #F2B457; border-color: #F2B457; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(232,163,61,0.3); }

.footer-social-icons { display: flex; gap: 10px; }
.footer-social-icon {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: #cfc7e0;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.footer-social-icon:hover {
    background: var(--brand-color, var(--gold));
    color: #fff;
    border-color: var(--brand-color, var(--gold));
    transform: translateY(-2px);
}

.footer-links { display: flex; flex-direction: column; gap: 9px; }
.footer-links a { color: #cfc7e0; text-decoration: none; font-size: 13px; }
.footer-links a:hover { color: var(--gold); }

/* Collapsible footer columns (Browse, Pages) — the toggle button
   uses the same visual language as .footer-col-heading (gold,
   uppercase-ish weight) so a collapsible column doesn't look out
   of place next to the plain, non-collapsible ones. Collapsed by
   default everywhere; the Browse column's own further-down
   desktop override is what actually keeps it always-expanded there. */
.footer-col-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    padding: 0 0 12px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--gold);
}
.footer-col-arrow { display: inline-block; transition: transform 0.2s ease; font-size: 11px; }
/* Gap between Download App and Follow Us — both live stacked
   inside the same 4th grid column rather than as separate grid
   items of their own, so the grid's own gap never applied between
   them at all. Using flex + gap on .footer-col itself (below,
   .footer-col { display:flex; flex-direction:column; }) rather than
   margin-top on the subsections themselves — margin-top between
   plain block siblings is exactly the kind of thing vertical margin
   collapsing can silently eat, which is what actually kept
   happening here even after correcting the value more than once;
   gap can't collapse the same way, so this is the more reliable fix. */
.footer-col-collapsible.open .footer-col-arrow { transform: rotate(180deg); }
.footer-col-content { display: none; }
.footer-col-collapsible.open .footer-col-content { display: flex; }

@media (min-width: 781px) {
    /* Important Pages and Browse both stay always-expanded on
       desktop, regardless of their own .open toggle state — the
       footer only has two collapsible columns at all now (Logo/Info
       and Download App never were), and both of those two are
       collapsible on mobile only, always open on desktop. */
    .footer-col-desktop-open .footer-col-content { display: flex !important; }
    .footer-col-desktop-open .footer-col-toggle { cursor: default; pointer-events: none; }
    .footer-col-desktop-open .footer-col-arrow { display: none; }
}

.footer-copyright {
    text-align: center;
    padding: 16px 20px;
    border-top: 1px solid var(--border);
    font-size: 12.5px;
    color: var(--muted);
}

@media (max-width: 780px) {
    .footer-columns {
        grid-template-columns: 1fr;
        gap: 28px;
        text-align: center;
    }
    /* .footer-col became a flex column (see the base rule earlier in
       this file, added for the Download App/Follow Us gap fix) —
       text-align on .footer-columns above no longer reaches into it
       to center the logo link, since flex items are positioned by
       flex alignment, not text-align, once their container is a
       flex box. align-self here (rather than align-items on the
       whole .footer-col) keeps this scoped to just the logo — the
       collapsible content further down still needs its own full-
       width stretch for its internal grid/flex layout to work, and
       changing the parent's align-items would have shrunk those to
       fit their content instead of spanning the column properly. */
    .footer-logo { align-self: center; }
    .footer-col-text { max-width: none; margin-left: auto; margin-right: auto; }
    .footer-links {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
        align-items: stretch;
    }
    .footer-links a {
        background: var(--card-bg);
        border: 1px solid var(--border);
        border-radius: 8px;
        padding: 12px 10px;
        text-align: center;
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;
        transition: border-color 0.15s ease, color 0.15s ease;
    }
    .footer-links a:hover { border-color: var(--gold); }
    .footer-social-icons { justify-content: center; }
    .footer-social-icon { width: 44px; height: 44px; }

    /* The actual bug: .footer-col-content elements also carry the
       .footer-links class (for the same link-grid styling above),
       so the .footer-links{display:grid} rule right above this one
       — same specificity, but later in the file — was silently
       overriding the base .footer-col-content{display:none} rule
       everywhere on mobile, showing every collapsible column's
       content immediately regardless of whether it was ever
       actually opened. Restating the hide rule here, after
       .footer-links within this same media query, is what makes it
       win the cascade on mobile too. The existing higher-specificity
       .footer-col-collapsible.open .footer-col-content rule still
       correctly overrides this the moment a column is actually
       opened, exactly as it already did before this fix. */
    .footer-col-content { display: none; }
    .footer-col-collapsible.open .footer-col-content { display: grid; }
    /* Content that isn't a plain link list (Download App's install
       button, Follow Us's social icons) doesn't want the 2-column
       link grid above — falls back to a plain block, which is all
       it actually needs once visible. */
    .footer-col-collapsible.open .footer-col-content-block { display: block; }

    /* Mobile only, per an explicit follow-up request — every
       collapsible column's toggle becomes a real bordered button,
       matching the FAQ section's own question buttons exactly:
       label on the left, arrow on the right, same background,
       border, and rounded corners. Desktop keeps the plain
       heading-style toggle from the base rule above, untouched. */
    .footer-col-toggle {
        width: 100%;
        justify-content: space-between;
        background: var(--card-bg);
        border: 1px solid var(--border);
        border-radius: 8px;
        color: var(--text);
        text-align: left;
        text-transform: none;
        letter-spacing: normal;
        padding: 5px 6px;
        font-size: 14px;
        font-weight: 600;
    }
    .footer-col-toggle:hover { color: var(--gold); }
    .footer-col-arrow { color: var(--gold); font-size: 18px; }
    /* .footer-col itself becomes a flex column with a real gap here
       (see .footer-col { display:flex... } base rule above/below),
       so Download App and Follow Us space apart reliably — margin-
       top between them kept silently collapsing away even after
       being set correctly more than once, which gap doesn't suffer
       from. 2px per an explicit follow-up request — tighter than
       the 28px this replaces. */
    .footer-columns { gap: 2px; }
    .footer-col { gap: 2px; }
}

#back-to-top-btn {
    position: fixed;
    right: 20px;
    bottom: 20px;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: var(--gold);
    color: #1B1730;
    border: none;
    font-size: 18px;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0,0,0,0.35);
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
    z-index: 90;
}
#back-to-top-btn.visible { opacity: 1; visibility: visible; transform: translateY(0); }
#back-to-top-btn:hover { background: #F2B457; }

/* ---------------------------------------------------------
   Responsive
   --------------------------------------------------------- */
@media (max-width: 640px) {
    .hero h1 { font-size: 32px; }
    .header-inner { padding: 12px 16px; }
    .site-header nav { gap: 12px; }
    .novel-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    /* Homepage "per category" sections specifically — 4 novels
       total on mobile, not 5, using the exact same good-looking
       2-column layout every other .novel-grid page already uses at
       this width (title/author/badges/description all shown in
       full, nothing shrunk or hidden). Getting to "4" is simply
       hiding the 5th card rather than cramming a 4th column into one
       row — that squeezed layout looked bad and isn't used here.
       Desktop is untouched (still the real 5-column layout above). */
    .novel-grid--5col > :nth-child(5) { display: none; }
    /* The alternate "list" look for every 2nd category (see
       renderNovelSection() in novel-card.js) — same .novel-card
       markup, just laid out horizontally instead of upright: cover
       on the left at a fixed width, title/author/badges/description
       filling the rest on the right. Only active at this mobile
       width; .novel-grid--5col's own desktop rule above still shows
       every category as the same 5-across grid there. */
    .novel-grid--list { display: flex; flex-direction: column; gap: 10px; }
    .novel-grid--list .novel-card { display: flex; flex-direction: row; align-items: stretch; padding: 6px; }
    /* The actual flex child is .novel-cover-wrap (added at runtime by
       cover-watermark.js around every .novel-cover) — fixed-size that,
       and let the image/placeholder inside it just fill that box. */
    .novel-grid--list .novel-card .novel-cover-wrap { width: 76px; height: 108px; flex-shrink: 0; }
    .novel-grid--list .novel-card .novel-cover { width: 100%; height: 100%; object-fit: cover; }
    .novel-grid--list .novel-card .novel-info { flex: 1; min-width: 0; padding: 0 0 0 10px; }
    .novel-grid--list .novel-card .card-synopsis {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }
    .reader-box { padding: 22px 16px; }
}

/* ---------------------------------------------------------
   Accessibility & mobile navigation
   --------------------------------------------------------- */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--gold);
    color: #1B1730;
    padding: 10px 18px;
    font-weight: 700;
    z-index: 200;
    border-radius: 0 0 6px 0;
}
.skip-link:focus { left: 0; }

:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}

.nav-toggle { display: none; flex-direction: column; justify-content: center; gap: 5px; width: 40px; height: 40px; background: none; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; flex-shrink: 0; }
.nav-toggle span { display: block; width: 20px; height: 2px; background: #fff; margin: 0 auto; }

/* Mobile-only standalone avatar link — hidden on desktop, where
   this same info already lives in the horizontal nav. The old
   always-visible info grid (Online/Gossip/Subscribed/Coins or
   Login/Sign Up) no longer has its own permanent row at all — that
   same info now only shows inside the hamburger panel, opened via
   the mobile menu toggle, freeing up this space for the search box
   below instead. */
.mobile-avatar-link { display: none; }

/* ---------------------------------------------------------
   Quick notification ticker — a brief "someone replied to you"
   banner, shown once per new event, then fades itself out. Lives
   inside <header> (not after it) so it inherits the header's own
   sticky positioning and stays pinned in view for as long as it's
   showing, even if the page is scrolled.
   --------------------------------------------------------- */
#quick-notification-bar {
    background: linear-gradient(135deg, rgba(232,163,61,0.22), rgba(232,96,124,0.14));
    border-bottom: 2px solid var(--gold);
}
#quick-notification-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px 16px;
    max-width: 1100px;
    margin: 0 auto;
    padding: 11px 20px;
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.3s ease, transform 0.3s ease;
}
#quick-notification-bar.show #quick-notification-inner { opacity: 1; transform: translateY(0); }
#quick-notification-inner a, #quick-notification-inner span {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
    text-decoration: none;
}
#quick-notification-inner a:hover { color: var(--gold); }
#quick-notification-dnd {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
}
#quick-notification-dnd input { width: auto; margin: 0; cursor: pointer; }

@media (max-width: 780px) {
    .nav-toggle { display: flex; order: 5; }
    /* wrap (not nowrap) is what actually lets the search bar and
       nav panel break onto their own full-width rows below — the
       previous nowrap silently blocked that regardless of the
       flex-basis/order settings below it. */
    .header-inner { flex-wrap: wrap; align-items: center; gap: 8px; }
    .logo { flex-shrink: 0; order: 1; }
    #theme-mode-toggle { order: 2; }
    .mobile-avatar-link { order: 4; }

    /* The Browse-links dropdown only shows on desktop — mobile
       already reaches every one of these links through the
       hamburger panel instead. */
    .nav-links-dropdown { display: none; }

    /* Now the only search box, on every device — it takes over the
       space the old always-visible info grid used to occupy, sized
       to genuinely fill a mobile-width row rather than being capped
       at the narrow max-width that suited sitting next to other
       header elements on desktop. */
    .header-search { order: 3; flex: 1 1 auto; max-width: none; min-width: 0; }
    .header-search input {
        width: 100%;
        padding: 10px 14px;
        border: 1.5px solid rgba(232,163,61,0.1);
        border-radius: 6px;
        font-size: 14px;
        background: var(--dark);
        color: #fff;
    }
    .header-search input::placeholder { color: #fff; opacity: 1; }
    .header-search input:focus { outline: none; border-color: rgba(232,163,61,0.25); box-shadow: none; }
    .header-search .header-search-results { left: 0; right: 0; width: auto; }

    /* Tapping into the search box replaces it with a genuine
       full-width bar fixed to the very top of the screen — not
       constrained to the header's own padded content width at all,
       edge to edge, and layered above the header itself (a higher
       z-index than .site-header's own 10) rather than sharing space
       inside it. Collapses back to its normal spot in the header
       row the moment focus is lost to anything outside the search
       box (see the click-outside handler below), whether that's a
       tap elsewhere on the page or picking a result. */
    .header-search.expanded {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        width: 100%;
        z-index: 100;
        max-width: none;
        padding: 12px 16px;
        background: #15121F;
        box-shadow: 0 4px 18px rgba(0,0,0,0.35);
    }
    .header-search.expanded input { padding: 12px 14px; font-size: 15px; }
    .header-search.expanded .header-search-results { top: calc(100% + 0px); left: 16px; right: 16px; width: auto; }

    .mobile-avatar-link { display: flex; flex-direction: column; align-items: center; gap: 2px; flex-shrink: 0; }
    .mobile-avatar-link .header-avatar { width: 32px; height: 32px; }
    .mobile-avatar-username {
        font-size: 10px;
        font-weight: 600;
        color: #fff;
        max-width: 56px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .site-header nav .nav-primary-link { display: block; }

    /* Two-column mobile layout: Browse/Categories/Advanced Search/
       Pricing/Leaderboard stacked on the left, Let's Gossip/Login/
       Sign Up (or Logout) stacked on the right, with a vertical
       divider line between the two columns. Both stretch to the
       full height of whichever column ends up taller. */
    .mobile-nav-columns {
        display: flex;
        flex-direction: row;
        align-items: stretch;
        gap: 14px;
        width: 100%;
    }
    .mobile-nav-col-left, .mobile-nav-col-right {
        display: flex;
        flex-direction: column;
        gap: 8px;
        flex: 1;
        min-width: 0;
    }
    .mobile-nav-divider { display: block; width: 1px; background: var(--border); flex-shrink: 0; }

    /* Right column's buttons (Gossip/Login/Sign Up/Logout) get the
       same full-width, stacked, block-level treatment as the left
       column's nav-primary-btn links below — so the two columns
       actually look like matching stacks of buttons, as asked for,
       rather than two visually different styles side by side. */
    .nav-btn { display: block; width: 100%; text-align: center; box-sizing: border-box; }

    /* The right column only ever has 2-3 buttons against the left
       column's 5 links, so left naturally without this taller;
       each right-column button growing equally to fill the same
       leftover vertical space is what stretches the whole stack
       down to actually reach the bottom of the menu, matching the
       left column's own height, per an explicit follow-up request. */
    .mobile-nav-col-right > .nav-btn {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    /* Button-styled instead of plain text links. */
    .nav-primary-btn-full {
        display: block;
        width: 100%;
        text-align: center;
        padding: 11px 12px;
        border: 1px solid var(--border);
        border-radius: 8px;
        background: var(--card-bg);
        font-weight: 600;
        font-size: 13.5px;
    }

    /* The logged-in name + avatar already shows in the mobile
       header itself (.mobile-avatar-link, next to the hamburger
       button) — showing it a second time inside the opened menu
       would just be a duplicate. Desktop is untouched: #site-nav's
       .username link is its only such display there. */
    .site-header nav .username { display: none; }
    .nav-btn-account { display: block; }

    /* Row 3: the hamburger's panel — its own full-width row below
       the search bar, hidden until opened. Still inside the same
       sticky <header>, so it scrolls together with the rest; capped
       height + scroll so a long link list never pushes the page's
       actual content off screen on a short phone. */
    .site-header nav {
        display: none;
        order: 6;
        flex-basis: 100%;
        flex-direction: column;
        align-items: flex-start;
        width: 100%;
        gap: 14px;
        padding: 16px 4px 4px;
        max-height: calc(100vh - 140px);
        overflow-y: auto;
    }
    .site-header nav.open { display: flex; }
}

/* Comfortable touch targets */
.toolbar-btn, .action-btn, .page-btn, .settings-option, .btn {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.chapter-list-item, .category-pill { min-height: 40px; }

/* Prevent iOS Safari auto-zoom on form focus */
@media (max-width: 640px) {
    .form-group input, .form-group select, .form-group textarea, .modal-search, .settings-select {
        font-size: 16px;
    }
}

/* ---------------------------------------------------------
   Header live search
   --------------------------------------------------------- */
.header-search { position: relative; flex: 1; max-width: 320px; min-width: 140px; }
.header-search input {
    width: 100%;
    padding: 9px 14px;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: rgba(255,255,255,0.06);
    color: #fff;
    font-size: 14px;
    font-family: var(--font-body);
}
.header-search input::placeholder { color: #9a92b3; }
.header-search input:focus { background: #FAF7F1; color: #241F3B; }
.header-search-results {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
    z-index: 50;
    overflow: hidden;
}
.header-search-results.open { display: block; }
.header-search-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    text-decoration: none;
    color: var(--text);
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}
.header-search-item:hover { background: var(--card-bg-2); }
.header-search-item img, .hsr-cover-fallback {
    width: 34px; height: 45px; border-radius: 3px; object-fit: cover; flex-shrink: 0;
}
.hsr-cover-fallback {
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, var(--primary), #6B4FA0);
    color: #fff; font-family: var(--font-display); font-weight: 700;
}
.header-search-viewall { display: block; padding: 10px 14px; text-align: center; color: var(--gold); text-decoration: none; font-size: 13px; font-weight: 600; }
.header-search-empty { padding: 14px; font-size: 13px; color: var(--muted); }

/* ---------------------------------------------------------
   Enhanced novel card badges (rating, likes, category, status)
   --------------------------------------------------------- */
.card-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.card-category, .card-status, .card-rating, .card-likes, .card-views {
    font-size: 10px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 3px 8px 8px 3px;
}
.card-category { background: rgba(232,163,61,0.15); color: var(--gold); }
.card-status { background: rgba(255,255,255,0.06); color: var(--muted); }
.card-status.status-ongoing { background: rgba(111,196,149,0.16); color: var(--success-text); }
.card-status.status-completed { background: rgba(232,96,124,0.16); color: var(--primary); }
.card-status.status-hiatus { background: rgba(255,255,255,0.06); color: var(--muted); }

/* ---------------------------------------------------------
   Novel detail page — author badge, latest updates, mobile centering
   --------------------------------------------------------- */
.novel-meta-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.author-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--text);
    font-weight: 600;
}

@media (max-width: 640px) {
    /* Cover stays on the left, title/rating on the right (row 1) —
       same idea as desktop, just a smaller cover so it fits a phone
       width. Action buttons + Share now span BOTH columns as their
       own full-width row underneath (row 2), rather than being
       squeezed into the narrow column 2 next to a small cover. */
    .novel-detail { grid-template-columns: 140px 1fr; grid-template-rows: auto auto; column-gap: 14px; text-align: left; }
    .novel-detail .novel-cover, .novel-detail .novel-cover-wrap { grid-row: 1; width: 140px; }
    .novel-detail-info { grid-row: 1; grid-column: 2; min-width: 0; }
    .novel-detail-info h1 { font-size: 23px; }
    .novel-meta-row, .rating-row, .action-row { justify-content: flex-start; }
    .novel-detail-actions { grid-row: 2; grid-column: 1 / 3; margin-top: 14px; }

    /* Like / Favorite / Listen / Report all on one line, not wrapped
       across several — smaller, tighter buttons so they actually
       have a real chance of fitting a phone's width, and a
       horizontal scroll as a safe fallback on the narrowest screens
       rather than wrapping or breaking the page's own width. */
    .novel-detail-actions .action-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        padding-bottom: 4px;
        gap: 8px;
    }
    .novel-detail-actions .action-btn {
        flex-shrink: 0;
        padding: 8px 12px;
        font-size: 12.5px;
        white-space: nowrap;
    }
}

/* ---------------------------------------------------------
   Ranking carousels (New Arrivals, Top 10, Mostly Viewed, Popular)
   Manual swipe/scroll — no auto-animation.
   --------------------------------------------------------- */
.rank-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    background: var(--gold);
    color: #1B1730;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 13px;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(0,0,0,0.4);
    z-index: 2;
}
.ranked-card { position: relative; flex: 0 0 195px; }
.rank-carousel-viewport {
    display: flex;
    gap: 16px;
    overflow-x: auto;
    margin-top: 12px;
    padding-bottom: 10px;
    scroll-snap-type: x proximity;
}
.rank-carousel-viewport .ranked-card { scroll-snap-align: start; }
.rank-carousel-viewport::-webkit-scrollbar { height: 6px; }
.rank-carousel-viewport::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* ---------------------------------------------------------
   Top 10 Spotlight — #1/#2/#3 podium + numbered list, built from
   the homepage's existing "popular" ranking data. Desktop: podium
   and list side by side. Mobile: stacked, with the podium itself
   swipeable (matches every other ranking row's own swipe behavior)
   since three full-size cover cards rarely all fit comfortably at
   phone width.
   --------------------------------------------------------- */
.top-ten-section {
    margin: 32px 0;
    background: linear-gradient(180deg, rgba(232,163,61,0.08), transparent 55%);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 26px 24px;
}
/* Carousel full-width on top, numbered list below — not side by
   side anymore, on any screen size; the list's own 2-column split
   (1-5 left, 6-10 right) is desktop-only, in the min-width:900px
   block further down. */
.top-ten-layout { display: block; }

/* --- Carousel: all 10, center card enlarged (see initTopTenCarousel
   in novel-card.js for how .is-centered actually gets assigned as
   the user scrolls/swipes/uses the arrows). --- */
.top-ten-carousel-wrap {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.5s ease, transform 0.5s ease;
}
.top-ten-section.in-view .top-ten-carousel-wrap { opacity: 1; transform: translateY(0); }
.top-ten-carousel {
    display: flex;
    align-items: flex-end;
    gap: 20px;
    overflow-x: auto;
    /* overflow-x: auto alone can make a browser also compute
       overflow-y as auto (a real CSS spec quirk — a visible axis
       next to an auto one gets forced to auto too) and silently show
       a vertical scrollbar the moment content is even a pixel taller
       than the box, e.g. from a card's own box-shadow. Setting this
       explicitly is what actually stops that stray scrollbar. */
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    /* A small FIXED amount, not a percentage of the container — a
       percentage-based gap (what this used to be) is exactly what
       caused a large empty area at whichever end runs out of cards
       first: #1 needs that much empty space before it to reach
       dead-center, and once you've scrolled to the actual last card,
       there's nothing left to fill that same gap on the other side.
       No reordering trick fixes that — it only relocates which end
       shows it. A small fixed peek instead means #1 and #10 sit near
       the edge rather than perfectly centered, which is a far smaller
       visual trade-off than a large dead zone. */
    scroll-padding: 0 24px;
    padding: 10px 24px 14px;
    flex: 1;
    min-width: 0;
}
.top-ten-carousel::-webkit-scrollbar { height: 6px; }
.top-ten-carousel::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.top-ten-carousel-item {
    display: block;
    flex-shrink: 0;
    scroll-snap-align: center;
    width: 260px;
    text-decoration: none;
    color: var(--text);
    text-align: center;
    opacity: 0.6;
    transform: scale(0.86);
    transition: opacity 0.3s ease, transform 0.3s ease;
}
.top-ten-carousel-item.is-centered { opacity: 1; transform: scale(1.1); }

/* Every card, 1st through 10th, shares this exact same structure and
   size now — see renderCarouselCard() in novel-card.js. The only
   thing that varies by rank is this badge's color; nothing about the
   card's own height or width does, so nothing about being "1st,
   2nd, or 3rd" makes a card structurally bigger than "8th, 9th, or
   10th" — only actually being the centered card does that. */
.podium-cover-wrap {
    position: relative;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 10px 26px rgba(0,0,0,0.4);
    border: 3px solid var(--border);
}
.podium-cover-wrap .novel-cover { width: 100%; }

/* Fixed dark background + fixed white text, deliberately NOT tied to
   the site's day/night theme colors — this sits on top of a cover
   PHOTO, not the page background, so it needs to stay readable
   against any cover regardless of which theme is active. */
.carousel-rank-badge {
    position: absolute;
    top: 10px; left: 10px;
    width: 34px; height: 34px;
    border-radius: 50%;
    background: rgba(27,23,48,0.85);
    border: 1px solid rgba(255,255,255,0.25);
    color: #fff;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    display: flex; align-items: center; justify-content: center;
}
.carousel-rank-badge--top1 { background: var(--gold); border-color: var(--gold); color: #1B1730; }
.carousel-rank-badge--top2 { background: #C9C9D8; border-color: #C9C9D8; color: #1B1730; }
.carousel-rank-badge--top3 { background: #C98A4B; border-color: #C98A4B; color: #1B1730; }
.podium-title {
    margin-top: 14px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15.5px;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.podium-meta { margin-top: 6px; font-size: 12.5px; color: var(--muted); display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.podium-genre { color: var(--gold); }

/* Prev/Next — desktop only (see the mobile media query below, which
   hides these entirely: touch swipe is the only control there,
   matching how every other carousel on this site already behaves
   on mobile). */
.top-ten-arrow {
    flex-shrink: 0;
    width: 44px; height: 44px;
    border-radius: 50%;
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.top-ten-arrow:hover { background: var(--gold); border-color: var(--gold); color: #1B1730; transform: scale(1.08); }

/* --- Numbered list — single column on mobile/tablet, splits into
   two columns (1-5 left, 6-10 right) on desktop via the media query
   further down. CSS multi-column naturally fills the first column
   top-to-bottom before starting the second, so with exactly 10 items
   this lands as 1-5 then 6-10 with no extra markup needed. --- */
.top-ten-list { display: flex; flex-direction: column; gap: 8px; margin-top: 24px; }
.top-list-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px;
    border-radius: 8px;
    text-decoration: none;
    color: var(--text);
    transition: background 0.15s ease, transform 0.15s ease, opacity 0.4s ease;
    opacity: 0;
    transform: translateX(14px);
}
.top-ten-section.in-view .top-list-row { opacity: 1; transform: translateX(0); }
.top-ten-list .top-list-row:nth-child(1) { transition-delay: 0.05s; }
.top-ten-list .top-list-row:nth-child(2) { transition-delay: 0.1s; }
.top-ten-list .top-list-row:nth-child(3) { transition-delay: 0.15s; }
.top-ten-list .top-list-row:nth-child(4) { transition-delay: 0.2s; }
.top-ten-list .top-list-row:nth-child(5) { transition-delay: 0.25s; }
.top-ten-list .top-list-row:nth-child(6) { transition-delay: 0.3s; }
.top-ten-list .top-list-row:nth-child(7) { transition-delay: 0.35s; }
.top-ten-list .top-list-row:nth-child(8) { transition-delay: 0.4s; }
.top-ten-list .top-list-row:nth-child(9) { transition-delay: 0.45s; }
.top-ten-list .top-list-row:nth-child(10) { transition-delay: 0.5s; }
.top-list-row:hover { background: var(--card-bg-2); transform: translateX(2px); }
.top-list-row .novel-cover { width: 42px; height: 60px; border-radius: 4px; flex-shrink: 0; font-size: 9px; }
.top-list-rank {
    flex-shrink: 0;
    width: 24px; height: 24px;
    border-radius: 50%;
    background: var(--card-bg-2);
    border: 1px solid var(--border);
    color: var(--muted);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12px;
}
.top-list-rank--top1 { background: var(--gold); border-color: var(--gold); color: #1B1730; }
.top-list-rank--top2 { background: #C9C9D8; border-color: #C9C9D8; color: #1B1730; }
.top-list-rank--top3 { background: #C98A4B; border-color: #C98A4B; color: #1B1730; }
.top-list-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.top-list-title { font-weight: 700; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-list-sub { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-list-views { font-size: 11px; color: var(--gold); }

/* Desktop: 1st-5th on the left, 6th-10th on the right, side by side —
   requested specifically for wider screens; mobile/tablet keeps the
   simple single vertical list above. */
@media (min-width: 781px) {
    .top-ten-list { display: block; column-count: 2; column-gap: 28px; }
    .top-list-row { break-inside: avoid; -webkit-column-break-inside: avoid; margin-bottom: 8px; }
}

@media (prefers-reduced-motion: reduce) {
    .top-ten-carousel-wrap, .top-list-row { opacity: 1; transform: none; transition: none; }
    .top-ten-carousel-item { transition: none; }
}

@media (max-width: 780px) {
    .top-ten-section { padding: 14px; }
    /* Swipe only on mobile — no arrow buttons, matching how every
       other ranking row on this site already behaves at this width. */
    .top-ten-arrow { display: none; }
    .top-ten-carousel { scroll-padding: 0 16px; padding: 10px 16px 14px; gap: 14px; }
    .top-ten-carousel-item { width: 236px; }
    .top-ten-list { margin-top: 18px; }
}

/* ---------------------------------------------------------
   Latest Chapters section (above the footer)
   --------------------------------------------------------- */
.latest-chapters-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; margin-top: 16px; }
.latest-chapter-item {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px 14px;
    text-decoration: none;
    color: var(--text);
    font-size: 13px;
    display: flex;
    align-items: center;
    gap: 12px;
}
.latest-chapter-item .latest-chapter-cover {
    width: 42px;
    height: 58px;
    object-fit: cover;
    border-radius: 4px;
    flex-shrink: 0;
}
.latest-chapter-item:hover { border-color: var(--gold); }
.latest-chapter-item strong { color: var(--gold); }

/* ---------------------------------------------------------
   Profile page horizontal sliders (Bookmarks, Favorites,
   Reading History) — manual left-to-right scroll/swipe, no
   auto-animation (unlike the homepage ranking carousels).
   --------------------------------------------------------- */
.profile-slider {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    padding-bottom: 10px;
    margin-top: 12px;
    scroll-snap-type: x proximity;
}
.profile-slider-card { flex: 0 0 140px; scroll-snap-align: start; }
.profile-slider::-webkit-scrollbar { height: 6px; }
.profile-slider::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* ---------------------------------------------------------
   Continue Reading — a vertical list (cover left, details right)
   instead of the horizontal scrolling card row every other homepage
   "your stuff" section (Highlights, Recommended) still uses. This
   is specifically about picking up where you left off, so a quick
   scannable list reads faster than swiping through upright cards.
   --------------------------------------------------------- */
.continue-reading-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.continue-reading-row {
    position: relative;
    border-radius: 8px;
    background: var(--card-bg);
    transition: background 0.15s ease;
}
.continue-reading-row:hover { background: var(--card-bg-2); }
.continue-reading-link {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px;
    text-decoration: none;
    color: var(--text);
}
.continue-reading-row .novel-cover { width: 52px; height: 74px; border-radius: 5px; flex-shrink: 0; font-size: 10px; }
.continue-reading-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.continue-reading-title { font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.continue-reading-chapter { font-size: 12.5px; color: var(--muted); }
.continue-reading-highlight-link {
    position: absolute;
    top: 8px; right: 8px;
    background: rgba(27,23,48,0.75);
    border-radius: 10px;
    padding: 3px 7px;
    font-size: 12px;
    text-decoration: none;
    z-index: 2;
}
.card-rating { background: rgba(232,163,61,0.15); color: var(--gold); }
.card-likes { background: rgba(232,96,124,0.15); color: var(--primary); }
.card-views { background: rgba(255,255,255,0.06); color: var(--muted); }
.card-synopsis {
    font-size: 12px;
    color: var(--muted);
    margin-top: 8px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ---------------------------------------------------------
   Curated homepage sections (grid, 6 per section + View More)
   --------------------------------------------------------- */
.novel-section { margin-top: 40px; }
.section-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; }
.section-more { color: var(--gold); text-decoration: none; font-size: 13px; font-weight: 600; }

/* ---------------------------------------------------------
   Admin navigation — categorized accordion groups.
   Right sidebar on desktop, full-width panel on mobile (both use
   the same vertical accordion layout, just different width).
   --------------------------------------------------------- */
/* ---------------------------------------------------------
   Admin panel — WordPress-style layout: a thin top admin bar,
   plus a dark icon+label sidebar with expandable groups. Every
   color below reuses this site's own existing variables — the
   admin/author color scheme is unchanged, only rearranged.
   --------------------------------------------------------- */
.wp-admin-bar {
    display: flex;
    align-items: center;
    gap: 4px;
    height: 34px;
    padding: 0 14px;
    background: var(--dark);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 50;
    font-size: 12.5px;
}
.wp-admin-bar a { color: #cfc7e0; text-decoration: none; padding: 0 10px; height: 100%; display: flex; align-items: center; }
.wp-admin-bar a:hover { color: var(--gold); background: rgba(255,255,255,0.05); }
.wp-admin-bar-spacer { flex: 1; }
.wp-admin-bar-howdy { color: var(--muted); padding: 0 10px; }
.wp-admin-bar-logout:hover { color: var(--primary) !important; }

.admin-layout { display: flex; gap: 0; flex-direction: row; align-items: flex-start; }
.admin-content { flex: 1; min-width: 0; padding: 20px var(--admin-pad-x, 20px); }
/* Hidden by default (desktop) — the mobile media query below
   switches these on and defines their actual mobile appearance. */
.admin-mobile-nav-toggle, .admin-mobile-nav-backdrop { display: none; }
.admin-nav {
    flex: 0 0 190px;
    position: sticky;
    /* The site's own header no longer renders on admin pages at
       all (see includes/header.php) — only the 34px top admin bar
       sits above this now, so that's the only offset needed. */
    top: 34px;
    max-height: calc(100vh - 34px);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0;
    background: var(--dark);
    border-right: 1px solid var(--border);
    padding: 6px 0;
    /* Firefox's equivalent of the thin, border-colored ::-webkit-
       scrollbar rules just below — Firefox doesn't support styling
       via ::-webkit-scrollbar at all, so without this it would fall
       back to its own default (usually much wider, mismatched)
       scrollbar regardless of how the webkit one below is styled. */
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.admin-nav::-webkit-scrollbar { width: 8px; }
.admin-nav::-webkit-scrollbar-track { background: transparent; }
.admin-nav::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.admin-nav::-webkit-scrollbar-thumb:hover { background: var(--gold); }

.admin-nav-group summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 16px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
    user-select: none;
    color: #cfc7e0;
    border-left: 3px solid transparent;
}
.admin-nav-icon { font-size: 15px; flex-shrink: 0; width: 18px; text-align: center; }
.admin-nav-label { flex: 1; }
.admin-nav-group summary::-webkit-details-marker { display: none; }
.admin-nav-group summary::after { content: '▸'; color: var(--muted); font-size: 10px; margin-left: auto; transition: transform 0.15s ease; }
.admin-nav-group[open] summary::after { transform: rotate(90deg); }
.admin-nav-group summary:hover { background: rgba(255,255,255,0.05); color: #fff; }
/* has-active: this group contains the page currently being viewed.
   [open]: the group is simply expanded right now, regardless of
   whether it contains the active page — clicking a heading to open
   it should turn that heading gold immediately, the same way a
   clicked FAQ-style tab does elsewhere on the site, not only once
   navigation happens to land inside it. */
.admin-nav-group.has-active summary, .admin-nav-group[open] summary { border-left-color: var(--gold); color: var(--gold); background: rgba(232,163,61,0.08); }

.admin-nav-group-items { display: flex; flex-direction: column; padding: 2px 0 6px; background: rgba(0,0,0,0.15); }
.admin-nav-group-items a {
    padding: 8px 16px 8px 44px;
    color: var(--muted);
    text-decoration: none;
    font-size: 12.5px;
    border-left: 3px solid transparent;
}
.admin-nav-group-items a:hover { background: rgba(255,255,255,0.04); color: #fff; }
.admin-nav-group-items a.active { color: var(--gold); font-weight: 700; border-left-color: var(--gold); background: rgba(232,163,61,0.08); }

/* ---------------------------------------------------------
   Admin design system — compact, data-dense.
   Retrofit target: replace repeated inline table/card styles
   across admin pages with these shared classes.
   --------------------------------------------------------- */
.admin-h1 {
    font-family: var(--font-body);
    font-size: 19px;
    font-weight: 800;
    letter-spacing: -0.2px;
}
.admin-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--admin-radius);
    box-shadow: var(--admin-shadow);
    padding: 14px;
}
.admin-card h2 { font-size: 14px; font-weight: 700; margin-bottom: 10px; }

.admin-table-wrap {
    overflow-x: auto;
    border-radius: var(--admin-radius);
    border: 1px solid var(--border);
    box-shadow: var(--admin-shadow);
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.admin-table-wrap::-webkit-scrollbar { height: 8px; }
.admin-table-wrap::-webkit-scrollbar-track { background: transparent; }
.admin-table-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.admin-table-wrap::-webkit-scrollbar-thumb:hover { background: var(--gold); }
.admin-table { width: 100%; border-collapse: collapse; background: var(--card-bg); font-size: var(--admin-font-size); }
.admin-table thead tr { background: var(--dark); color: #fff; text-align: left; }
.admin-table th { padding: 8px var(--admin-pad-x); font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--muted); position: sticky; top: 0; background: var(--dark); z-index: 1; }
.admin-table td { padding: var(--admin-pad-y) var(--admin-pad-x); border-bottom: 1px solid var(--border); vertical-align: middle; }
.admin-table tbody tr:hover { background: var(--card-bg-2); }
.admin-table tbody tr:last-child td { border-bottom: none; }

/* Responsive tables — below this width, an admin table with
   several inline mini-forms per cell stops being usable even with
   horizontal scroll (you'd have to scroll sideways mid-edit). Turn
   each row into a labeled stacked card instead: add this class to
   any admin-table you want this treatment for, and a data-label
   attribute on each <td> naming its column. */
@media (max-width: 780px) {
    .admin-table.admin-table-responsive-cards thead { display: none; }
    .admin-table.admin-table-responsive-cards, .admin-table.admin-table-responsive-cards tbody { display: block; width: 100%; }
    .admin-table.admin-table-responsive-cards tr {
        display: block;
        background: var(--card-bg);
        border: 1px solid var(--border);
        border-radius: var(--admin-radius);
        margin-bottom: 10px;
        padding: 4px 0;
    }
    .admin-table.admin-table-responsive-cards td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 10px;
        padding: 8px 12px;
        border-bottom: 1px solid var(--border);
        text-align: right;
        white-space: normal;
    }
    .admin-table.admin-table-responsive-cards tr td:last-child { border-bottom: none; }
    .admin-table.admin-table-responsive-cards td::before {
        content: attr(data-label);
        font-size: 10.5px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.4px;
        color: var(--muted);
        flex-shrink: 0;
        text-align: left;
    }
    /* Inline forms inside a cell (price editors, action buttons)
       need to wrap and use the space naturally instead of being
       squeezed to fixed pixel widths meant for a wide desktop cell. */
    .admin-table.admin-table-responsive-cards td form { flex-wrap: wrap; justify-content: flex-end; }
    .admin-table.admin-table-responsive-cards td input[type="number"],
    .admin-table.admin-table-responsive-cards td input[type="text"] { width: 64px !important; }

    /* "View More" collapsed-row toggle — used on Manage Users so a
       mobile card shows just Select/Username/Email plus this button
       by default, with every other field (Role, Status, Coins,
       Subscription, Joined, Actions) hidden until tapped. Add
       class="mobile-collapsible" to any <td> that should start
       hidden, and a lone <td class="mobile-view-more-cell"> holding
       the toggle button — .mobile-view-more-btn's own JS click
       handler is what actually adds/removes .row-expanded on the
       parent <tr>. */
    .admin-table.admin-table-responsive-cards .mobile-view-more-cell { display: flex; justify-content: center; padding: 8px 12px; }
    .admin-table.admin-table-responsive-cards .mobile-view-more-btn {
        background: var(--card-bg-2, transparent);
        border: 1px solid var(--border);
        border-radius: 6px;
        padding: 6px 16px;
        font-size: 12px;
        font-weight: 600;
        color: var(--primary);
        cursor: pointer;
    }
    .admin-table.admin-table-responsive-cards td.mobile-collapsible { display: none; }
    .admin-table.admin-table-responsive-cards tr.row-expanded td.mobile-collapsible { display: flex; }
}
/* The "View More" cell only ever exists for the mobile card layout
   above — on desktop, the normal wide table (with every column
   already visible at once) has no use for it, and without this it
   would otherwise render as an extra, misaligned, mostly-empty
   column next to Email. */
.mobile-view-more-cell { display: none; }

.admin-stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
.admin-stat-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--admin-radius-sm); box-shadow: var(--admin-shadow); padding: 12px 14px; }
.admin-stat-card .admin-stat-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.3px; }
.admin-stat-card .admin-stat-value { font-size: 20px; font-weight: 800; margin-top: 2px; font-family: var(--font-body); }

/* Dashboard section layout — the toggle only applies on desktop
   (per spec); mobile always stacks single-column regardless of
   the chosen mode, since there's no room for a real grid there. */
.dashboard-sections { margin-top: 20px; }
.dashboard-sections section {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--admin-radius);
    padding: 16px 18px;
    margin-bottom: 18px;
}
/* The toggle itself only matters once the grid layout can
   actually apply — below that width it would show as clickable
   with no visible effect, which just looks broken. Hiding it here
   keeps the control honest about what it can currently do. */
@media (max-width: 899px) {
    .dashboard-view-toggle { display: none; }
}
@media (min-width: 900px) {
    .dashboard-sections.dashboard-grid-mode {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 18px;
    }
    .dashboard-sections.dashboard-grid-mode section { margin-bottom: 0; }
}

.admin-btn-sm {
    border: 1px solid var(--border);
    background: var(--card-bg-2);
    color: var(--text);
    border-radius: var(--admin-radius-sm);
    padding: 4px 10px;
    font-size: 11.5px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.admin-btn-sm:hover { background: var(--card-bg); border-color: var(--gold); }
.admin-btn-sm.danger { color: var(--primary); border-color: transparent; background: none; padding: 4px 6px; }
.admin-btn-sm.danger:hover { background: var(--error-bg); }
.admin-btn-sm.gold { color: var(--gold); border-color: transparent; background: none; padding: 4px 6px; }
.admin-btn-sm.gold:hover { background: rgba(232,163,61,0.12); }

.admin-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 700;
}
.admin-badge.on { background: var(--success-bg); color: var(--success-text); }
.admin-badge.off { background: var(--error-bg); color: var(--error-text); }
.admin-badge.neutral { background: rgba(255,255,255,0.06); color: var(--muted); }

.admin-toolbar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.admin-toolbar input[type="text"], .admin-toolbar input[type="search"] {
    padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--admin-radius-sm);
    background: var(--bg); color: var(--text); font-size: 12.5px;
}

@media (max-width: 900px) {
    .admin-layout { flex-direction: column; }

    /* Top admin bar: drop the "Howdy" greeting on narrow screens to
       keep the essential links (View Site, Dashboard, Log Out) from
       wrapping or overflowing. */
    .wp-admin-bar-howdy { display: none; }
    .wp-admin-bar { overflow-x: auto; }

    /* Mobile-only reorder of the admin bar's links — Log Out first
       on the left, then View Site, then Dashboard, with the
       hamburger pushed to the far right by the spacer. Desktop
       keeps the original DOM order (View Site, Dashboard, ...,
       Log Out) untouched — this is a pure visual reorder via CSS
       order, not a DOM change, specifically because it should only
       apply on mobile. */
    .wp-admin-bar-logout { order: 1; }
    .wp-admin-bar-site { order: 2; }
    .wp-admin-bar-home { order: 3; }
    .wp-admin-bar-spacer { order: 4; }
    .admin-mobile-nav-toggle { order: 5; }

    /* Hamburger toggle — visible on mobile only, sitting inline in
       the top admin bar itself (right next to Log Out), not as its
       own separate row below the bar — a compact icon button that
       matches the bar's own existing link styling (same height,
       same horizontal padding) rather than the standalone card
       style a toggle placed outside the bar would need. */
    .admin-mobile-nav-toggle {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        height: 100%;
        padding: 0 12px;
        background: none;
        border: none;
        cursor: pointer;
    }
    .admin-mobile-nav-toggle span {
        display: block;
        width: 16px;
        height: 2px;
        background: #cfc7e0;
        border-radius: 1px;
    }
    .admin-mobile-nav-toggle:hover span { background: var(--gold); }

    /* The sidebar becomes a fixed slide-out drawer, off-screen by
       default so it never pushes or overlaps page content — only
       the .open state (toggled by the hamburger) brings it on
       screen, above everything else via z-index. */
    .admin-nav {
        position: fixed;
        top: 0;
        left: -300px;
        bottom: 0;
        width: 280px;
        max-height: 100vh;
        height: 100vh;
        z-index: 310;
        border-radius: 0;
        box-shadow: 4px 0 24px rgba(0,0,0,0.4);
        transition: left 0.25s ease;
        overflow-y: auto;
    }
    .admin-nav.open { left: 0; }

    .admin-mobile-nav-backdrop {
        display: none;
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,0.55);
        z-index: 300;
    }
    .admin-mobile-nav-backdrop.open { display: block; }

    /* Content fills the full width underneath — the drawer overlays
       it rather than sharing space with it. */
    .admin-content { width: 100%; }
}

/* ---------------------------------------------------------
   Text-to-Speech player — fixed audiobook-style bar at the
   bottom of the viewport while active. Only ever rendered for
   an unlocked chapter (see chapter.php's $isUnlocked check) —
   there is no client-side path to show this for locked content.
   --------------------------------------------------------- */
.tts-player {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 95;
    background: var(--card-bg);
    border-top: 1px solid var(--border);
    box-shadow: 0 -6px 24px rgba(0,0,0,0.35);
    padding: 10px 16px 12px;
}
.tts-player-inner { max-width: 720px; margin: 0 auto; }
.tts-progress-row { display: flex; align-items: center; gap: 10px; }
.tts-time { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 34px; }
.tts-time:last-child { text-align: right; }
.tts-progress-track {
    flex: 1;
    height: 6px;
    background: var(--border);
    border-radius: 3px;
    cursor: pointer;
    position: relative;
}
.tts-progress-fill {
    height: 100%;
    width: 0%;
    background: var(--gold);
    border-radius: 3px;
    transition: width 0.15s linear;
}
.tts-controls-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.tts-btn {
    background: none;
    border: 1px solid var(--border);
    color: var(--text);
    width: 34px;
    height: 34px;
    border-radius: 50%;
    cursor: pointer;
    font-size: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.tts-btn:hover { border-color: var(--gold); }
.tts-btn-play { background: var(--gold); color: #1B1730; border: none; width: 40px; height: 40px; font-size: 16px; }
.tts-btn-play:hover { background: #F2B457; }
.tts-btn-close { margin-left: auto; }
.tts-volume-row { display: flex; align-items: center; gap: 6px; flex: 1; max-width: 140px; font-size: 13px; }
.tts-volume-row input[type="range"] { flex: 1; }
body.tts-player-open { padding-bottom: 88px; }

.tts-resume-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 96;
    width: 100%;
    background: var(--gold);
    color: #1B1730;
    border: none;
    padding: 16px;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 -6px 24px rgba(0,0,0,0.35);
    animation: ttsResumePulse 1.6s ease-in-out infinite;
}
@keyframes ttsResumePulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.85; }
}

@media (max-width: 640px) {
    .tts-volume-row { display: none; }
}

/* ---------------------------------------------------------
   Reading settings — small button fixed to the right edge,
   opens a slide-in panel. Stays accessible after closing.
   --------------------------------------------------------- */
.settings-fab {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 120;
    background: var(--gold);
    color: #1B1730;
    border: none;
    width: 42px;
    height: 52px;
    border-radius: 8px 0 0 8px;
    font-size: 18px;
    cursor: pointer;
    box-shadow: -2px 2px 10px rgba(0,0,0,0.25);
    transition: width 0.15s ease, box-shadow 0.15s ease;
}
.settings-fab:hover { width: 46px; box-shadow: -4px 4px 16px rgba(232,163,61,0.3); }
.settings-slide-panel {
    position: fixed;
    top: 0;
    right: -320px;
    width: 300px;
    max-width: 85vw;
    height: 100vh;
    background: var(--card-bg);
    border-left: 1px solid var(--border);
    box-shadow: -6px 0 24px rgba(0,0,0,0.35);
    z-index: 130;
    overflow-y: auto;
    transition: right 0.25s ease;
}
.settings-slide-panel.open { right: 0; }
.settings-slide-panel .modal-header { border-bottom: 1px solid var(--border); }

/* Voice Library — the richer voice picker modal, opened from the
   "Choose Voice" button in Reading Settings. Deliberately built in
   this site's own existing gold/dark palette (not a separate theme)
   so it reads as part of the same product, not a bolted-on widget. */
.voice-library-box { max-width: 900px; width: 100%; height: 90vh; max-height: 880px; }
.voice-library-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 18px 22px;
    border-bottom: 1px solid var(--border);
}
.voice-library-header h3 { font-family: var(--font-display); font-size: 18px; }
.voice-library-body { display: flex; flex: 1; overflow: hidden; }
.voice-library-sidebar {
    width: 240px;
    flex-shrink: 0;
    border-right: 1px solid var(--border);
    padding: 14px;
    overflow-y: auto;
}
.voice-library-lang-list-heading {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--muted);
    font-weight: 700;
    margin: 14px 0 6px;
    padding: 0 4px;
}
.voice-library-lang-list-heading:first-child { margin-top: 0; }
.voice-library-lang-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 9px 10px;
    border-radius: 6px;
    border: none;
    background: none;
    color: var(--text);
    font-size: 13.5px;
    text-align: left;
    cursor: pointer;
}
.voice-library-lang-btn:hover { background: var(--card-bg-2); }
.voice-library-lang-btn.active { background: var(--gold); color: #1B1730; font-weight: 700; }
.voice-library-lang-btn .lang-count { font-size: 11px; opacity: 0.75; }
.voice-library-main { flex: 1; display: flex; flex-direction: column; padding: 16px 20px; overflow: hidden; }
.voice-library-gender-tabs { display: flex; gap: 10px; margin-bottom: 14px; flex-shrink: 0; }
.voice-library-gender-tab {
    padding: 8px 16px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--card-bg-2);
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}
.voice-library-gender-tab.active { background: var(--gold); color: #1B1730; border-color: var(--gold); }
.voice-library-cards { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.voice-library-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--card-bg-2);
    cursor: pointer;
}
.voice-library-card:hover { border-color: var(--gold); }
.voice-library-card.selected { border-color: var(--gold); background: rgba(212, 175, 55, 0.12); }
.voice-library-card-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--gold);
    color: #1B1730;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 14px;
    flex-shrink: 0;
}
.voice-library-card-info { flex: 1; min-width: 0; }
.voice-library-card-name { font-weight: 700; font-size: 14px; }
.voice-library-card-meta { font-size: 12px; color: var(--muted); }
.voice-library-card-preview-btn {
    flex-shrink: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 7px 12px;
    color: var(--text);
    font-size: 12.5px;
    cursor: pointer;
}
.voice-library-card-preview-btn:hover { border-color: var(--gold); color: var(--gold); }
.voice-library-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-top: 1px solid var(--border);
    flex-wrap: wrap;
}
@media (max-width: 720px) {
    .voice-library-box { height: 92vh; max-height: none; }
    .voice-library-body { flex-direction: column; }
    .voice-library-sidebar {
        width: 100%;
        max-height: 160px;
        border-right: none;
        border-bottom: 1px solid var(--border);
    }
}
@media (max-width: 480px) {
    .settings-fab { height: 46px; width: 38px; }
}

/* ---------------------------------------------------------
   Toast / popup notifications
   --------------------------------------------------------- */
#toast-container {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 300;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
    pointer-events: none;
}
.toast {
    background: var(--card-bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 4px solid var(--gold);
    padding: 12px 20px;
    border-radius: 8px;
    font-size: 14px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.35);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.25s ease, transform 0.25s ease;
    max-width: 90vw;
}
.toast-show { opacity: 1; transform: translateY(0); }
.toast-success { border-left-color: var(--success-text); }
.toast-error { border-left-color: var(--primary); }
.toast-info { border-left-color: var(--gold); }

/* ---------------------------------------------------------
   Comments
   --------------------------------------------------------- */
.comments-toggle-row { margin-top: 20px; }
.comments-body { margin-top: 14px; }
.comment-item { margin-top: 12px; }
.comment-bubble {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 14px;
    transition: border-color 0.15s ease;
}
.comment-meta { font-size: 12px; margin-bottom: 4px; }
.comment-body { font-size: 14px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }

/* Blank avatar placeholder — a colored circle with the user's
   first initial, shown next to gossip messages and comments. */
.avatar-circle {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), #6B4FA0);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    flex-shrink: 0;
    box-shadow: 0 2px 6px rgba(0,0,0,0.25);
}
.message-row { display: flex; gap: 10px; align-items: flex-start; }
.typing-indicator { font-size: 12px; color: var(--muted); font-style: italic; padding: 6px 0; min-height: 18px; }
.gossip-guidelines {
    background: rgba(232,163,61,0.1);
    border: 1px solid rgba(232,163,61,0.25);
    border-radius: 8px;
    padding: 10px 14px;
    font-size: 12px;
    color: var(--muted);
    margin: 14px 0;
}
.tab-bar {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.tab-bar::-webkit-scrollbar { height: 6px; }
.tab-bar::-webkit-scrollbar-track { background: transparent; }
.tab-bar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.tab-bar::-webkit-scrollbar-thumb:hover { background: var(--gold); }
.tab-btn {
    background: none;
    border: none;
    color: var(--muted);
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 14px;
    padding: 12px 18px;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    white-space: nowrap;
    flex-shrink: 0;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.tab-btn.active { color: var(--gold); border-bottom-color: var(--gold); }
.tab-btn:hover { color: var(--text); }

.currency-toggle-btn {
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 12.5px;
    padding: 8px 14px;
    border-radius: 20px;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.currency-toggle-btn:hover { border-color: var(--gold); color: var(--text); }
.currency-toggle-btn.active { background: var(--gold); border-color: var(--gold); color: #1B1730; }
.tab-panel { display: none; animation: tabFadeIn 0.2s ease; }
.tab-panel.active { display: block; }
@keyframes tabFadeIn { from { opacity: 0; } to { opacity: 1; } }

/* FAQ-style collapsible sections — used on the account page so a
   reader sees one clean list of section titles at a glance (Profile,
   Notifications, Achievements, Bookmarks, Favorite Novels, Reading
   History) rather than every section's full content stacked on the
   page at once. Deliberately a separate set of classes from
   .tab-btn/.tab-panel above, which are shared by many other pages
   site-wide as an actual tab switcher — this is a genuine expand/
   collapse accordion instead, where more than one section can be
   open at a time. */
.accordion-section { border: 1px solid var(--border); border-radius: var(--admin-radius, 8px); margin-bottom: 10px; overflow: hidden; }
.accordion-header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px;
    background: var(--card-bg);
    border: none;
    cursor: pointer;
    font-family: var(--font-heading, inherit);
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    text-align: left;
}
.accordion-header:hover { background: var(--card-bg-2, var(--card-bg)); }
.accordion-chevron { transition: transform 0.2s ease; color: var(--muted); flex-shrink: 0; }
.accordion-header[aria-expanded="true"] .accordion-chevron { transform: rotate(180deg); }
.accordion-body { display: none; padding: 4px 16px 18px; }
.accordion-body.accordion-open { display: block; animation: tabFadeIn 0.2s ease; }

/* Form rows (e.g. chapter number + title side by side) */
.form-row { display: flex; gap: 16px; flex-wrap: wrap; }
.form-row .form-group { margin-bottom: 16px; }
.form-row-3col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; align-items: end; }
.form-row-4col { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 16px; align-items: end; }
@media (max-width: 640px) {
    .form-row-3col, .form-row-4col { grid-template-columns: 1fr; }
}

/* Fixed-height, scrollable content editor — stays a manageable
   size no matter how much text/how many paragraphs are entered */
.fixed-height-editor .ql-editor { height: 340px; overflow-y: auto; }
/* Same fixed-height, scrollable treatment for the Synopsis editor
   on Add/Edit Novel — without an explicit height here, min-height
   on the outer container alone doesn't reliably constrain Quill's
   own inner .ql-editor, letting a longer synopsis grow the editor
   tall enough to visually overlap the Tags section rendered right
   below it in the page layout. !important guards against Quill's
   own bundled CSS (loaded from its CDN, after this stylesheet)
   setting a conflicting height on the same element. overflow:hidden
   on the container itself is a second, redundant safeguard — even
   if the inner .ql-editor were somehow taller than its own set
   height for any reason, the container physically cannot let that
   overflow bleed into the page below it.
   */
#synopsis-editor { overflow: hidden; }
#synopsis-editor .ql-editor { height: 220px !important; max-height: 220px !important; overflow-y: auto !important; }

/* Text-to-speech paragraph highlighting — the paragraph containing
   the word currently being spoken gets a left accent bar, so it's
   easy to spot at a glance which part of a longer chapter is
   currently playing. (Word-level highlighting existed here too at
   one point; removed on request — .tts-word spans are still wrapped
   around every word for the auto-scroll-to-position logic, they're
   just never visually marked as active anymore.) */
.tts-active-paragraph {
    border-left: 3px solid var(--gold);
    padding-left: 10px;
    margin-left: -13px;
}
/* Quill's own editor area keeps its default white background, but
   this site's dark theme sets a light text color on <body> that
   was cascading straight into the editor uncorrected — light text
   on Quill's white background is exactly white-on-white,
   unreadable while typing. Explicit dark text + white background
   here, regardless of the surrounding page's theme. */
.ql-editor, .ql-editor.ql-blank::before {
    color: #1a1a1a;
    background: #fff;
}
.ql-toolbar { background: #f4f2f7; border-color: var(--border) !important; }
.ql-container { border-color: var(--border) !important; }

/* List toolbar (search + sort, admin & reader chapter lists) */
.list-toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }

/* Quill editor — align with site theme */
#chapter-editor { background: #FAF7F1; color: #241F3B; border-radius: 0 0 6px 6px; min-height: 260px; }
.ql-toolbar.ql-snow { border-radius: 6px 6px 0 0; background: #FAF7F1; }
.ql-container.ql-snow { border-color: var(--border); }
.ql-toolbar.ql-snow { border-color: var(--border); }

/* Paragraph highlights / reading pins — a reader-selected paragraph
   marked to visually stand out and to jump straight back to on a
   later visit (see chapter.php's highlight JS and
   highlight_paragraph_ajax.php). Each color is a soft, semi-
   transparent tint so the underlying text stays fully readable
   regardless of light/dark reading theme. */
.paragraph-highlight-gold { background: rgba(232,163,61,0.22); border-radius: 4px; scroll-margin-top: 90px; }
.paragraph-highlight-pink { background: rgba(232,61,140,0.18); border-radius: 4px; scroll-margin-top: 90px; }
.paragraph-highlight-green { background: rgba(61,200,120,0.18); border-radius: 4px; scroll-margin-top: 90px; }
.paragraph-highlight-blue { background: rgba(61,140,232,0.18); border-radius: 4px; scroll-margin-top: 90px; }
/* Positioned below the selection/paragraph, not above it — mobile's
   native selection toolbar (Copy/Share/Select all/Web search) can't
   be reliably suppressed by any web page (a genuine, long-standing
   platform limitation, not something this site's own code can turn
   off), and it always appears directly above the selection. Showing
   this popup below instead is what actually keeps the two from
   covering each other, since fighting the native one isn't a real
   option. */
#highlight-popup, #highlight-remove-popup { transform: translate(-50%, 0); margin-top: 10px; }

/* ---------------------------------------------------------
   Horizontal category selector (category.php)
   --------------------------------------------------------- */
.category-nav-wrap {
    display: flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    /* overflow-x:hidden here, not just on the scroll strip inside —
       this is what actually guarantees the row (and the mouse-drag
       scrolling below) can never cause the *page itself* to scroll
       sideways, only the strip's own contents. */
    overflow-x: hidden;
}
.category-nav-scroll {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scroll-behavior: smooth;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    padding: 4px 2px 10px;
    flex: 1;
    min-width: 0;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
    cursor: grab;
}
.category-nav-scroll.dragging { cursor: grabbing; scroll-behavior: auto; user-select: none; }
.category-nav-scroll::-webkit-scrollbar { height: 6px; }
.category-nav-scroll::-webkit-scrollbar-track { background: transparent; }
.category-nav-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.category-nav-scroll::-webkit-scrollbar-thumb:hover { background: var(--gold); }
.category-nav-btn {
    flex-shrink: 0;
    scroll-snap-align: start;
    white-space: nowrap;
    padding: 8px 18px;
    border-radius: 20px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
    font-size: 13.5px;
    font-weight: 600;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.category-nav-btn:hover { border-color: var(--gold); color: var(--gold); }
.category-nav-btn.active { background: var(--gold); border-color: var(--gold); color: #1B1730; }
.category-nav-arrow {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    display: none; /* shown on desktop only, below — "on desktop if useful" */
}
.category-nav-arrow:hover { border-color: var(--gold); color: var(--gold); }
@media (min-width: 641px) {
    .category-nav-arrow { display: flex; align-items: center; justify-content: center; }
}
