/* GodWeb - Celestial Path Overhaul
 * --------------------------------------------------------------------
 * "Dual Realms" UI/UX layer that extends the existing Xianxia theme.
 *
 * This stylesheet loads LAST so it can:
 *   1) Force a silver / pale spirit-fire-blue default for text under
 *      html.theme-dark (the "no black text on dark backgrounds" fix
 *      called out in the FEAT-002 design brief).
 *   2) Wrap the existing moon/sun toggle icons in a rotating Yin-Yang
 *      (Taiji) ring without breaking the SVG-icon contract enforced by
 *      tests/test_theme_toggle.py.
 *   3) Provide the `.xx-mortal-card` (aged bamboo scroll) and
 *      `.xx-immortal-card` (animated linh-khi aura + talisman badge +
 *      hover ascend / mist) variants the brief calls for.
 *   4) Add a silk shimmer pass over the announcement ticker.
 * ------------------------------------------------------------------ */

/* ════════════════════════════════════════════════════════════════
 * 1. Dual Realms palette (user-supplied tokens layered on top of the
 *    existing xianxia palette so the rest of the app keeps working).
 * ════════════════════════════════════════════════════════════════ */
:root {
    /* Demonic / Ghostly Realm — dark mode anchor tones */
    --cp-ink-obsidian: #0b0b0b;
    --cp-soul-purple: #7c3aed;
    --cp-crimson: #dc2626;
    --cp-silver-white: #e8e4f0;
    --cp-spirit-fire-blue: #cbeaff;
    --cp-spirit-fire-blue-soft: rgba(203, 234, 255, 0.9);

    /* Heavenly Realm — light mode anchor tones */
    --cp-polished-jade: #00a86b;
    --cp-imperial-gold: #ffd700;
    --cp-porcelain: #fbfaf3;
    --cp-ink-soft: #1e293b;
}

/* ════════════════════════════════════════════════════════════════
 * 2. Dark-Mode Typography Safety Net
 *    Loads after every other stylesheet so any element that would
 *    otherwise inherit color: #1f2937 / var(--dark-color) on a dark
 *    surface gets force-promoted to silver-white. Specific overrides
 *    elsewhere (premium gold, jade gradients, danger reds, etc.)
 *    still win because they are more specific than these element-level
 *    rules.
 * ════════════════════════════════════════════════════════════════ */
html.theme-dark,
html.theme-dark body {
    color: var(--cp-silver-white);
}

html.theme-dark h1,
html.theme-dark h2,
html.theme-dark h3,
html.theme-dark h4,
html.theme-dark h5,
html.theme-dark h6 {
    color: var(--cp-silver-white);
}

html.theme-dark p,
html.theme-dark li,
html.theme-dark dt,
html.theme-dark dd,
html.theme-dark label,
html.theme-dark blockquote,
html.theme-dark figcaption,
html.theme-dark summary {
    color: var(--cp-silver-white);
}

/* Spans, table cells and form controls that previously inherited a
 * near-black color from style.css now read as Pale Spirit-Fire Blue —
 * still legible, but distinct from headings so visual hierarchy
 * survives. */
html.theme-dark span,
html.theme-dark small,
html.theme-dark td,
html.theme-dark th,
html.theme-dark input,
html.theme-dark textarea,
html.theme-dark select {
    color: var(--cp-spirit-fire-blue-soft);
}

/* …but explicitly-coloured tokens (jade pills, gold prices, danger
 * badges) must keep their original colour. These selectors carry the
 * design system's intent and override the safety net by being equally
 * specific yet listed later. */
html.theme-dark .card-price,
html.theme-dark .card-price *,
html.theme-dark .premium-badge,
html.theme-dark .premium-badge *,
html.theme-dark .filter-tag.active,
html.theme-dark .btn-primary,
html.theme-dark .btn-secondary,
html.theme-dark .alert,
html.theme-dark .alert *,
html.theme-dark .badge,
html.theme-dark .stock-badge,
html.theme-dark .section-title h2 {
    color: inherit;
}

/* Anchors inside dark cards: pale spirit-blue so they still read as
 * links without falling back to body black. */
html.theme-dark .card a:not(.btn):not(.premium-badge),
html.theme-dark .post-card a:not(.btn):not(.premium-badge),
html.theme-dark .product-card a:not(.btn):not(.premium-badge) {
    color: var(--cp-spirit-fire-blue);
}

/* ════════════════════════════════════════════════════════════════
 * 3. Yin-Yang (Taiji) Theme Toggle
 *    The existing `.theme-icon-moon` / `.theme-icon-sun` SVGs are
 *    preserved (the test suite asserts they live inside the toggle
 *    button), but they are now overlaid on top of a rotating Yin-Yang
 *    disc rendered via SVG <use>. The disc rotates 0deg→180deg when
 *    switching realms — the moon half/sun half visually swap sides.
 * ════════════════════════════════════════════════════════════════ */

.theme-toggle-btn {
    position: relative;
    width: 44px;
    height: 44px;
    padding: 0;
    border-radius: 50%;
    overflow: visible;
    isolation: isolate;
}

.theme-toggle-btn .theme-yinyang-ring,
#mobileThemeToggle .theme-yinyang-ring {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5em;
    height: 1.5em;
    vertical-align: middle;
    flex: 0 0 auto;
    margin-right: 0.4em;
    transition:
        transform 0.6s cubic-bezier(0.2, 0.8, 0.3, 1),
        filter 0.4s ease;
    will-change: transform;
    filter: drop-shadow(0 0 4px rgba(251, 191, 36, 0.35));
}

.theme-toggle-btn .theme-yinyang-ring {
    position: absolute;
    inset: 0;
    margin: 0;
    width: 100%;
    height: 100%;
}

.theme-toggle-btn .theme-yinyang-ring svg,
#mobileThemeToggle .theme-yinyang-ring svg {
    width: 100%;
    height: 100%;
    display: block;
}

/* Dark realm: ring at 0deg, "yang" (white) half on top so the sun
 * icon overlaying it reads correctly.
 * Light realm: ring rotates 180deg so the "yin" (black) half is on
 * top, ready to host the moon. */
html.theme-dark .theme-yinyang-ring { transform: rotate(0deg); }
html.theme-light .theme-yinyang-ring { transform: rotate(180deg); }
html:not(.theme-light):not(.theme-dark) .theme-yinyang-ring { transform: rotate(0deg); }

/* The existing moon/sun icons sit on top of the ring. Keep their CSS
 * visibility rules in style.css (lines 19-24) — we only re-position
 * them so they overlay the centre of the taiji disc. */
.theme-toggle-btn .theme-icon-moon,
.theme-toggle-btn .theme-icon-sun {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 1em;
    height: 1em;
    color: #fff7c8;
    filter: drop-shadow(0 0 6px rgba(255, 215, 0, 0.7));
    z-index: 1;
    pointer-events: none;
}

#mobileThemeToggle {
    display: flex;
    align-items: center;
    gap: 0.45em;
}

#mobileThemeToggle .theme-icon-moon,
#mobileThemeToggle .theme-icon-sun {
    position: static;
    width: 1em;
    height: 1em;
    margin: 0;
    filter: drop-shadow(0 0 4px rgba(255, 215, 0, 0.6));
}

/* When mobile toggle has the yinyang ring, the existing icon classes
 * become inline siblings — the CSS in style.css already toggles their
 * visibility, so we only have to make sure the layout doesn't break. */
#mobileThemeToggle .theme-yinyang-ring + .theme-icon-moon,
#mobileThemeToggle .theme-yinyang-ring + .theme-icon-sun {
    display: none;
}
html.theme-dark #mobileThemeToggle .theme-icon-sun { display: inline-block; }
html.theme-light #mobileThemeToggle .theme-icon-moon { display: inline-block; }
html:not(.theme-light):not(.theme-dark) #mobileThemeToggle .theme-icon-sun { display: inline-block; }

.theme-toggle-btn:hover .theme-yinyang-ring,
#mobileThemeToggle:hover .theme-yinyang-ring {
    filter: drop-shadow(0 0 10px rgba(251, 191, 36, 0.65));
}

/* In light mode, give the toggle a soft jade halo instead of gold so
 * it visually agrees with the Heavenly Realm palette. */
body.light-mode .theme-toggle-btn .theme-icon-moon,
body.light-mode #mobileThemeToggle .theme-icon-moon {
    color: var(--cp-ink-soft);
    filter: drop-shadow(0 0 4px rgba(0, 168, 107, 0.4));
}

body.light-mode .theme-toggle-btn .theme-yinyang-ring,
body.light-mode #mobileThemeToggle .theme-yinyang-ring {
    filter: drop-shadow(0 0 4px rgba(0, 168, 107, 0.35));
}

/* ════════════════════════════════════════════════════════════════
 * 4. Mortal Posts — "Aged Bamboo Scroll"
 *    Default card variant for non-premium blog posts. Soft drop
 *    shadow, brushstroke top/bottom rules, and a parchment hue that
 *    reads as bamboo without overwhelming the existing card layout.
 * ════════════════════════════════════════════════════════════════ */
.xx-mortal-card {
    position: relative;
    border: 1px solid rgba(184, 134, 11, 0.18);
    box-shadow:
        0 6px 20px -10px rgba(0, 0, 0, 0.55),
        0 2px 6px -3px rgba(0, 0, 0, 0.35),
        inset 0 0 0 1px rgba(232, 228, 217, 0.04);
    background:
        linear-gradient(160deg,
            rgba(28, 26, 38, 0.94) 0%,
            rgba(14, 14, 22, 0.96) 60%,
            rgba(20, 18, 26, 0.96) 100%);
}

.xx-mortal-card::before,
.xx-mortal-card::after {
    content: "";
    position: absolute;
    left: 6%;
    right: 6%;
    height: 1px;
    background: linear-gradient(90deg,
        transparent,
        rgba(192, 139, 0, 0.35) 20%,
        rgba(184, 134, 11, 0.5) 50%,
        rgba(192, 139, 0, 0.35) 80%,
        transparent);
    pointer-events: none;
    z-index: 1;
}

.xx-mortal-card::before { top: 0; }
.xx-mortal-card::after { bottom: 0; }

.xx-mortal-card:hover {
    transform: translateY(-2px);
    box-shadow:
        0 12px 28px -12px rgba(0, 0, 0, 0.6),
        0 4px 10px -3px rgba(0, 0, 0, 0.4),
        inset 0 0 0 1px rgba(232, 228, 217, 0.06);
    border-color: rgba(192, 139, 0, 0.35);
}

body.light-mode .xx-mortal-card {
    background:
        linear-gradient(160deg,
            #fdfcf5 0%,
            #f7f3e3 60%,
            #f3eed7 100%);
    border-color: rgba(184, 134, 11, 0.25);
    box-shadow:
        0 6px 18px -10px rgba(120, 90, 20, 0.25),
        0 2px 6px -3px rgba(120, 90, 20, 0.18),
        inset 0 0 0 1px rgba(255, 255, 255, 0.6);
}

body.light-mode .xx-mortal-card::before,
body.light-mode .xx-mortal-card::after {
    background: linear-gradient(90deg,
        transparent,
        rgba(120, 90, 20, 0.35) 20%,
        rgba(120, 90, 20, 0.55) 50%,
        rgba(120, 90, 20, 0.35) 80%,
        transparent);
}

/* ════════════════════════════════════════════════════════════════
 * 5. Immortal Posts — "Linh Khí Aura + Talisman Badge"
 *    Layered on top of the existing `.xx-vip-card` styling. The conic
 *    gradient border simulates spiritual aura flowing around the card.
 *    The Talisman Badge takes over from `.premium-badge` and adds the
 *    paper-charm look with a pulsating glow + corner stamp.
 * ════════════════════════════════════════════════════════════════ */
/* Compound `.card.xx-immortal-card` matches the legacy
 * `.card:has(.premium-badge)` specificity (0,2,0) so the `overflow:
 * hidden` actually wins over `xianxia-theme.css`' `overflow: visible`
 * — otherwise the rotating conic-gradient aura sweeps outside the
 * card and reads as red "ghosting" diagonals around each VIP post
 * (the original bug this overhaul shipped to kill). */
.card.xx-immortal-card,
.xx-immortal-card {
    position: relative;
    isolation: isolate;
    border-radius: 18px;
    border: 1px solid rgba(251, 191, 36, 0.28);
    background:
        linear-gradient(160deg,
            rgba(38, 28, 56, 0.96) 0%,
            rgba(18, 14, 30, 0.98) 55%,
            rgba(28, 16, 42, 0.96) 100%);
    box-shadow:
        0 16px 42px -18px rgba(124, 58, 237, 0.45),
        0 8px 22px -10px rgba(251, 191, 36, 0.18),
        inset 0 0 0 1px rgba(251, 191, 36, 0.08);
    overflow: hidden;
    transition:
        transform 0.45s cubic-bezier(0.2, 0.8, 0.3, 1),
        box-shadow 0.45s,
        border-color 0.45s;
}

/* Spiritual aura: a conic-gradient border that spins via its
 * `from <angle>` parameter — NOT a `transform: rotate` on the whole
 * pseudo-element. Rotating the rectangle itself made the bounding box
 * sweep outside the card and read as red "ghosting" diagonals; spinning
 * just the gradient's start angle keeps the pseudo's geometry fixed.
 *
 * Specificity note: legacy `.card:has(.premium-badge)::before` in
 * xianxia-theme.css computes to (0,2,0). We use `.card.xx-immortal-card`
 * here so we match it on specificity AND win on order (this file loads
 * after xianxia-theme.css), ensuring the conic aura replaces the older
 * linear-gradient pulse. */
@property --xx-aura-spin {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}

.card.xx-immortal-card::before,
.xx-immortal-card::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 2px;
    background: conic-gradient(
        from var(--xx-aura-spin),
        rgba(251, 191, 36, 0.75),
        rgba(167, 139, 250, 0.55),
        rgba(45, 212, 160, 0.45),
        rgba(220, 38, 38, 0.45),
        rgba(251, 191, 36, 0.75)
    );
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
    animation: xxImmortalAura 6s linear infinite;
    pointer-events: none;
    z-index: 0;
    opacity: 0.85;
}

@keyframes xxImmortalAura {
    from { --xx-aura-spin: 0deg; }
    to   { --xx-aura-spin: 360deg; }
}

/* Older browsers without @property support can't animate the gradient
 * angle. Hold a static aura rather than fall back to the old transform
 * rotation, which is what caused the diagonal bleed. */
@supports not (background: paint(none)) {
    .card.xx-immortal-card::before,
    .xx-immortal-card::before {
        animation: none;
    }
}

/* Faint inner radial halo so the aura feels like it's emanating
 * outward from the card content. */
.card.xx-immortal-card::after,
.xx-immortal-card::after {
    content: "";
    position: absolute;
    inset: 6%;
    border-radius: inherit;
    background: radial-gradient(ellipse at 30% 20%,
        rgba(251, 191, 36, 0.10),
        transparent 65%);
    pointer-events: none;
    z-index: 0;
}

.xx-immortal-card > * {
    position: relative;
    z-index: 1;
}

.xx-immortal-card:hover {
    transform: translateY(-6px) scale(1.012);
    border-color: rgba(251, 191, 36, 0.55);
    box-shadow:
        0 28px 60px -22px rgba(124, 58, 237, 0.55),
        0 14px 28px -10px rgba(251, 191, 36, 0.28),
        0 0 36px -2px rgba(251, 191, 36, 0.18),
        inset 0 0 0 1px rgba(251, 191, 36, 0.18);
}

/* Dark-mode hover speed-up — must use the shorthand `animation:` so
 * we override the legacy `.card:has(.premium-badge):hover::before
 * { animation: none; }` rule in xianxia-theme.css (same specificity,
 * but we load after). If we only set animation-duration, animation-name
 * stays "none" from the legacy rule and the aura stops spinning. */
.card.xx-immortal-card:hover::before,
.xx-immortal-card:hover::before {
    opacity: 1;
    animation: xxImmortalAura 3.5s linear infinite;
}

/* Light-mode hover override — same speed-up + opacity boost as dark
 * mode but must be re-declared because the light-mode base rule above
 * re-pins opacity and animation. */
body.light-mode .card.xx-immortal-card:hover::before,
body.light-mode .xx-immortal-card:hover::before {
    opacity: 1;
    animation: xxImmortalAura 3.5s linear infinite;
}

/* Talisman Badge — paper-charm with pulsating glow. Targets
 * `.premium-badge` whenever it lives inside an Immortal card, so the
 * existing templates don't need to add a new class. */
.xx-immortal-card .premium-badge {
    position: relative;
    padding: 6px 14px 6px 22px;
    background:
        linear-gradient(160deg, #fff4c4 0%, #fbbf24 55%, #c08b00 100%);
    color: #3a1f00 !important;
    border-radius: 4px 12px 4px 12px;
    font-family: "Cinzel Decorative", "Ma Shan Zheng", serif;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    box-shadow:
        0 0 10px rgba(251, 191, 36, 0.55),
        0 0 22px rgba(251, 191, 36, 0.25),
        inset 0 0 0 1px rgba(255, 255, 255, 0.45);
    animation: xxTalismanPulse 2.4s ease-in-out infinite;
}

/* Red stamp seal on the left edge of the talisman */
.xx-immortal-card .premium-badge::before {
    content: "";
    position: absolute;
    left: 4px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
    border-radius: 2px;
    background: radial-gradient(circle at 35% 35%, #ef4444, #7f1d1d);
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.4),
        0 0 6px rgba(220, 38, 38, 0.4);
}

/* Faint folded-paper crease across the talisman */
.xx-immortal-card .premium-badge::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        repeating-linear-gradient(90deg,
            transparent 0,
            transparent 6px,
            rgba(120, 80, 0, 0.06) 6px,
            rgba(120, 80, 0, 0.06) 7px);
    border-radius: inherit;
    pointer-events: none;
}

@keyframes xxTalismanPulse {
    0%, 100% {
        box-shadow:
            0 0 8px rgba(251, 191, 36, 0.40),
            0 0 16px rgba(251, 191, 36, 0.18),
            inset 0 0 0 1px rgba(255, 255, 255, 0.40);
    }
    50% {
        box-shadow:
            0 0 16px rgba(251, 191, 36, 0.75),
            0 0 36px rgba(251, 191, 36, 0.45),
            0 0 60px rgba(167, 139, 250, 0.25),
            inset 0 0 0 1px rgba(255, 255, 255, 0.55);
    }
}

/* Mist that drifts upward from the bottom of the Immortal card on
 * hover — uses CSS only so it works even if xianxia-interactions.js
 * hasn't initialised yet. The JS module already emits richer
 * particles for richer browsers. */

.xx-immortal-card .xx-immortal-mist {
    position: absolute;
    inset: auto 0 0 0;
    height: 40%;
    pointer-events: none;
    background:
        radial-gradient(ellipse 60% 60% at 20% 100%, rgba(167, 139, 250, 0.18), transparent 70%),
        radial-gradient(ellipse 60% 60% at 80% 100%, rgba(251, 191, 36, 0.14), transparent 70%);
    opacity: 0;
    transition: opacity 0.4s ease;
    z-index: 0;
}

.xx-immortal-card:hover .xx-immortal-mist {
    opacity: 1;
    animation: xxImmortalMistDrift 4s ease-in-out infinite;
}

@keyframes xxImmortalMistDrift {
    0%, 100% { transform: translateY(0) scale(1); opacity: 0.65; }
    50% { transform: translateY(-6px) scale(1.06); opacity: 1; }
}

/* Light-mode Immortal card: keep the aura but use porcelain + gold so
 * it reads in the Heavenly Realm. */
body.light-mode .xx-immortal-card {
    background:
        linear-gradient(160deg, #ffffff 0%, #fff8de 55%, #fff2c0 100%);
    border-color: rgba(255, 215, 0, 0.55);
    box-shadow:
        0 16px 38px -18px rgba(192, 139, 0, 0.35),
        0 8px 18px -10px rgba(192, 139, 0, 0.18),
        inset 0 0 0 1px rgba(255, 215, 0, 0.18);
}

body.light-mode .card.xx-immortal-card::before,
body.light-mode .xx-immortal-card::before {
    background: conic-gradient(
        from var(--xx-aura-spin),
        rgba(255, 215, 0, 0.85),
        rgba(124, 58, 237, 0.5),
        rgba(0, 168, 107, 0.55),
        rgba(220, 38, 38, 0.4),
        rgba(255, 215, 0, 0.85)
    );
    /* Re-pin the rotation animation in light mode — the legacy
     * `xianxia-theme-light.css` rule otherwise replaces it with the
     * older `xxVipAuraPulseLight` opacity pulse. */
    animation: xxImmortalAura 6s linear infinite;
    opacity: 0.7;
}

body.light-mode .card.xx-immortal-card::after,
body.light-mode .xx-immortal-card::after {
    background: radial-gradient(ellipse at 30% 20%,
        rgba(255, 215, 0, 0.18),
        transparent 65%);
}

body.light-mode .xx-immortal-card .premium-badge {
    color: #3a1f00 !important;
}

/* ════════════════════════════════════════════════════════════════
 * 6. Silk-Shimmer Announcement Ticker
 *    A thin diagonal sheen drifts across the announcement bar every
 *    few seconds — the "silk" motion the brief calls out. The
 *    underlying marquee track is untouched.
 * ════════════════════════════════════════════════════════════════ */
.site-ticker {
    position: relative;
    overflow: hidden;
}

.site-ticker::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(115deg,
        transparent 30%,
        rgba(255, 255, 255, 0.18) 48%,
        rgba(255, 255, 255, 0.32) 50%,
        rgba(255, 255, 255, 0.18) 52%,
        transparent 70%);
    transform: translateX(-100%);
    animation: xxSilkShimmer 6s linear infinite;
    mix-blend-mode: screen;
}

@keyframes xxSilkShimmer {
    0% { transform: translateX(-100%); }
    50% { transform: translateX(100%); }
    100% { transform: translateX(100%); }
}

body.light-mode .site-ticker::after {
    background: linear-gradient(115deg,
        transparent 30%,
        rgba(255, 248, 220, 0.45) 48%,
        rgba(255, 248, 220, 0.7) 50%,
        rgba(255, 248, 220, 0.45) 52%,
        transparent 70%);
}

/* ════════════════════════════════════════════════════════════════
 * 7. Reduced motion respect
 * ════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    .theme-yinyang-ring { transition: none; }
    .xx-immortal-card::before,
    .xx-immortal-card .premium-badge,
    .xx-immortal-card:hover .xx-immortal-mist,
    .site-ticker::after {
        animation: none;
    }
}

/* ════════════════════════════════════════════════════════════════
 * 8. Dual-Realm Palette Tokens — Heavenly Court ↔ Blood Mist
 *    Brief's canonical colour tokens (Radiant Gold, Ivory, Jade for
 *    the Heavenly Court; Deep Obsidian, Blood Red, Charcoal for the
 *    Blood Mist Underworld). Exposed as CSS variables so the rest of
 *    the realm-specific rules below stay readable.
 * ════════════════════════════════════════════════════════════════ */
:root {
    /* Heavenly Court — Light Mode anchor palette */
    --hc-radiant-gold: #FFD700;
    --hc-ivory-white: #FFFFF0;
    --hc-celestial-yellow: #FFFACD;
    --hc-jade-green: #00A86B;
    --hc-pure-white: #FFFFFF;

    /* Blood Mist Underworld — Dark Mode anchor palette */
    --bm-deepest-black: #050505;
    --bm-blood-red: #990000;
    --bm-blood-red-deep: #8B0000;
    --bm-crimson-glow: #B22222;
    --bm-charcoal: #1A1A1A;
    --bm-pale-gold: #F5E1A4;
    --bm-silver: #C0C0C0;
}

/* ════════════════════════════════════════════════════════════════
 * 9. Heavenly Court — Anti-Veil + Auspicious Cloud Background
 *    Kill every fixed-position dark element that bleeds through the
 *    Light Mode body gradient and replaces it with a soft Auspicious
 *    Cloud (Tường Vân) glow. This is the fix for the "grey veil"
 *    bug — the legacy `.xx-stars` div lives at `z-index:-3` and its
 *    `--lq-void` (#080810) base colour was dimming the entire Heavenly
 *    Court palette to ash.
 * ════════════════════════════════════════════════════════════════ */
html.theme-light .xx-stars,
body.light-mode .xx-stars {
    /* Strip the deep-void base colour and replace the radial nebulae
     * with auspicious-cloud gold/jade glows. */
    background:
        radial-gradient(1100px 700px at 50% 18%, rgba(255, 215, 0, 0.10), transparent 65%),
        radial-gradient(900px  650px at 12% 80%, rgba(0, 168, 107, 0.08), transparent 65%),
        radial-gradient(900px  650px at 88% 80%, rgba(255, 250, 205, 0.18), transparent 65%),
        radial-gradient(600px  500px at 50% 50%, rgba(255, 255, 255, 0.30), transparent 70%),
        #FFFFF0;
}

html.theme-light canvas.xx-stars-canvas,
body.light-mode canvas.xx-stars-canvas {
    /* The animated star canvas was authored for the void. Hide it
     * outright in the Heavenly Court so it can't blend down to grey. */
    display: none !important;
}

html.theme-light .xx-mountain-far,
html.theme-light .xx-mountain-near,
body.light-mode .xx-mountain-far,
body.light-mode .xx-mountain-near {
    /* Mountain silhouettes drawn with dark jade clip-paths read as
     * heavy grey blobs on white. Suppress them in the Heavenly Court. */
    display: none !important;
}

html.theme-light .fx-bg .fx-orb,
body.light-mode .fx-bg .fx-orb {
    /* The legacy fx-orbs are dark amber blurs anchored to the corners.
     * Re-tint them to a soft gold halo so they read as celestial qi. */
    background: radial-gradient(circle,
        rgba(255, 215, 0, 0.18),
        rgba(255, 250, 205, 0.10) 45%,
        transparent 70%) !important;
    opacity: 0.45;
}

/* The dark mist transition overlay defaults to a near-black gradient.
 * Swap it for an ivory ink-wash in the Heavenly Court so the World
 * Shift transition reads as a Heavenly mist rather than fog. */
html.theme-light #xx-mist-transition,
body.light-mode #xx-mist-transition {
    background:
        radial-gradient(ellipse at 30% 40%, rgba(255, 215, 0, 0.18), transparent 55%),
        radial-gradient(ellipse at 70% 60%, rgba(0, 168, 107, 0.12), transparent 55%),
        radial-gradient(ellipse at 50% 50%, rgba(255, 250, 205, 0.20), transparent 55%),
        linear-gradient(to bottom, rgba(255, 255, 240, 0.96), rgba(255, 255, 255, 0.98));
}

/* ════════════════════════════════════════════════════════════════
 * 10. Kill the "Ghosting Blocks" — floating swords + rune circles
 *     The translucent rotated rectangles the user spotted around the
 *     post cards came from `.xx-floating-sword` (a 60×8 px clipped
 *     gradient bar rotated via GSAP). They cluttered the layout in
 *     both realms — remove them and the orbiting rune discs entirely
 *     so the cards stand alone, replaced by their own contained
 *     animated borders (handled in section 11).
 * ════════════════════════════════════════════════════════════════ */
.xx-floating-sword,
.xx-floating-rune {
    display: none !important;
}

/* Keep the floating clouds but soften them further so they read as
 * Auspicious Vapour rather than literal blobs. */
.xx-floating-cloud {
    opacity: 0.05 !important;
    filter: blur(46px) !important;
}

/* ════════════════════════════════════════════════════════════════
 * 11. Immortal Card aura — Halo (Heavenly) ↔ Soul Mist (Demonic)
 *     Re-paints the conic-gradient border so it transforms between
 *     a pulsating gold halo in Light Mode and a flowing red/black
 *     soul-mist in Dark Mode. The aura still uses the existing
 *     `xxImmortalAura` keyframe (tests assert it stays present) so
 *     the rotation contract is preserved.
 * ════════════════════════════════════════════════════════════════ */

/* Dark Realm: pulsating crimson "Soul Mist" — drop the multicolour
 * spectrum and stay in the blood-red / soul-purple register. */
html.theme-dark .card.xx-immortal-card::before,
html.theme-dark .xx-immortal-card::before {
    background: conic-gradient(
        from var(--xx-aura-spin),
        rgba(220, 38, 38, 0.85) 0deg,
        rgba(153, 0, 0, 0.65) 90deg,
        rgba(60, 0, 0, 0.45) 180deg,
        rgba(178, 34, 52, 0.75) 270deg,
        rgba(220, 38, 38, 0.85) 360deg
    );
    filter: drop-shadow(0 0 6px rgba(178, 34, 52, 0.35));
    animation: xxImmortalAura 7s linear infinite, xxSoulMistPulse 3.4s ease-in-out infinite;
}

html.theme-dark .card.xx-immortal-card,
html.theme-dark .xx-immortal-card {
    border-color: rgba(178, 34, 52, 0.45);
    box-shadow:
        0 18px 44px -18px rgba(153, 0, 0, 0.55),
        0 8px 20px -10px rgba(178, 34, 52, 0.32),
        inset 0 0 0 1px rgba(178, 34, 52, 0.18);
}

html.theme-dark .card.xx-immortal-card::after,
html.theme-dark .xx-immortal-card::after {
    background: radial-gradient(ellipse at 30% 20%,
        rgba(178, 34, 52, 0.18),
        rgba(60, 0, 0, 0.05) 50%,
        transparent 70%);
}

@keyframes xxSoulMistPulse {
    0%, 100% { opacity: 0.75; filter: drop-shadow(0 0 4px rgba(178, 34, 52, 0.30)); }
    50%      { opacity: 1.00; filter: drop-shadow(0 0 12px rgba(220, 38, 38, 0.55)); }
}

/* Heavenly Realm: golden "Halo" — soft pulsing pure-gold ring. */
html.theme-light .card.xx-immortal-card::before,
html.theme-light .xx-immortal-card::before,
body.light-mode .card.xx-immortal-card::before,
body.light-mode .xx-immortal-card::before {
    background: conic-gradient(
        from var(--xx-aura-spin),
        rgba(255, 215, 0, 0.85) 0deg,
        rgba(255, 244, 196, 0.65) 90deg,
        rgba(255, 250, 205, 0.85) 180deg,
        rgba(255, 215, 0, 0.75) 270deg,
        rgba(255, 215, 0, 0.85) 360deg
    );
    filter: drop-shadow(0 0 6px rgba(255, 215, 0, 0.45));
    /* Re-pin the rotation animation because xianxia-theme-light.css
     * already injects `xxVipAuraPulseLight` on this same ::before
     * pseudo-element — without the explicit `animation:` shorthand,
     * the cascade strips xxImmortalAura back to the opacity pulse. */
    animation: xxImmortalAura 7s linear infinite, xxHaloPulse 3.4s ease-in-out infinite;
}

body.light-mode .card.xx-immortal-card,
body.light-mode .xx-immortal-card {
    border-color: rgba(255, 215, 0, 0.55);
    box-shadow:
        0 16px 38px -18px rgba(192, 139, 0, 0.40),
        0 8px 18px -10px rgba(192, 139, 0, 0.25),
        inset 0 0 0 1px rgba(255, 215, 0, 0.25);
}

@keyframes xxHaloPulse {
    0%, 100% { opacity: 0.70; filter: drop-shadow(0 0 4px rgba(255, 215, 0, 0.40)); }
    50%      { opacity: 1.00; filter: drop-shadow(0 0 14px rgba(255, 215, 0, 0.70)); }
}

/* Smooth realm-shift between Halo gold and Soul Mist crimson: animate
 * the static colours (border, shadow) so they crossfade rather than
 * snap. The conic gradient itself swaps instantly (browsers can't
 * interpolate gradients) but the surrounding cues sell the morph. */
.card.xx-immortal-card,
.xx-immortal-card,
.card.xx-immortal-card::before,
.xx-immortal-card::before,
.card.xx-immortal-card::after,
.xx-immortal-card::after {
    transition:
        border-color 700ms cubic-bezier(0.22, 1, 0.36, 1),
        box-shadow   700ms cubic-bezier(0.22, 1, 0.36, 1),
        background   700ms cubic-bezier(0.22, 1, 0.36, 1),
        filter       700ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* ════════════════════════════════════════════════════════════════
 * 12. Mortal Card — Parchment Border refinement
 *     Light Mode: thin ivory / aged-parchment edge (existing).
 *     Dark Mode: thin charcoal edge with hairline crimson glow.
 *     Adds a smooth crossfade for the realm-shift.
 * ════════════════════════════════════════════════════════════════ */
.xx-mortal-card,
.xx-mortal-card::before,
.xx-mortal-card::after {
    transition:
        border-color 700ms cubic-bezier(0.22, 1, 0.36, 1),
        box-shadow   700ms cubic-bezier(0.22, 1, 0.36, 1),
        background   700ms cubic-bezier(0.22, 1, 0.36, 1);
}

html.theme-dark .xx-mortal-card {
    border-color: rgba(178, 34, 52, 0.22);
    box-shadow:
        0 6px 20px -10px rgba(0, 0, 0, 0.65),
        0 2px 6px -3px rgba(60, 0, 0, 0.35),
        inset 0 0 0 1px rgba(178, 34, 52, 0.06);
}

html.theme-dark .xx-mortal-card::before,
html.theme-dark .xx-mortal-card::after {
    background: linear-gradient(90deg,
        transparent,
        rgba(178, 34, 52, 0.28) 20%,
        rgba(220, 38, 38, 0.42) 50%,
        rgba(178, 34, 52, 0.28) 80%,
        transparent);
}

/* ════════════════════════════════════════════════════════════════
 * 13. Heavenly Court ambient body tint — push contrast to 11
 *     The Light Mode body gradient was sliding to a muted slate
 *     #f1f5f9 at the foot of the viewport, which paired with the
 *     legacy fixed dark layers to read as a grey wash. Replace with
 *     pure ivory → celestial yellow.
 * ════════════════════════════════════════════════════════════════ */
html.theme-light,
html.theme-light body,
body.light-mode {
    background: linear-gradient(180deg,
        var(--hc-pure-white) 0%,
        var(--hc-ivory-white) 50%,
        var(--hc-celestial-yellow) 100%) !important;
    background-attachment: fixed !important;
}

/* Soft gold/jade Auspicious-Cloud halo behind the content layer. */
html.theme-light body::before,
body.light-mode::before {
    background:
        radial-gradient(ellipse 380px 160px at 12% 12%, rgba(255, 215, 0, 0.10), transparent 70%),
        radial-gradient(ellipse 320px 140px at 84% 28%, rgba(0, 168, 107, 0.06), transparent 70%),
        radial-gradient(ellipse 260px 110px at 50% 78%, rgba(255, 250, 205, 0.18), transparent 70%) !important;
}

/* ════════════════════════════════════════════════════════════════
 * 14. Blood Mist Underworld ambient body tint
 *     Push the Dark Mode body to the deepest obsidian and seed the
 *     viewport corners with crimson glow. Keeps the existing
 *     starfield/fog layers intact — this only adjusts the base.
 * ════════════════════════════════════════════════════════════════ */
html.theme-dark .xx-stars {
    background:
        radial-gradient(1400px 900px at 50% 25%, rgba(220, 38, 38, 0.10), transparent 65%),
        radial-gradient(1100px 800px at 88% 92%, rgba(153, 0, 0, 0.10), transparent 65%),
        radial-gradient(900px  700px at 8% 78%,  rgba(60, 0, 0, 0.10),  transparent 65%),
        radial-gradient(600px  500px at 60% 55%, rgba(178, 34, 52, 0.06), transparent 65%),
        var(--bm-deepest-black);
}

/* ════════════════════════════════════════════════════════════════
 * 15. World Shift — full-viewport ink-wash transition fired on
 *     every theme toggle. The overlay element (#xx-mist-transition)
 *     already exists in base.html; we add a `.xx-world-shifting`
 *     hook on <html> that pulses it for ~900ms. Backed by JS in
 *     main.js#toggleSiteTheme.
 * ════════════════════════════════════════════════════════════════ */
#xx-mist-transition {
    transition: opacity 220ms ease-out;
}

html.xx-world-shifting #xx-mist-transition {
    animation: xxWorldShift 900ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes xxWorldShift {
    0%   { opacity: 0; }
    20%  { opacity: 0.85; }
    60%  { opacity: 0.55; }
    100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    html.xx-world-shifting #xx-mist-transition {
        animation: none;
        opacity: 0;
    }
}

/* ════════════════════════════════════════════════════════════════
 * 16. Dark-mode text safety net — supplement the section-2 rules
 *     for elements that style.css hard-coded against a near-black
 *     `--dark-color`. Without these, anchors/tag labels can render
 *     as black-on-charcoal in the Blood Mist Underworld.
 * ════════════════════════════════════════════════════════════════ */
html.theme-dark a:not(.btn):not(.premium-badge):not(.pin-badge):not(.filter-tag.active) {
    color: var(--bm-pale-gold);
}

html.theme-dark .filter-tag,
html.theme-dark .category-tag,
html.theme-dark .card-meta,
html.theme-dark .card-meta * {
    color: var(--bm-silver) !important;
}

html.theme-dark .filter-tag.active {
    /* active filter chip already paints its own foreground in the
     * theme — keep that. */
    color: inherit !important;
}

/* ════════════════════════════════════════════════════════════════
 * 17. Magic Circle (Trận Pháp) button ripple — keeps the existing
 *     xx-bagua-ripple but re-tints it per realm so the click feedback
 *     stays consistent with the active palette.
 * ════════════════════════════════════════════════════════════════ */
html.theme-light .xx-bagua-ripple,
body.light-mode .xx-bagua-ripple {
    background: radial-gradient(circle,
        rgba(255, 215, 0, 0.35) 0%,
        rgba(255, 250, 205, 0.25) 35%,
        rgba(0, 168, 107, 0.10)  55%,
        transparent 70%);
}

html.theme-light .xx-bagua-ripple::after,
body.light-mode .xx-bagua-ripple::after {
    color: rgba(192, 139, 0, 0.85);
    text-shadow: 0 0 8px rgba(255, 215, 0, 0.55);
}

html.theme-dark .xx-bagua-ripple {
    background: radial-gradient(circle,
        rgba(220, 38, 38, 0.30) 0%,
        rgba(153, 0, 0, 0.20)   35%,
        rgba(60, 0, 0, 0.10)    55%,
        transparent 70%);
}

html.theme-dark .xx-bagua-ripple::after {
    color: rgba(220, 38, 38, 0.80);
    text-shadow: 0 0 8px rgba(178, 34, 52, 0.45);
}

/* ════════════════════════════════════════════════════════════════
 * 18. Performance — off-screen paint skip + reduced-motion guards
 *     The blog grid can hold dozens of `.card`s, each with a conic
 *     gradient + drop-shadow filter on `::before`. Repainting them
 *     all every frame is the main cause of perceived lag on mid-tier
 *     hardware. Three mitigations:
 *
 *       a) `content-visibility: auto` on `.card` so the browser skips
 *          layout + paint for cards outside the viewport entirely.
 *          A `contain-intrinsic-size` placeholder keeps the scroll
 *          position stable as cards scroll in/out.
 *       b) `prefers-reduced-motion` short-circuits every aura, pulse,
 *          and floating-cloud animation. The static colours still
 *          carry the realm identity; the spin is just decoration.
 *       c) `.xx-floating-cloud`s collapse to `display: none` on
 *          narrow viewports where they cost the most and the user
 *          is most likely to be on a battery-powered device.
 * ════════════════════════════════════════════════════════════════ */
.card,
.post-card,
.product-card {
    content-visibility: auto;
    contain-intrinsic-size: 480px 360px;
}

@media (prefers-reduced-motion: reduce) {
    .card.xx-immortal-card::before,
    .xx-immortal-card::before,
    html.theme-dark .card.xx-immortal-card::before,
    html.theme-dark .xx-immortal-card::before,
    html.theme-light .card.xx-immortal-card::before,
    html.theme-light .xx-immortal-card::before,
    body.light-mode .card.xx-immortal-card::before,
    body.light-mode .xx-immortal-card::before,
    .card.xx-immortal-card:hover::before,
    .xx-immortal-card:hover::before,
    body.light-mode .card.xx-immortal-card:hover::before,
    body.light-mode .xx-immortal-card:hover::before,
    .xx-immortal-card .premium-badge::after,
    .xx-floating-cloud {
        animation: none !important;
    }
}

@media (max-width: 640px) {
    .xx-floating-cloud,
    #xxFloatingLayer .xx-floating-cloud {
        display: none !important;
    }
}

/* Pause the aura animations while the card is scrolled out of view.
 * `IntersectionObserver` in main.js toggles `.xx-aura-paused` on the
 * card.
 *
 * Specificity note: the realm-scoped rules above
 * (`html.theme-dark .card.xx-immortal-card::before` and
 * `body.light-mode .card.xx-immortal-card::before`) compute to (0,3,2)
 * and re-set the full `animation:` shorthand — which silently resets
 * `animation-play-state` back to `running`. So the pause rule MUST
 * match or beat the realm rules on specificity AND mention the realm
 * prefix to win the cascade. We list all three variants explicitly. */
.card.xx-immortal-card.xx-aura-paused::before,
.xx-immortal-card.xx-aura-paused::before,
html.theme-dark .card.xx-immortal-card.xx-aura-paused::before,
html.theme-dark .xx-immortal-card.xx-aura-paused::before,
html.theme-light .card.xx-immortal-card.xx-aura-paused::before,
html.theme-light .xx-immortal-card.xx-aura-paused::before,
body.light-mode .card.xx-immortal-card.xx-aura-paused::before,
body.light-mode .xx-immortal-card.xx-aura-paused::before {
    animation-play-state: paused;
}
