﻿/* ============================================================
   Qimen AI — Shared Stylesheet
   Single source of truth for design tokens, components,
   and page-specific layouts.
   ============================================================ */

/* ---------- Design Tokens ---------- */
:root {
    /* Surfaces — rice paper light theme */
    --bg-base: #F9F9F6;          /* warm off-white app background */
    --bg-elevated: #FFFFFF;       /* pure white cards */
    --bg-deep: #FFFFFF;           /* iframe wrap / code blocks */
    --bg-glass: rgba(255, 255, 255, 0.85);        /* translucent white for backdrop-blur panels */
    --bg-glass-strong: rgba(255, 255, 255, 0.95);

    /* Borders — barely-there dark hairlines */
    --border-subtle: rgba(0, 0, 0, 0.06);
    --border-strong: rgba(0, 0, 0, 0.10);

    /* Text — deep ink */
    --text-primary: #1A1B20;
    --text-secondary: #4A4D57;
    --text-muted: #8A8D97;

    /* ---- Brand accent — teal green (was gold #C5A880) ----
       Single value for both themes, by choice. Measured against the two page
       grounds: 4.20 contrast on the cream light background and 4.27 on the dark
       indigo. That light-mode figure is nearly double the old gold's 2.14, which
       had been failing AA outright.

       ⚠️ --wx-metal is a SEPARATE token and is still genuinely gold (#C9A100 /
       #ffd700) — it colours Wu Xing Metal terms in the Paipan. Never fold it
       into the accent.

       Prefer --accent-* in new code; the --gold-* names below are back-compat
       aliases so the ~162 existing consumers keep working untouched. */
    --accent: #2F8577;
    --accent-bright: #3FA492;
    --accent-glow: rgba(47, 133, 119, 0.30);
    --accent-soft: rgba(47, 133, 119, 0.14);

    /* Deliberately NOT the brand accent. The Paipan's palace-highlight aura is
       two-tone — a cyan --ring-hue core with a warm rim — so the palace the
       Oracle names stands out from the cyan rings around it. A teal rim on cyan
       rings would blur that signal away, so this keeps the original gold. */
    --aura-warm: #C5A880;

    --gold: var(--accent);
    --gold-bright: var(--accent-bright);
    --gold-glow: var(--accent-glow);
    --gold-soft: var(--accent-soft);
    --blue: #3B82C4;
    --blue-bright: #5BA0DD;
    --blue-glow: rgba(59, 130, 196, 0.25);
    --blue-soft: rgba(59, 130, 196, 0.10);

    /* Status */
    --success: #2E9E5B;
    --danger: #D6453E;
    --warning: #C98A1E;

    /* Motion */
    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --fast: 150ms;
    --med: 250ms;
    --slow: 450ms;

    /* Radii */
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 16px;
    --r-xl: 24px;
    --r-pill: 999px;

    /* Layout */
    --nav-h: 72px;
    --container: 1280px;
    --container-narrow: 1080px;

    /* ---- Wu Xing element inks (SINGLE SOURCE OF TRUTH) ----
       Used by the Paipan chart, the phone palace sheet, and the colour legend
       in the Dashboard FAQ. These were previously duplicated across four
       scoped blocks (.paipan-terminal / .palace-sheet, light + dark), which
       guaranteed drift the moment a hue was retuned — and they get retuned
       often. Declared here (day) and in body.dark-theme (neon) instead, so
       every consumer inherits the same value and the legend can never
       disagree with the chart.
       Day versions are the neon hues darkened to read on white. Metal stays
       gold, never orange. */
    --wx-wood:  #00A838;   /* day green     */
    --wx-fire:  #E4004B;   /* day red-pink  */
    --wx-earth: #D97A00;   /* day orange    */
    --wx-metal: #C9A100;   /* day gold      */
    --wx-water: #0090B8;   /* day cyan-blue */
}

/* ---------- Dark Theme: "Ink Wash Blue" override ----------
   Re-declares the surface/text/border tokens; gold + blue accents
   stay identical (gold reads beautifully on both themes). Cascades
   to every component on all 4 pages via the custom properties.
   ----------------------------------------------------------------- */
body.dark-theme {
    --bg-base: #0B111A;          /* deep ink-wash blue */
    --bg-elevated: #151E2D;       /* slightly lighter indigo panels */
    --bg-deep: #0E1622;           /* iframe wrap / code blocks */
    --bg-glass: rgba(21, 30, 45, 0.72);          /* translucent indigo for blur panels */
    --bg-glass-strong: rgba(21, 30, 45, 0.88);

    --border-subtle: rgba(234, 236, 239, 0.10);
    --border-strong: rgba(234, 236, 239, 0.18);

    --text-primary: #EAECEF;      /* soft silver-white */
    --text-secondary: rgba(234, 236, 239, 0.62);
    --text-muted: rgba(234, 236, 239, 0.40);

    /* Wu Xing inks — full "Neon Circuit" set. The dark page and the dark
       Paipan panel share a background family, so one set serves both the
       chart and the FAQ legend. See the :root block for why these live here
       rather than scoped to the panel. */
    --wx-wood:  #00ff00;
    --wx-fire:  #ff0055;
    --wx-earth: #ffaa00;
    --wx-metal: #ffd700;
    --wx-water: #00ffff;
}

/* ---------- Reset & Base ---------- */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

body {
    margin: 0;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-primary);
    background: var(--bg-base);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
    overflow-x: hidden;
    transition: background-color 0.4s ease, color 0.4s ease, border-color 0.4s ease;
}

/* Ambient backdrop — barely-there warm tint for rice-paper depth */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(800px 600px at 12% 10%, rgba(47, 133, 119, 0.06), transparent 60%),
        radial-gradient(900px 700px at 90% 90%, rgba(59, 130, 196, 0.04), transparent 60%),
        var(--bg-base);
    pointer-events: none;
}

h1, h2, h3, h4, h5 {
    font-family: 'Noto Serif SC', 'Songti SC', 'Inter', serif;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    margin: 0 0 0.5em;
    color: var(--text-primary);
}

h1 { font-size: clamp(2.25rem, 4.5vw, 3.75rem); font-weight: 700; }
h2 { font-size: clamp(1.75rem, 3vw, 2.5rem); }
h3 { font-size: 1.375rem; }
h4 { font-size: 1.125rem; }

p {
    margin: 0 0 1em;
    color: var(--text-secondary);
}

a {
    color: var(--blue);
    text-decoration: none;
    transition: color var(--fast) var(--ease);
}

a:hover {
    color: var(--blue-bright);
}

code,
.mono {
    font-family: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace;
    font-size: 0.92em;
}

/* ---------- Layout Primitives ---------- */
.container {
    width: 100%;
    max-width: var(--container);
    margin: 0 auto;
    padding: 0 24px;
}

.container--narrow {
    max-width: var(--container-narrow);
}

.section {
    padding: 80px 0;
}

.section--tight {
    padding: 48px 0;
}

.eyebrow {
    display: inline-block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gold);
    padding: 6px 12px;
    border: 1px solid var(--gold-soft);
    border-radius: var(--r-pill);
    background: var(--gold-soft);
    margin-bottom: 18px;
}

.text-gold { color: var(--gold); }
.text-blue { color: var(--blue); }
.text-muted { color: var(--text-muted); }
.text-center { text-align: center; }

/* ---------- Glass Panel Component ---------- */
.glass-panel {
    background: var(--bg-glass);
    backdrop-filter: blur(20px) saturate(120%);
    -webkit-backdrop-filter: blur(20px) saturate(120%);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.06);
    transition: background-color 0.4s ease, color 0.4s ease, border-color 0.4s ease;
}

/* Deepen card shadows on the dark theme so panels still read as elevated */
body.dark-theme .glass-panel {
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
}

.glass-panel--strong {
    background: var(--bg-glass-strong);
    border-color: var(--border-strong);
}

.glow-gold {
    box-shadow: 0 6px 22px var(--gold-glow), 0 8px 30px rgba(0, 0, 0, 0.06);
}

.glow-blue {
    box-shadow: 0 6px 22px var(--blue-glow), 0 8px 30px rgba(0, 0, 0, 0.06);
}

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 500;
    line-height: 1;
    padding: 12px 22px;
    border-radius: var(--r-pill);
    border: 1px solid transparent;
    cursor: pointer;
    transition: all var(--fast) var(--ease);
    text-decoration: none;
    white-space: nowrap;
}

.btn:hover {
    transform: translateY(-1px);
}

.btn:active {
    transform: translateY(0);
}

.btn--primary {
    /* Runs from --accent-bright UPWARD, not from --accent. Teal at the accent's
       own lightness puts the dark label at 4.13 contrast — under the 4.5 floor —
       and a gradient's darkest end sets the worst case. Starting one step
       lighter lifts the worst point to 6.04. (White text is not the answer: it
       measures worse at every stop, 4.43 → 2.53.) */
    background: linear-gradient(135deg,
        var(--accent-bright),
        color-mix(in srgb, var(--accent-bright) 82%, white));
    color: #1A140A;
    font-weight: 600;
    box-shadow: 0 4px 20px var(--gold-glow);
}

.btn--primary:hover {
    box-shadow: 0 6px 28px var(--gold-glow), 0 0 0 1px var(--gold);
    color: #1A140A;
}

.btn--blue {
    background: linear-gradient(135deg, var(--blue), var(--blue-bright));
    color: #07111E;
    font-weight: 600;
    box-shadow: 0 4px 20px var(--blue-glow);
}

.btn--blue:hover {
    box-shadow: 0 6px 28px var(--blue-glow), 0 0 0 1px var(--blue);
    color: #07111E;
}

.btn--ghost {
    background: var(--bg-glass);
    color: var(--text-primary);
    border-color: var(--border-strong);
    backdrop-filter: blur(10px);
}

.btn--ghost:hover {
    background: var(--bg-glass-strong);
    border-color: var(--gold);
    color: var(--gold);
}

.btn--lg {
    padding: 16px 32px;
    font-size: 1rem;
}

.btn--block {
    width: 100%;
}

/* ---------- Top Navigation ---------- */
.site-nav {
    position: sticky;
    top: 12px;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 28px;
    padding: 12px 20px;
    margin: 12px auto 0;
    max-width: calc(var(--container) - 24px);
    border-radius: var(--r-pill);
    /* 80% transparent — the hero painting shows clearly through; the blur
       keeps the text legible. (Scoped to the nav; the global --bg-glass
       stays opaque for panels on solid backgrounds.) */
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(24px) saturate(130%);
    -webkit-backdrop-filter: blur(24px) saturate(130%);
    /* slide for the auto-hide behaviour, kept alongside the theme transition */
    transition: transform 0.4s var(--ease), opacity 0.4s var(--ease),
        background-color 0.4s ease, border-color 0.4s ease;
}

/* Auto-hide: scrolled-down state slides the bar fully above the viewport */
.site-nav.nav-hidden {
    transform: translateY(-150%);
    opacity: 0;
    pointer-events: none;
}

/* Transparent top-edge hover zone (desktop reveal trigger), under the nav */
.nav-peek-zone {
    position: fixed;
    inset: 0 0 auto 0;
    height: 14px;
    z-index: 49;
}

/* Glass "handle" — visible only while the nav is hidden; the explicit
   click/tap trigger and a drawer-style pull-down affordance.
   RIGHT-aligned, not centred: floating fixed over the page, a centred pill
   lands squarely on the text column and covers the words you're reading.
   (It was originally centred to dodge the shop's cart FAB — that cart was
   removed in the e-book rewrite, so the constraint is gone.)
   ⚠️ The offset is set by `right` alone, with NO horizontal translate, so the
   .is-visible rule below must not reintroduce one or the pill jumps sideways
   as it fades in. */
.nav-reveal-fab {
    position: fixed;
    top: 8px;
    right: 16px;
    left: auto;
    transform: translateY(-6px);
    z-index: 48;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 26px;
    padding: 0;
    border-radius: var(--r-pill);
    background: var(--bg-glass);
    backdrop-filter: blur(20px) saturate(130%);
    -webkit-backdrop-filter: blur(20px) saturate(130%);
    border: 1px solid var(--border-subtle);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
    color: var(--gold);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}

.nav-reveal-fab.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

/* Back-to-top — injected on every page by wireBackToTop() in main.js.
   Same glass language as the nav handle above, parked bottom-right.
   z-index 45 is deliberate: it must sit BELOW the chat backdrop (60) and the
   expanded chat panel (70) so a fullscreen Oracle on ask.html covers it rather
   than the button floating over the conversation. Bottom-right is otherwise
   free — .cart-fab was top-right and its markup is long gone. */
.back-to-top {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 45;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    padding: 0;
    border-radius: 50%;
    background: var(--bg-glass);
    backdrop-filter: blur(20px) saturate(130%);
    -webkit-backdrop-filter: blur(20px) saturate(130%);
    border: 1px solid var(--border-subtle);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
    color: var(--gold);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transform: translateY(8px);
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease),
                border-color var(--fast) var(--ease);
}

.back-to-top.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.back-to-top:hover {
    border-color: var(--gold-soft);
}

@media (max-width: 560px) {
    .back-to-top { right: 16px; bottom: 16px; }
}

.nav-reveal-fab:hover {
    border-color: var(--gold);
}

@media (prefers-reduced-motion: reduce) {
    .site-nav,
    .nav-reveal-fab,
    .back-to-top { transition: none; }

    /* html{scroll-behavior:smooth} is global, and was never switched off for
       reduced motion. The back-to-top button makes that impossible to ignore —
       one click animates the whole document. Turn it off here so the jump is
       instant for anyone who asked for less motion. */
    html { scroll-behavior: auto; }
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text-primary);
    font-weight: 600;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
}

.brand-mark {
    display: inline-flex;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    /* FeiQingYi profile photo — light theme (white-background version). Dark theme swaps below. */
    background: url('../FeiQingYi Profile Image (White Background).png') center / cover no-repeat;
    border: 1px solid var(--gold-soft);
}

.brand-text {
    font-weight: 600;
}

.brand-accent {
    background: linear-gradient(135deg, var(--gold), var(--gold-bright));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    font-weight: 700;
}

.nav-links {
    display: flex;
    gap: 6px;
    list-style: none;
    padding: 0;
    margin: 0 auto;
}

.nav-links a {
    display: inline-block;
    padding: 8px 16px;
    border-radius: var(--r-pill);
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 500;
    /* Two-word labels ("Ask Fei QingYi", "About Qimen") wrapped mid-label once
       the nav grew to six items, doubling each item's height and pushing the
       bar from 72px to 88px. They fit on one line — they just need permission
       to stay there. */
    white-space: nowrap;
    transition: all var(--fast) var(--ease);
}

.nav-links a:hover {
    color: var(--text-primary);
    background: var(--bg-glass-strong);
}

.nav-links a.is-active {
    color: var(--gold);
    background: var(--gold-soft);
}

.nav-cta {
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    padding: 9px 18px;
    border-radius: var(--r-pill);
    border: 1px solid var(--gold);
    background: transparent;
    color: var(--gold);
    cursor: pointer;
    transition: all var(--fast) var(--ease);
}

.nav-cta:hover {
    background: var(--gold);
    color: #2A2207;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

/* ---------- Global sign-in / account control (nav) ---------- */
.nav-account-wrap {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
}
.nav-signin {
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    padding: 8px 16px;
    border-radius: var(--r-pill);
    border: 1px solid var(--border-strong);
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
    white-space: nowrap;
    transition: all var(--fast) var(--ease);
}
.nav-signin:hover {
    border-color: var(--gold);
    color: var(--gold);
    background: var(--gold-soft);
}
.nav-account {
    position: relative;
    display: inline-flex;
}
.nav-account-chip {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 1px solid var(--gold);
    background: var(--gold-soft);
    color: var(--gold);
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 700;
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all var(--fast) var(--ease);
}
.nav-account-chip:hover {
    background: var(--gold);
    color: #2A2207;
}
.nav-account-menu {
    position: absolute;
    top: calc(100% + 12px);
    right: 0;
    min-width: 210px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: 12px;
    box-shadow: 0 16px 44px rgba(0, 0, 0, 0.18);
    z-index: 60;
}
.nav-account-menu[hidden] { display: none; }
.nav-account-email {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-primary);
    word-break: break-all;
}
.nav-account-credits {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--gold);
}
.nav-account-menu .account-link { align-self: flex-start; }

.nav-mobile-toggle {
    display: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    font-size: 1.4rem;
    cursor: pointer;
    padding: 4px 8px;
}

/* Mobile nav.
   Breakpoint raised 880 → 1040 when the nav went from four items to six:
   "Home · Ask Fei QingYi · About Qimen · Subscription · Shop · FAQs" no longer
   fits beside the brand, the Sign-in control and the theme toggle below ~1040px
   — at 900px the toggle was pushed clean off the right edge and the page
   scrolled sideways. Collapsing to the hamburger sooner is the fix; squeezing
   the labels only produced a cramped, wrapping bar. */
@media (max-width: 1040px) {
    .nav-links {
        display: none;
        position: absolute;
        top: calc(100% + 8px);
        left: 0;
        right: 0;
        flex-direction: column;
        background: var(--bg-elevated);
        border: 1px solid var(--border-subtle);
        border-radius: var(--r-lg);
        padding: 12px;
        gap: 2px;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
    }

    .nav-links.is-open {
        display: flex;
    }

    .nav-links a {
        text-align: center;
    }

    .nav-cta {
        display: none;
    }

    .nav-mobile-toggle {
        display: inline-flex;
        margin-left: auto;
    }

    .site-nav {
        position: sticky;
        top: 8px;
        gap: 16px;
    }

    /* The account chip sits on the left half on mobile, so open its menu
       rightward to avoid spilling off the left edge of the screen. */
    .nav-account-menu {
        left: 0;
        right: auto;
    }
}

/* ---------- Footer ---------- */
.site-footer {
    margin-top: 96px;
    padding: 56px 24px 28px;
    border-top: 1px solid var(--border-subtle);
    background:
        linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.015)),
        #FFFFFF;
}

.footer-grid {
    max-width: var(--container);
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1.5fr 1fr 1fr 1fr;
    gap: 40px;
    margin-bottom: 36px;
}

.footer-brand p {
    margin-top: 14px;
    color: var(--text-muted);
    font-size: 0.92rem;
    max-width: 320px;
}

.footer-col h5 {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-muted);
    margin-bottom: 16px;
}

.footer-col ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

.footer-col li {
    margin-bottom: 10px;
}

.footer-col a {
    color: var(--text-secondary);
    font-size: 0.92rem;
}

.footer-col a:hover {
    color: var(--gold);
}

.footer-base {
    max-width: var(--container);
    margin: 0 auto;
    padding-top: 24px;
    border-top: 1px solid var(--border-subtle);
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    color: var(--text-muted);
    font-size: 0.82rem;
}

.dev-toggle {
    background: transparent;
    border: 1px dashed var(--border-strong);
    color: var(--text-muted);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    padding: 6px 12px;
    border-radius: var(--r-pill);
    cursor: pointer;
    transition: all var(--fast) var(--ease);
}

.dev-toggle:hover {
    color: var(--gold);
    border-color: var(--gold);
}

@media (max-width: 720px) {
    .footer-grid {
        grid-template-columns: 1fr 1fr;
    }

    .footer-brand {
        grid-column: 1 / -1;
    }
}

/* ============================================================
   Page: Dashboard (index.html)
   ============================================================ */

/* --- Hero region: ink-wash painting fading into the solid theme --- */
.hero-ink-wrapper {
    position: relative;
    /* Painting starts BELOW the nav — full artwork visible, nothing veiled
       by the glass bar. (The old negative margin that slid the hero up
       behind the sticky nav was removed at the user's request.) */
    padding-top: 48px;   /* breathing room between painting edge and hero text */
    padding-bottom: 96px;                       /* room for the fade to complete */
    /* Layer 1: LIGHT fade — keeps the painting bright at top, dissolving its
       bottom edge into the rice-paper background (no harsh line).
       Layer 2: the ink-wash landscape painting. */
    background-image:
        linear-gradient(to bottom,
            rgba(249, 249, 246, 0) 0%,
            rgba(249, 249, 246, 0) 55%,
            rgba(249, 249, 246, 0.85) 90%,
            var(--bg-base) 100%),
        url('../Ink Splash sansui.png');
    /* Gradient fills the wrapper; the painting COVERS it — proportions kept,
       CROPPED rather than stretched. (It used to be `100% 100%`, which scales
       width and height independently: at 1280 that stretched the 16:9 art wide
       by 1.73×, and on a portrait phone box squashed it by 2.44×.)
       Anchored TOP because of how both paintings are composed — the red sun,
       the birds and the faint city skyline sit top-right, so the crop must eat
       the foreground pines, not the sky. The fade below then dissolves the
       crop seam, so the bottom edge never reads as a hard cut. */
    background-size: 100% 100%, cover;
    background-position: center top;
    background-repeat: no-repeat;
}

.hero-content {
    position: relative;
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
    align-items: center;
}

/* Subtle light halo keeps charcoal hero text legible over the busy painting */
.hero-content .hero-band-text h1,
.hero-content .hero-band-text p {
    text-shadow: 0 1px 3px rgba(255, 255, 255, 0.7);
}

/* --- App dashboard: solid theme, seamless continuation of the fade --- */
.app-container {
    position: relative;
    background: var(--bg-base);
    padding: 8px 0 64px;   /* gradient already resolved to --bg-base at hero bottom */
}

/* ask.html has no ink-wash hero (that stays on Home), so this compact block
   carries the page's <h1>. Deliberately sized down from the base h1
   clamp(2.25rem, 4.5vw, 3.75rem) — a hero-scale title would dwarf the chart
   and chat it introduces. */
.ask-page-head {
    padding: 28px 0 4px;
    max-width: 720px;
}

.ask-page-head h1 {
    font-size: clamp(1.6rem, 2.6vw, 2.1rem);
    margin-bottom: 8px;
}

@media (max-width: 720px) {
    .ask-page-head { padding-top: 20px; }
}

.hero-band-text h1 {
    margin-bottom: 14px;
    color: var(--text-primary);   /* solid deep ink — crisp on rice paper */
}

.hero-band-text p {
    font-size: 1.05rem;
    max-width: 560px;
    margin-bottom: 24px;
}

.hero-band-ctas {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

@media (max-width: 880px) {
    .hero-ink-wrapper {
        padding-bottom: 64px;
    }
}

@media (max-width: 560px) {
    .hero-ink-wrapper {
        /* Phones give the hero a PORTRAIT box, so `cover` scales by HEIGHT —
           the painting's full height shows and only the WIDTH is cropped
           (~42% of it at 375px). The window must sit toward the right to keep
           the sun, the birds and the city skyline; a centre anchor shows
           source x 29–71% and loses all three.

           Why 79% and not `right`: at a full right anchor the sun lands at
           screen x 188–241, straight behind the h1's first line (which ends at
           x 294) — it read as a smudge behind the words. LOWERING the
           percentage slides the painting RIGHTward inside the window (the
           value aligns that point of the image with that point of the box), so
           79% carries the sun out to x 303–356, clear of the text and still
           fully on screen. Cost: the far-right cliff and the outer ~8% of the
           skyline move off-screen (visible source is now x 46–87%).
           Two positions because the layers differ — the gradient fills the
           wrapper, only the painting is offset. */
        background-position: center top, 79% top;
    }

    /* The dark painting is a DIFFERENT image with the moon ~5.5% further right
       in its own frame (x 85.0–89.6% vs the light sun's 79.5–85.3%), so the
       same offset would push it off the right edge. 88% lands it at x 303–345,
       matching the light version's clearance. */
    body.dark-theme .hero-ink-wrapper {
        background-position: center top, 88% top;
    }

    /* The right crop puts the hero paragraph over mountains rather than the
       pale mist it used to sit on, and --text-secondary is too muted to
       survive that: measured 2.67 light / 3.26 dark, both under the 4.5 AA
       floor for 16.8px body text. Promote it to --text-primary → 5.44 / 5.66.
       Deliberately NOT solved by strengthening the veil: the gradient alphas
       needed to rescue the muted colour (~0.52) cut the painting's presence
       roughly in half, while this leaves the artwork untouched. */
    .hero-content .hero-band-text p {
        color: var(--text-primary);
    }
}

/* --- Dashboard Grid --- */
.dashboard-grid {
    display: grid;
    grid-template-columns: 1fr 380px;
    gap: 24px;
    align-items: start;
}

@media (max-width: 1080px) {
    .dashboard-grid {
        grid-template-columns: 1fr;
    }
}

/* --- Paipan Terminal --- */
.paipan-terminal {
    position: relative;
    overflow: visible;
    min-width: 0;   /* grid item: don't let the pond's min-width widen the page */
    /* "Day Circuit" (light theme base) — the panel wears the SAME warm
       rice-paper colour as the page itself (var(--bg-base), #F9F9F6 in
       light); the header is transparent in light mode so header and chart
       body are literally the same colour. body.dark-theme overrides below
       switch the whole panel to the full "Neon Circuit". */
    background: var(--bg-base);
    /* Scoped panel tokens (light values; the dark block redefines them). */
    --text-primary: #1A1B20;
    --text-secondary: rgba(26, 27, 32, 0.62);
    --text-muted: rgba(26, 27, 32, 0.45);
    --border-subtle: rgba(26, 27, 32, 0.08);
    /* Art + Data inks (zh strong / py soft) */
    --ink-strong: #1A1B20;
    --ink-soft: rgba(0, 0, 0, 0.5);    /* secondary Pinyin */
    /* Wu Xing element inks (--wx-*) are inherited from :root — see the note
       there. Do NOT re-declare them here; the legend in the Dashboard FAQ
       reads the same tokens and must not be able to drift from the chart. */
    /* Circuit chrome: the ring tint + the plain-ink halos. Light = pale
       cyan ring, no silver halos. (The per-element wx glow strengths
       live as explicit rules below — they reference the per-element
       --wx, which a panel-level custom property cannot carry.) */
    --ring-hue: #00A8C8;
    --ink-glow: none;
    --ink-glow-soft: none;
    --tag-bg: rgba(255, 255, 255, 0.9);
    /* Bagua trigram watermark ink — soft charcoal on the light panel */
    --trigram-ink: rgba(0, 0, 0, 0.15);
}

.terminal-header {
    display: flex;
    flex-wrap: wrap;        /* lets the time control drop to its own row on narrow screens */
    align-items: center;
    gap: 16px;
    row-gap: 8px;
    padding: 16px 22px;
    border-bottom: 1px solid var(--border-subtle);
    /* Light: transparent — the header shows the panel's own flat colour,
       so header and Paipan body match exactly (dark override below). */
    background: transparent;
    /* keep the panel's rounded top tidy now that the body overflow is visible */
    border-radius: var(--r-lg) var(--r-lg) 0 0;
}

.terminal-title {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.85rem;
    color: var(--text-primary);
    letter-spacing: 0.04em;
}

.terminal-title strong {
    color: var(--gold);
    font-weight: 600;
}

.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--r-pill);
    background: rgba(46, 204, 113, 0.12);
    border: 1px solid rgba(46, 204, 113, 0.35);
    color: var(--success);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.1em;
}

.status-pill::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--success);
    box-shadow: 0 0 8px var(--success);
    animation: pulse-dot 1.6s ease-in-out infinite;
}

@keyframes pulse-dot {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.terminal-clock {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.85rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* --- "Scholar's Desk" date & time selector (frosted glass) --- */
.time-control {
    margin-left: auto;      /* takes over the clock's old auto slot */
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px 4px 10px;
    background: rgba(0, 0, 0, 0.03);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 8px;
}

.time-ico {
    color: var(--text-muted);
    flex-shrink: 0;
}

/* The de-chromed native picker — quiet "Data" typography */
.time-input {
    background: transparent;
    border: none;
    outline: none;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.78rem;
    color: var(--text-secondary);
    width: 168px;
    cursor: pointer;
    color-scheme: light;    /* native popup matches the light panel (dark override below) */
}

.time-input::-webkit-calendar-picker-indicator {
    opacity: 0.45;
    cursor: pointer;
}

/* Quiet gold "reset to live" chip */
.time-live-btn {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 6px;
    border: 1px solid var(--gold-soft);
    color: var(--gold);
    background: transparent;
    cursor: pointer;
    transition: all var(--fast) var(--ease);
}

.time-live-btn:hover {
    background: var(--gold-soft);
    border-color: var(--gold);
}

/* While time-travelling the pill goes gold ● FIXED (honesty over vibes) */
.status-pill.is-fixed {
    /* Tokenised, not re-hardcoded — these two bypassed --gold entirely and so
       survived the gold→teal swap until caught by grepping the raw rgba. */
    background: var(--accent-soft);
    border-color: color-mix(in srgb, var(--accent) 40%, transparent);
    color: var(--gold);
}

.status-pill.is-fixed::before {
    background: var(--gold);
    box-shadow: 0 0 8px var(--gold-glow);
    animation: none;
}

.terminal-icon-btn {
    background: transparent;
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    width: 30px;
    height: 30px;
    border-radius: 8px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all var(--fast) var(--ease);
}

.terminal-icon-btn:hover {
    color: var(--gold);
    border-color: var(--gold);
}

.terminal-iframe-wrap {
    position: relative;
    overflow: hidden;    /* safety net — geometry is contained by construction */
    background: transparent;
    min-height: 860px;   /* tall stage = room for the scaled-up cells */
    display: flex;
    align-items: stretch;    /* the grid fills the full stage height */
    justify-content: center;
    padding: 24px;
}

.terminal-iframe-wrap iframe {
    display: block;
    border: 0;
    background: transparent;
}

/* ============================================================
   Native Paipan — "Neon Circuit"
   The traditional 3×3 Luoshu board: each palace is a glowing ring
   circle holding a 2×2 quadrant matrix (deity · door · star · palace
   name) over its Bagua trigram watermark, text in themed Wu Xing
   colours, and the Heaven / Earth stems orbiting the top / bottom
   arcs of each ring.
   ============================================================ */
#paipan-container {
    position: relative;
    width: 100%;
    min-height: 780px;
    display: block;      /* .paipan-grid fills it edge to edge */
    font-family: 'Inter', sans-serif;
}

/* Shared zh / py font split ("Art + Data", rule #2) */
#paipan-container .zh { font-family: 'Noto Serif SC', serif; }
#paipan-container .py { font-family: 'Space Grotesk', sans-serif; }

/* --- The 3×3 Luoshu grid: nine cells spread evenly to fill the entire
   Paipan stage (no width cap, no forced square — cells may be slightly
   rectangular on wide panels; the neon ring circle centres within each).
   The Tai Chi watermark sits behind the cells. */
.paipan-grid {
    position: relative;
    width: 100%;
    height: 100%;
    min-height: 780px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: 14px;
    padding: 6px;
}

/* Tai Chi backdrop — the hand-painted yin-yang (assets/tai chi.png,
   indigo ink on a white canvas) as a large SLOWLY ROTATING watermark
   behind the cells: a centred square bigger than the stage (118% of its
   height; the panel's overflow:hidden crops the spill), turning one full
   revolution every 90s. multiply melts the white canvas into the light
   panel; the dark override inverts + screens it so it reads pale on the
   neon board. */
.paipan-grid::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    height: 118%;
    aspect-ratio: 1;
    /* The painted disc's centre sits at 52.8%/42.8% of its canvas, not
       50/50. Measured as the midpoint of the TWO DOTS (a yin-yang's dots
       are symmetric about the disc centre) — the only crisp anchors, since
       the white half's rim is invisible on the white canvas and defeats
       every ink-based fit. Pin the rotation origin there and translate
       THAT point to the stage centre so the symbol renders centred and
       spins in place (no wobble). */
    transform-origin: 52.8% 42.8%;
    transform: translate(-52.8%, -42.8%);
    z-index: 0;
    pointer-events: none;
    background: url('../tai chi.png') center / contain no-repeat;
    mix-blend-mode: multiply;
    opacity: 0.15;
    animation: taichi-turn 90s linear infinite;
}

@keyframes taichi-turn {
    from { transform: translate(-52.8%, -42.8%) rotate(0deg); }
    to   { transform: translate(-52.8%, -42.8%) rotate(360deg); }
}

body.dark-theme .paipan-grid::before {
    filter: invert(1);
    mix-blend-mode: screen;
    opacity: 0.16;
}

/* Cells paint above the Tai Chi watermark layer */
.paipan-grid > * {
    z-index: 1;
}

/* Loading / error message */
.paipan-message {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    text-align: center;
    color: var(--text-muted);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.9rem;
    padding: 24px;
}

.paipan-message strong { color: var(--gold); }

/* --- The neon-ringed cells (palaces) ---
   Each cell is a crisp glowing circle (a real border + glow — no
   artwork). The circle is sized by the cell's HEIGHT (cells can be wider
   than tall), centred; the 2×2 matrix sits inside it and the stems orbit
   its edge. */
.palace-disc {
    position: relative;
    /* Query container: lets the ring/orbit size themselves from the cell's
       SMALLER dimension (cqw/cqh) — cells are only square-ish on desktop;
       on narrow screens they're taller than wide, and a height-sized ring
       overlaps its neighbours. */
    container-type: size;
    transition: all 0.4s var(--ease);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 16px;
    text-align: center;
    color: var(--text-primary);
}

/* The circuit ring — a true centred circle sized by the cell's SMALLER
   dimension (min of width/height via container-query units), so rings can
   never spill into neighbouring cells on narrow screens. Tinted by
   --ring-hue (pale cyan on the light Day Circuit, full neon cyan in dark). */
.palace-disc::before,
.paipan-core::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    /* fallback for engines without cq units (also keeps aspect-ratio moot) */
    height: 96%;
    aspect-ratio: 1;
    /* modern: square on min(cell width, cell height). cq units measure the
       CONTENT box (cell minus its 16px padding), so 108% of content ≈ the
       old 96%-of-cell ring size — while still provably ≤ the cell for any
       cell narrower than ~430px (0.08·w ≤ 2·16px padding). */
    width: min(108cqw, 108cqh);
    height: min(108cqw, 108cqh);
    transform: translate(-50%, -50%);
    border-radius: 50%;
    z-index: -1;
    pointer-events: none;
    border: 1px solid color-mix(in srgb, var(--ring-hue) 40%, transparent);
    box-shadow: 0 0 14px color-mix(in srgb, var(--ring-hue) 25%, transparent),
                inset 0 0 22px color-mix(in srgb, var(--ring-hue) 8%, transparent);
    transition: border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

.palace-disc:hover {
    transform: scale(1.03);
}

/* Hover: the ring itself brightens (the aura ::after adds the outer bloom) */
.palace-disc:hover::before {
    border-color: color-mix(in srgb, var(--ring-hue) 70%, transparent);
    box-shadow: 0 0 22px color-mix(in srgb, var(--ring-hue) 40%, transparent),
                inset 0 0 26px color-mix(in srgb, var(--ring-hue) 12%, transparent);
}

/* --- The centre "core" (Time Pillars) — the middle grid cell, same
   neon ring treatment. --- */
.paipan-core {
    position: relative;
    container-type: size;   /* same cqw/cqh ring sizing as the palaces */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 16px;
    text-align: center;
}

.core-pillars {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 5px 12px;
}

.bazi-pillar {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    min-width: 0;
}

.bazi-label {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.60rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.bazi-value .zh {
    font-size: 1.26rem;
    font-weight: 700;
    color: var(--ink-strong);
    line-height: 1.2;
    white-space: nowrap;
    text-shadow: var(--ink-glow);   /* silver halo in dark, none on light */
}

.bazi-value .py {
    display: block;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ink-soft);
    white-space: nowrap;
    text-shadow: var(--ink-glow-soft);
}

.core-date {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.74rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}

/* --- "Art + Data" disc typography ---
   The Art: Mandarin in Noto Serif SC, prominent. The Data: Pinyin in
   Space Grotesk, tucked directly beneath its Mandarin. All text carries
   a glow: silver halo by default, neon element glow via the wx-* rules. */
.palace-disc .zh {
    font-size: 1.08rem;
    font-weight: 700;
    color: var(--ink-strong);
    line-height: 1.12;
    text-shadow: var(--ink-glow);
}

.palace-disc .py {
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--ink-soft);
    line-height: 1.1;
    text-shadow: var(--ink-glow-soft);
}

/* --- Bagua trigram watermark (behind the 2×2 matrix) ---
   Three ink lines, TOP → BOTTOM per the palace's trigram: Yang = one
   continuous bar, Yin = two dashes with a centre gap. Traditional
   Shuimo ink — flat, faint, NO neon/glow — a pure background watermark
   the text floats over (matrix z-index 10 vs this layer's 0). */
.disc-trigram {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 46%;              /* spans the matrix zone inside the ring */
    height: 38%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    z-index: 0;
    pointer-events: none;
}

.tri-line {
    position: relative;
    height: 12%;             /* brushstroke thickness */
}

.tri-line.tri-solid {
    background: var(--trigram-ink);
    border-radius: 2px;      /* soften the bar ends — ink, not pixels */
}

/* Yin: two dashes (42% each) with a clear 16% gap in the middle */
.tri-line.tri-broken::before,
.tri-line.tri-broken::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 42%;
    background: var(--trigram-ink);
    border-radius: 2px;
}

.tri-line.tri-broken::before { left: 0; }
.tri-line.tri-broken::after  { right: 0; }

/* --- The 2×2 quadrant matrix (centre of the circle) ---
   Ba Shen (deity) top-left · Ba Men (door) top-right ·
   Jiu Xing (star) bottom-left · Palace Name bottom-right. */
.disc-matrix {
    position: relative;
    z-index: 10;             /* the text floats above the trigram ink */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 18px;
    width: 72%;          /* stays inside the neon ring */
    align-items: center;
    justify-items: center;
    text-align: center;
}

.disc-matrix .q { line-height: 1.05; }
.disc-matrix .py { display: block; }

/* Palace name (bottom-right quadrant) — full traditional form (坎一宮);
   its element colour comes from the wx-* class emitted by paipan.js.
   NO per-quadrant font-size overrides: every word in the 2×2 matrix
   inherits the same scale (.palace-disc .zh / .py). */
.disc-name .zh { letter-spacing: 0.06em; }
.disc-name .py {
    margin-top: 0;
    letter-spacing: 0.04em;
}

/* --- Orbiting stems ---
   The Heaven and Earth stems detach from the grid and ride the neon
   ring's edge: each lives in a square "orbit" box matching the ring
   (height-sized circle), pinned to the top / bottom arc, and the box
   oscillates ±30° about the circle's centre — a slow pendulum sweep
   along the curve. The two swings are phase-opposed at different
   durations so the pair never mirrors in lockstep. */
.stem-orbit {
    position: absolute;
    top: 50%;
    left: 50%;
    /* MUST match the ring ::before exactly so the stems ride its edge:
       fallback height+aspect, then min(cell width, cell height) squares. */
    height: 96%;
    aspect-ratio: 1;
    width: min(108cqw, 108cqh);
    height: min(108cqw, 108cqh);
    pointer-events: none;
    z-index: 2;
    /* static rest position (also where reduced-motion freezes the stems) */
    transform: translate(-50%, -50%);
}

.stem-orbit--heaven { animation: stem-swing-top 8s ease-in-out infinite; }
.stem-orbit--earth  { animation: stem-swing-bottom 9.5s ease-in-out infinite; }

@keyframes stem-swing-top {
    0%, 100% { transform: translate(-50%, -50%) rotate(-30deg); }
    50%      { transform: translate(-50%, -50%) rotate(30deg); }
}

@keyframes stem-swing-bottom {
    0%, 100% { transform: translate(-50%, -50%) rotate(30deg); }
    50%      { transform: translate(-50%, -50%) rotate(-30deg); }
}

/* The stem itself, centred on the ring's edge. Multi-stem palaces sit
   side by side in the carrier. */
.stem-carrier {
    position: absolute;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    gap: 8px;
}

.stem-orbit--heaven .stem-carrier { top: 0; }
.stem-orbit--earth  .stem-carrier { top: 100%; }

.stem-unit {
    line-height: 1.05;
    text-align: center;
}
.stem-unit .zh { font-size: 1.0rem; }
.stem-unit .py {
    display: block;
    font-size: 0.68rem;
}

/* --- Wu Xing text colours (NEON) ---
   Each chart term (Tian Gan, Di Zhi, Ba Shen, Ba Men, Jiu Xing — and the
   palace names) carries a wx-<element> class from paipan.js. The Art
   (Mandarin) takes the neon solid + a glowing halo; the Data (Pinyin)
   inherits the same neon slightly softened with a smaller halo. Placed
   after the typography rules so the element colour + glow win the cascade. */
.paipan-terminal .wx-wood  { --wx: var(--wx-wood); }
.paipan-terminal .wx-fire  { --wx: var(--wx-fire); }
.paipan-terminal .wx-earth { --wx: var(--wx-earth); }
.paipan-terminal .wx-metal { --wx: var(--wx-metal); }
.paipan-terminal .wx-water { --wx: var(--wx-water); }

.paipan-terminal [class*="wx-"] {
    color: var(--wx);
    /* light "day" bloom — a faint halo of the element's own hue.
       (Declared inline, not via a panel-scoped var: custom properties
       resolve their inner var()s where they're DECLARED, so a panel-level
       shadow list can't pick up the per-element --wx.) */
    text-shadow: 0 0 8px color-mix(in srgb, var(--wx) 22%, transparent);
}

/* The Data: Pinyin spans (or words inside a py span, e.g. pillar words)
   take the element hue at reduced strength with a tighter glow. */
.paipan-terminal .py[class*="wx-"],
.paipan-terminal .py [class*="wx-"] {
    color: color-mix(in srgb, var(--wx) 90%, transparent);
    text-shadow: 0 0 6px color-mix(in srgb, var(--wx) 15%, transparent);
}

/* Dark: the full two-layer NEON glow (the light rules above are the base) */
body.dark-theme .paipan-terminal [class*="wx-"] {
    text-shadow: 0 0 6px color-mix(in srgb, var(--wx) 80%, transparent),
                 0 0 16px color-mix(in srgb, var(--wx) 40%, transparent);
}

body.dark-theme .paipan-terminal .py[class*="wx-"],
body.dark-theme .paipan-terminal .py [class*="wx-"] {
    text-shadow: 0 0 5px color-mix(in srgb, var(--wx) 60%, transparent);
}

/* Status tags — chips riding the ring's right edge (3 o'clock).
   Laid out as a ROW so the cluster stays ~14px tall and sits inside the
   empty band between the matrix's two text rows (a 30px column would
   cover the door Pinyin above it on narrow cells). */
.palace-tags {
    position: absolute;
    top: 50%;
    right: 2%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: row;
    gap: 3px;
    align-items: center;
    z-index: 2;
}

.palace-tag {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.5rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 1px 5px;
    border-radius: var(--r-pill);
    background: var(--tag-bg);   /* white chip on light, dark chip in dark */
    white-space: nowrap;
}

.palace-tag.kong { color: var(--danger); box-shadow: inset 0 0 0 1px rgba(214, 69, 62, 0.35); }
.palace-tag.yima { color: var(--blue); box-shadow: inset 0 0 0 1px var(--blue-soft); }

/* ============================================================
   Phone detail sheet — the drill-down half of the mobile chart
   Hidden entirely above 560px (paipan.js gates every entry point on
   the same media query); the desktop cells already show this detail.
   ============================================================ */

/* "Tap a palace…" — revealed only in the ≤560px block. */
.paipan-hint {
    display: none;
    margin: 10px 0 0;
    text-align: center;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.palace-sheet-backdrop {
    position: fixed;
    inset: 0;
    z-index: 80;
    background: rgba(8, 12, 20, 0.5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s var(--ease);
}
.palace-sheet-backdrop.is-open { opacity: 1; pointer-events: auto; }

.palace-sheet {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 81;
    transform: translateY(100%);
    transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
    max-height: 82vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 10px 20px calc(22px + env(safe-area-inset-bottom, 0px));
    background: var(--bg-elevated);
    border-top: 1px solid var(--border-subtle);
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -12px 44px rgba(0, 0, 0, 0.20);

    /* This sheet lives on <body> (the panel's backdrop-filter would make it
       the containing block for position:fixed), so it can't inherit anything
       panel-scoped. That used to mean re-declaring the Wu Xing palette here;
       it now inherits from :root like everything else, and stays in sync for
       free. */
}
.palace-sheet.is-open { transform: translateY(0); }

/* Lock the page behind the sheet */
body.sheet-open { overflow: hidden; }

.sheet-grip {
    width: 38px;
    height: 4px;
    margin: 0 auto 14px;
    border-radius: var(--r-pill);
    background: var(--border-strong);
}

.sheet-close {
    position: absolute;
    top: 10px;
    right: 14px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--text-muted);
    background: transparent;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.sheet-close:hover { color: var(--text-primary); background: var(--bg-glass); }

.sheet-title {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    padding-right: 40px;      /* clear of the close button */
    margin-bottom: 14px;
}
.sheet-title .zh {
    font-family: 'Noto Serif SC', serif;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}
.sheet-title .py {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.sheet-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
}
.sheet-tags .palace-tag {
    font-size: 0.66rem;
    padding: 4px 10px;
    background: transparent;
}

.sheet-rows { margin: 0; }
.sheet-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 0;
    border-top: 1px solid var(--border-subtle);
}
.sheet-row dt {
    flex: 0 0 auto;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.sheet-row dd {
    flex: 1 1 auto;
    margin: 0;
    text-align: right;
}
/* Art + Data, side by side at a size that's actually readable */
.sheet-row dd .zh {
    font-family: 'Noto Serif SC', serif;
    font-size: 1.15rem;
    font-weight: 700;
}
.sheet-row dd .py {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.8rem;
    font-weight: 600;
    margin-left: 7px;
}
.sheet-sep {
    margin: 0 8px;
    color: var(--text-muted);
}

/* Element inks inside the sheet (mirrors the panel's plumbing) */
.palace-sheet .wx-wood  { --wx: var(--wx-wood); }
.palace-sheet .wx-fire  { --wx: var(--wx-fire); }
.palace-sheet .wx-earth { --wx: var(--wx-earth); }
.palace-sheet .wx-metal { --wx: var(--wx-metal); }
.palace-sheet .wx-water { --wx: var(--wx-water); }
.palace-sheet [class*="wx-"] { color: var(--wx); }
.palace-sheet .py[class*="wx-"],
.palace-sheet .py [class*="wx-"] {
    color: color-mix(in srgb, var(--wx) 82%, transparent);
}

/* --- Highlight (driven by the AI oracle) ---
   The named palace's ring goes full-electric — border to solid
   cyan-white + a hard glow, like a circuit lighting up. */
.palace-disc.palace-highlighted {
    transform: scale(1.05);
}

.palace-disc.palace-highlighted::before {
    border-color: color-mix(in srgb, var(--ring-hue) 60%, white);
    box-shadow: 0 0 30px color-mix(in srgb, var(--ring-hue) 55%, transparent),
                inset 0 0 30px color-mix(in srgb, var(--ring-hue) 18%, transparent);
}

/* Aura layer — a soft electric bloom behind the ring: ring-hue core with a
   faint WARM rim. The rim uses --aura-warm, not the brand accent: the accent is
   now teal, and teal-on-cyan would blur into the rings instead of marking the
   palace the Oracle named. Cheap to composite (opacity-only toggle). */
.palace-disc::after {
    content: "";
    position: absolute;
    inset: -6%;
    z-index: -2;
    pointer-events: none;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--ring-hue) 35%, transparent) 30%,
        color-mix(in srgb, var(--aura-warm) 18%, transparent) 55%,
        transparent 72%);
    filter: blur(6px);
    opacity: 0;
    transition: opacity 0.4s var(--ease);
}

.palace-disc.palace-highlighted::after { opacity: 1; }
.palace-disc:hover::after { opacity: 0.55; }

/* Focus Mode: while any palace is highlighted, the unselected cells (and
   the centre stone) fade back so the eye lands on the active node.
   (.palace-disc already transitions `all`, which covers opacity.) */
.paipan-grid.has-focus .palace-disc:not(.palace-highlighted),
.paipan-grid.has-focus .paipan-core {
    opacity: 0.4;
}

.paipan-core {
    transition: opacity 0.4s var(--ease);
}

/* Smaller screens: a 6-row bilingual circle can't shrink below ~140px and
   stay legible, so the pond keeps a 480px minimum and the stage becomes
   horizontally pannable (map-style) instead of crushing the discs. */
/* ============================================================
   PHONE (≤560px) — the whole 3×3 on one screen

   The chart used to keep its desktop size and pan sideways, which meant
   only ~half the grid was ever visible — fatal for a Paipan, which is
   read spatially (palace against palace, palace against direction).
   Here the grid fits the viewport instead, and the cells carry ONLY the
   Mandarin: big, Wu Xing-coloured, glanceable. The Pinyin and the full
   Art + Data detail move into the tap sheet (.palace-sheet), because at
   this cell size Pinyin would land at ~8px — worse than not showing it.
   ============================================================ */
@media (max-width: 560px) {
    /* --- Stage: fit, don't pan; height follows the square grid --- */
    .terminal-iframe-wrap {
        overflow: hidden;
        min-height: 0;
        padding: 10px;
        align-items: center;
    }
    #paipan-container { min-height: 0; }
    .paipan-grid {
        min-width: 0;
        min-height: 0;
        height: auto;
        aspect-ratio: 1 / 1;   /* square board → square-ish cells */
        gap: 6px;
        padding: 0;
    }
    /* Tai Chi fills the square board (no spill to clip). */
    .paipan-grid::before { height: auto; width: 100%; }

    /* --- Cells: Mandarin only (the Data lives in the sheet) --- */
    .paipan-grid .disc-matrix .py,
    .paipan-grid .stem-unit .py,
    .paipan-grid .bazi-label,
    .paipan-grid .bazi-value .py { display: none; }

    .palace-disc,
    .paipan-core {
        padding: 6px;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }
    /* The tall ROW gap is deliberate: it opens the corridor the Kong / Ma
       chips sit in at middle-right (the desktop chart works the same way).
       Width stays generous — the chips only need the vertical corridor. */
    .disc-matrix { width: 88%; gap: 14px 6px; }
    /* nowrap: a 2-glyph term must never break to 螣 / 蛇 */
    .palace-disc .zh { font-size: 15px; white-space: nowrap; }
    .disc-door .zh  { font-size: 15px; }   /* the door stays the hero */
    .stem-unit .zh  { font-size: 13px; }
    /* Palace name is 3 glyphs (離九宮) in a ~41px column — size it to sit on
       ONE line, or it breaks to "離九 / 宮". */
    .disc-name .zh {
        font-size: 11.5px;
        letter-spacing: 0;
        white-space: nowrap;
    }

    /* The Bagua watermark is tuned for big desktop cells; at this scale its
       three bars read as a strikethrough behind the glyphs. Halve it so it
       stays a watermark. */
    .disc-trigram { opacity: 0.5; }

    /* Centre cell: four pillar glyphs + the date */
    .core-pillars { gap: 2px 8px; }
    .bazi-value .zh { font-size: 14px; }
    .core-date { font-size: 8.5px; letter-spacing: 0.02em; }

    /* Status chips ride the ring's right edge, exactly like the desktop
       chart — they inherit top:50% / translateY(-50%) from the base rule.
       The matrix's tall row gap above is what keeps them clear of the text
       (same trick as desktop): the chips sit in that corridor. Glyph only
       here; the sheet spells out "Kong Wang · Void" / "Yi Ma". */
    .palace-tags { right: 1%; gap: 2px; }
    .palace-tag { font-size: 9px; padding: 0 2px; }
    .palace-tag .tag-py { display: none; }

    /* Tap affordance — the cells no longer spell everything out. */
    .paipan-hint { display: block; }

    /* ============================================================
       VARIANT B — Pinyin in the cells (comparison build)
       Everything above renders Mandarin-only. This block adds the Data
       layer back: the board grows ~18% taller to buy each cell a second
       text line, the glyphs shrink, and the Pinyin sits at 8px and is
       allowed to wrap ("Tian Chong" → two lines) because a 35px column
       cannot hold it otherwise.
       Delete this whole block to return to the Mandarin-only chart.
       ============================================================ */
    .paipan-grid { aspect-ratio: 1 / 1.18; }   /* taller cells for 2 lines */

    .paipan-grid .disc-matrix .py,
    .paipan-grid .stem-unit .py,
    .paipan-grid .bazi-value .py { display: block; }

    .palace-disc .zh { font-size: 13px; }
    .disc-door .zh  { font-size: 13.5px; }
    .disc-name .zh  { font-size: 10.5px; }

    .disc-matrix .py {
        font-size: 8px;
        line-height: 1.15;
        letter-spacing: 0;
        white-space: normal;   /* long romanisations wrap rather than clip */
    }
    .stem-unit .zh  { font-size: 11px; }
    .stem-unit .py  { font-size: 7.5px; line-height: 1.1; }
    .bazi-value .zh { font-size: 12px; }
    .bazi-value .py { font-size: 7.5px; line-height: 1.1; }

    /* --- Header: 4 wrapped rows → 2 --- */
    .terminal-header { padding: 12px 14px; gap: 8px; row-gap: 6px; }
    .terminal-title { font-size: 0.72rem; }
    .terminal-clock { font-size: 0.7rem; margin-left: auto; }
    .time-control {
        order: 9;             /* drops below the title row… */
        flex: 1 1 100%;       /* …and spans the full width   */
        margin-left: 0;
    }
    .time-input { flex: 1 1 auto; width: auto; }
}

@media (prefers-reduced-motion: reduce) {
    .palace-disc { transition: none; }
    /* Stems rest at the top / bottom centre of their rings; the Tai Chi
       watermark freezes upright */
    .stem-orbit--heaven,
    .stem-orbit--earth { animation: none; }
    .paipan-grid::before { animation: none; }
}

.terminal-fallback {
    position: absolute;
    inset: 0;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    text-align: center;
    color: var(--text-muted);
    padding: 32px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.85rem;
    pointer-events: none;
    background: var(--bg-deep);
}

.terminal-iframe-wrap.is-failed .terminal-fallback {
    display: flex;
}

.terminal-fallback strong {
    color: var(--gold);
}

.terminal-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px;
    background: var(--border-subtle);
    border-top: 1px solid var(--border-subtle);
}

.stat-cell {
    padding: 18px 20px;
    background: var(--bg-elevated);
}

.stat-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.stat-value {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--text-primary);
}

.stat-value .text-gold {
    color: var(--gold);
}

/* --- Chat Panel --- */
.chat-panel {
    position: sticky;
    top: calc(var(--nav-h) + 24px);
    display: flex;
    flex-direction: column;
    height: calc(100vh - var(--nav-h) - 48px);
    max-height: 760px;
    min-height: 560px;
    overflow: hidden;
}

.chat-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.chat-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    /* FeiQingYi profile photo — light theme (white-background version). Dark theme swaps below. */
    background: url('../FeiQingYi Profile Image (White Background).png') center / cover no-repeat;
    border: 1px solid var(--gold);
    box-shadow: 0 0 16px var(--gold-glow);
    flex-shrink: 0;
}

/* The white-background FeiQingYi photo is used in BOTH themes (no dark swap). */

.chat-header-text {
    flex: 1;
    min-width: 0;
}

.chat-header-text h4 {
    margin: 0;
    font-size: 0.95rem;
}

.chat-header-text .subtitle {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin: 0;
}

/* Expand / collapse button in the chat header */
.chat-expand-btn {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    border: 1px solid var(--border-subtle);
    background: var(--bg-glass);
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all var(--fast) var(--ease);
}

.chat-expand-btn:hover {
    color: var(--gold);
    border-color: var(--gold);
    background: var(--gold-soft);
}

.chat-expand-btn .icon-collapse { display: none; }
.chat-expand-btn[data-state="expanded"] .icon-expand { display: none; }
.chat-expand-btn[data-state="expanded"] .icon-collapse { display: inline-block; }

/* Backdrop shown behind the expanded chat overlay */
.chat-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 60;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--med) var(--ease);
}

.chat-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
}

/* Expanded chat panel — fullscreen-style overlay */
.chat-panel.is-expanded {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(960px, 90vw);
    height: 85vh;
    max-height: none;
    min-height: 0;
    z-index: 70;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.16);
    animation: chat-expand-in 280ms var(--ease-out);
}

@keyframes chat-expand-in {
    from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
    to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

@keyframes chat-expand-in-mobile {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@media (max-width: 720px) {
    .chat-panel.is-expanded {
        /* ANCHOR, don't centre. The desktop rule centres the panel with
           top:50% + translate(-50%,-50%); on a phone `100vh` is the LARGE
           viewport (measured as if the URL bar were retracted), so it exceeds
           the visible area whenever browser chrome is showing. Centring split
           that excess evenly top and bottom, pushing the panel's top negative
           and carrying the header — and the only collapse button — off the top
           of the screen. With no Escape key and the backdrop fully covered by
           the panel, that left no way out at all, and the persisted
           qimen_chat_expanded flag re-trapped the user on reload.
           top:0 + transform:none is what makes this safe: the header cannot
           rise above the screen whatever the height unit resolves to. */
        top: 0;
        left: 0;
        transform: none;
        width: 100%;
        height: 100vh;      /* fallback for engines without dvh */
        height: 100dvh;     /* tracks the VISIBLE area as the URL bar moves */
        max-height: 100dvh;
        max-width: 100%;
        border-radius: 0;
        /* Keep the header clear of the notch / status bar. */
        padding-top: env(safe-area-inset-top, 0px);
        /* The shared entry keyframe animates transform back to the centring
           translate, and a running animation beats the base rule — so without
           this override the panel would re-centre for its 280ms and flash the
           collapse button off-screen. */
        animation: chat-expand-in-mobile 220ms var(--ease-out);
    }
}

.chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}

.chat-messages::-webkit-scrollbar {
    width: 6px;
}

.chat-messages::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: 3px;
}

.chat-bubble {
    max-width: 86%;
    padding: 12px 16px;
    border-radius: 14px;
    font-size: 0.92rem;
    line-height: 1.55;
    animation: bubble-in 280ms var(--ease-out);
}

@keyframes bubble-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.chat-bubble--ai {
    align-self: flex-start;
    background: var(--bg-glass-strong);
    border: 1px solid var(--border-subtle);
    border-left: 2px solid var(--gold);
    color: var(--text-primary);
    border-top-left-radius: 4px;
}

/* ---- Markdown rendered inside AI bubbles ---- */
.chat-bubble--ai > *:first-child { margin-top: 0; }
.chat-bubble--ai > *:last-child  { margin-bottom: 0; }

.chat-bubble--ai p {
    margin: 0 0 0.7em;
    color: var(--text-primary);
    line-height: 1.55;
}

.chat-bubble--ai h1,
.chat-bubble--ai h2,
.chat-bubble--ai h3,
.chat-bubble--ai h4,
.chat-bubble--ai h5,
.chat-bubble--ai h6 {
    margin: 1em 0 0.4em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--gold);
}

.chat-bubble--ai h1 { font-size: 1.1rem; }
.chat-bubble--ai h2 { font-size: 1.05rem; }
.chat-bubble--ai h3 { font-size: 1rem; }
.chat-bubble--ai h4,
.chat-bubble--ai h5,
.chat-bubble--ai h6 {
    font-size: 0.92rem;
    color: var(--gold-bright);
    text-transform: none;
    letter-spacing: 0;
}

.chat-bubble--ai strong,
.chat-bubble--ai b {
    font-weight: 600;
    color: var(--gold-bright);
}

.chat-bubble--ai em,
.chat-bubble--ai i {
    font-style: italic;
    color: var(--text-primary);
}

.chat-bubble--ai del,
.chat-bubble--ai s {
    color: var(--text-muted);
}

.chat-bubble--ai a {
    color: var(--blue);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.chat-bubble--ai a:hover {
    color: var(--blue-bright);
}

.chat-bubble--ai ul,
.chat-bubble--ai ol {
    margin: 0.3em 0 0.7em;
    padding-left: 1.4em;
}

.chat-bubble--ai li {
    margin-bottom: 0.3em;
    line-height: 1.5;
}

.chat-bubble--ai li::marker {
    color: var(--gold);
}

.chat-bubble--ai li > p {
    margin: 0 0 0.3em;
}

.chat-bubble--ai blockquote {
    margin: 0.5em 0;
    padding: 0.4em 0.9em;
    border-left: 2px solid var(--gold);
    background: var(--gold-soft);
    color: var(--text-secondary);
    border-radius: 0 6px 6px 0;
    font-style: italic;
}

.chat-bubble--ai code {
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    font-size: 0.86em;
    background: rgba(0, 0, 0, 0.04);
    color: #8A6D3B;
    padding: 1px 6px;
    border-radius: 4px;
    border: 1px solid var(--border-subtle);
}

.chat-bubble--ai pre {
    margin: 0.6em 0;
    padding: 12px 14px;
    background: #F4F3EF;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    overflow-x: auto;
    font-size: 0.85em;
    line-height: 1.5;
}

.chat-bubble--ai pre code {
    background: transparent;
    border: 0;
    padding: 0;
    color: var(--text-primary);
    font-size: inherit;
}

.chat-bubble--ai hr {
    margin: 1em 0;
    border: 0;
    border-top: 1px solid var(--border-subtle);
}

.chat-bubble--ai table {
    width: 100%;
    border-collapse: collapse;
    margin: 0.6em 0;
    font-size: 0.9em;
}

.chat-bubble--ai th,
.chat-bubble--ai td {
    padding: 6px 10px;
    text-align: left;
    border-bottom: 1px solid var(--border-subtle);
}

.chat-bubble--ai th {
    color: var(--gold);
    font-weight: 600;
    background: rgba(0, 0, 0, 0.03);
}

/* ---- KaTeX math rendered inside AI bubbles ---- */
.chat-bubble--ai .katex {
    color: var(--text-primary);
    font-size: 1.02em;
}

.chat-bubble--ai .katex-display {
    margin: 0.6em 0;
    padding: 4px 2px;
    overflow-x: auto;       /* wide block equations scroll instead of overflowing */
    overflow-y: hidden;
}

.chat-bubble--ai .katex-display > .katex {
    white-space: nowrap;
}

/* Collapsed "working" of a long oracle reply — see foldAboveSummary() in
   chat.js. The summary is hoisted above; nothing is discarded. */
.reply-fold {
    display: none;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px dashed var(--border-subtle);
}

.reply-fold.is-open { display: block; }

.reply-fold-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    padding: 5px 12px;
    border-radius: var(--r-pill);
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.reply-fold-toggle::after { content: '▾'; font-size: 0.85em; }
.reply-fold-toggle[aria-expanded="true"]::after { content: '▴'; }

/* The closing toggle exists only while the working is expanded — collapsed,
   it would sit directly beneath the opening one. */
.reply-fold-toggle.is-hidden { display: none; }
.reply-fold-toggle--end { margin-bottom: 4px; }

.reply-fold-toggle:hover {
    color: var(--gold);
    border-color: var(--gold);
}

.chat-bubble--user {
    align-self: flex-end;
    background: linear-gradient(135deg, var(--blue-soft), rgba(77, 168, 255, 0.04));
    border: 1px solid rgba(77, 168, 255, 0.25);
    color: var(--text-primary);
    border-top-right-radius: 4px;
}

.chat-bubble--thinking {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.thinking-dots {
    display: inline-flex;
    gap: 4px;
}

.thinking-dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--gold);
    animation: dot-pulse 1.4s ease-in-out infinite;
}

.thinking-dots span:nth-child(2) { animation-delay: 0.18s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.36s; }

@keyframes dot-pulse {
    0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
    40% { opacity: 1; transform: scale(1); }
}

.chat-input-wrap {
    position: relative;
    border-top: 1px solid var(--border-subtle);
    padding: 14px;
    background: rgba(0, 0, 0, 0.02);
}

/* "Back to my question" pill — floats just above the input box (absolute
   against .chat-input-wrap, which is position: relative). Hidden until a
   long reply pushes the question out of view; chat.js toggles .is-visible. */
.chat-jump {
    position: absolute;
    bottom: calc(100% + 6px);
    right: 14px;
    z-index: 6;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: var(--r-pill);
    border: 1px solid var(--border-subtle);
    background: var(--bg-glass-strong);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.10);
    color: var(--text-secondary);
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transform: translateY(6px);
    transition: opacity var(--med) var(--ease), transform var(--med) var(--ease),
                color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.chat-jump.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.chat-jump:hover {
    color: var(--gold);
    border-color: var(--gold);
}

/* No conversation to navigate while the sign-in overlay is up */
.chat-input-wrap.is-locked .chat-jump { display: none; }

@media (max-width: 560px) {
    .chat-jump { padding: 7px; right: 10px; }
    .chat-jump span { display: none; }   /* arrow only — space is tight */
}

@media (prefers-reduced-motion: reduce) {
    .chat-jump { transition: none; }
}

.chat-input-row {
    display: flex;
    gap: 10px;
    align-items: flex-end;
    background: var(--bg-elevated);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: 8px 8px 8px 14px;
    transition: border-color var(--fast) var(--ease);
}

.chat-input-row:focus-within {
    border-color: var(--gold);
    box-shadow: 0 0 0 3px var(--gold-soft);
}

.chat-input {
    flex: 1;
    background: transparent;
    border: 0;
    outline: none;
    resize: none;
    font-family: inherit;
    font-size: 0.92rem;
    color: var(--text-primary);
    line-height: 1.5;
    max-height: 120px;
    padding: 6px 0;
}

.chat-input::placeholder {
    color: var(--text-muted);
}

.chat-send {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 10px;
    border: 0;
    background: linear-gradient(135deg, var(--gold), var(--gold-bright));
    color: #1A140A;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 14px var(--gold-glow);
    transition: all var(--fast) var(--ease);
}

.chat-send:hover {
    transform: scale(1.05) rotate(-8deg);
    box-shadow: 0 6px 20px var(--gold-glow);
}

.chat-send:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
}

/* Premium lock overlay */
.chat-lock {
    position: absolute;
    inset: 0;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    background: rgba(249, 249, 246, 0.82);
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 20px;
    text-align: center;
    border-radius: 0 0 var(--r-lg) var(--r-lg);
}

.chat-input-wrap.is-locked .chat-lock {
    display: flex;
}

.chat-lock-icon {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--gold-soft);
    border: 1px solid var(--gold);
    color: var(--gold);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.05rem;
}

.chat-lock-text {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin: 0;
}

/* ---- Sign-in / credits UI (Phase 3) ----
   The overlay lives inside .chat-input-wrap (a ~70px bar), so the original
   `inset: 0` sized it to that bar and clipped anything taller — which the
   Google button + divider made obvious. Anchor it to the BOTTOM instead and
   let it grow upward over the message list (correct while locked); the
   min-height keeps it covering the input bar when the content is short. */
.chat-lock {
    inset: auto 0 0 0;
    height: auto;
    min-height: 100%;
    padding: 20px 22px;
    gap: 10px;
    text-align: center;
    overflow-y: auto;
}
.chat-lock .btn { width: 100%; max-width: 240px; }

/* Keep the "or" rule the same width as the 240px buttons */
.chat-lock .auth-divider {
    width: 100%;
    max-width: 240px;
    margin: 4px 0;
}

.chat-login {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
    max-width: 240px;
}
.chat-login-input {
    width: 100%;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid var(--border-strong);
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.9rem;
}
.chat-login-input:focus {
    outline: none;
    border-color: var(--gold);
    box-shadow: 0 0 0 2px var(--gold-soft);
}
.chat-login-hint {
    font-size: 0.72rem;
    color: var(--text-muted);
    margin: 2px 0 0;
    max-width: 260px;
}
.chat-login-error {
    font-size: 0.74rem;
    color: var(--danger);
    margin: 4px 0 0;
}

/* "✦ N questions left · Sign out" bar under the chat header */
.chat-meta {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    padding: 4px 16px;
    font-size: 0.74rem;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border-subtle);
}
.chat-credits { color: var(--gold); font-weight: 600; }
.chat-link-btn {
    background: none;
    border: none;
    padding: 0;
    color: var(--text-secondary);
    font: inherit;
    font-size: 0.74rem;
    cursor: pointer;
    text-decoration: underline;
}
.chat-link-btn:hover { color: var(--gold); }

/* ============================================================
   Google OAuth sign-in button + "or" divider
   Shared by the chat lock and the nav sign-in modal. Neutral
   surface per Google's branding guidance (the four-colour "G"
   must sit on a light/white or dark-neutral field, never gold).
   ============================================================ */
.btn--google {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background: #FFFFFF;
    color: #1F1F1F;
    border: 1px solid var(--border-strong);
    font-weight: 600;
}

.btn--google:hover {
    background: #F7F8F8;
    border-color: var(--text-muted);
}

.btn--google .google-g { flex-shrink: 0; display: block; }

.btn--google:disabled { opacity: 0.6; cursor: default; }

/* Dark theme: Google's dark-surface recommendation (#131314) */
body.dark-theme .btn--google {
    background: #131314;
    color: #E3E3E3;
    border-color: rgba(255, 255, 255, 0.18);
}
body.dark-theme .btn--google:hover { background: #1E1F20; }

/* "or" divider — hairlines either side of the word */
.auth-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0;
    color: var(--text-muted);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.auth-divider::before,
.auth-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border-subtle);
}

/* ============================================================
   Checkout — sign-in modal + account strip (Phase 4)
   ============================================================ */
.auth-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.auth-modal-backdrop.is-open { display: flex; }
.auth-modal {
    position: relative;
    width: 100%;
    max-width: 380px;
    padding: 28px 26px 24px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: 16px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
}
.auth-modal-close {
    position: absolute;
    top: 12px;
    right: 14px;
    width: 30px;
    height: 30px;
    background: none;
    border: none;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
}
.auth-modal-close:hover { color: var(--text-primary); }
.auth-modal-title {
    margin: 0 0 8px;
    font-size: 1.2rem;
}
.auth-modal-text {
    margin: 0 0 16px;
    font-size: 0.86rem;
    color: var(--text-secondary);
    line-height: 1.5;
}
.auth-modal-form { display: flex; flex-direction: column; gap: 10px; }
.auth-modal-input {
    width: 100%;
    padding: 11px 13px;
    font-size: 0.9rem;
    color: var(--text-primary);
    background: var(--bg-base);
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    outline: none;
}
.auth-modal-input:focus { border-color: var(--gold); }
.auth-modal-hint {
    margin: 12px 0 0;
    font-size: 0.74rem;
    color: var(--text-muted);
    text-align: center;
}
.auth-modal-error {
    margin: 10px 0 0;
    font-size: 0.78rem;
    color: var(--danger);
}

.account-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 18px;
    margin-top: 24px;
    padding: 12px 18px;
    border-radius: 12px;
    font-size: 0.84rem;
    color: var(--text-secondary);
}
.account-who strong { color: var(--text-primary); }
.account-actions { display: inline-flex; align-items: center; gap: 16px; }
.account-link {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--gold);
    text-decoration: underline;
    cursor: pointer;
}
.account-link:hover { color: var(--text-primary); }

@media (max-width: 1080px) {
    .chat-panel {
        position: relative;
        top: auto;
        height: auto;
        max-height: none;
        min-height: 520px;
    }
}

/* ============================================================
   Page: History (history.html)
   ============================================================ */

.history-hero {
    padding: 96px 0 64px;
    text-align: center;
    position: relative;
}

.history-hero::before {
    content: "";
    position: absolute;
    inset: -40px 0 0;
    background:
        radial-gradient(500px 280px at 50% 30%, var(--gold-soft), transparent 70%),
        radial-gradient(400px 220px at 30% 60%, var(--blue-soft), transparent 70%);
    pointer-events: none;
    z-index: -1;
}

.history-hero h1 {
    max-width: 880px;
    margin: 0 auto 20px;
}

.history-hero .lede {
    font-size: 1.15rem;
    max-width: 680px;
    margin: 0 auto;
    color: var(--text-secondary);
}

/* About Qimen has no hero, so its <h1> lives inside the first .story-section
   (the Etymology heading) rather than in a page header. It must stay
   semantically the page title while READING as a section heading — without
   this it would jump from h2's clamp(1.75rem, 3vw, 2.5rem) to h1's
   clamp(2.25rem, 4.5vw, 3.75rem) and tower over its siblings. */
.story-section h1 {
    font-size: clamp(1.75rem, 3vw, 2.5rem);
}

.story-section {
    padding: 80px 0;
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
}

.story-section.is-visible {
    opacity: 1;
    transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
    .story-section {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

.section-head {
    text-align: center;
    margin-bottom: 48px;
}

.section-head h2 {
    margin-bottom: 12px;
}

.section-head p {
    max-width: 640px;
    margin: 0 auto;
    font-size: 1.02rem;
}

/* Two-column origin section */
.origin-grid {
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    gap: 56px;
    align-items: center;
}

.origin-text p {
    margin-bottom: 14px;
}

.lo-shu-card {
    position: relative;
    padding: 32px;
    text-align: center;
    background:
        radial-gradient(circle at 50% 50%, rgba(212, 175, 55, 0.1), transparent 70%),
        var(--bg-glass);
}

.lo-shu-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    aspect-ratio: 1;
    max-width: 320px;
    margin: 0 auto 18px;
    padding: 4px;
    background: var(--gold-soft);
    border-radius: var(--r-md);
}

.lo-shu-grid div {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #FBF8F1;
    border-radius: 8px;
    font-family: 'Noto Serif SC', serif;
    font-size: 2rem;
    font-weight: 600;
    color: var(--gold);
    aspect-ratio: 1;
}

.lo-shu-card p {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.78rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0;
}

@media (max-width: 880px) {
    .origin-grid {
        grid-template-columns: 1fr;
        gap: 32px;
    }
}

/* Etymology cards */
.etymology-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);   /* 2×2 tiles */
    gap: 18px;
}

/* Each tile opens a dialog, so it is a real <button>. That means resetting the
   UA button styling first, or the glass-panel look never shows through. */
.etymology-card {
    padding: 28px 22px;
    text-align: center;
    font: inherit;
    color: inherit;
    cursor: pointer;
    transition: transform var(--med) var(--ease), border-color var(--med) var(--ease);
}

.etymology-card:hover {
    transform: translateY(-4px);
    border-color: var(--gold);
}

.etymology-card:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* Long-form copy is authored inside the tile but only ever rendered in the
   dialog — wireEtymology() clones it across. */
.etymology-more { display: none; }

.etymology-char {
    font-family: 'Noto Serif SC', serif;
    font-size: 4.5rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 8px;
    background: linear-gradient(180deg, var(--gold-bright), var(--gold));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.etymology-pinyin {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 14px;
}

.etymology-card h4 {
    color: var(--text-primary);
    font-size: 1rem;
    margin-bottom: 8px;
}

.etymology-card p {
    font-size: 0.86rem;
    color: var(--text-secondary);
    margin: 0;
}

/* Two tiles plus a 4.5rem glyph get cramped on a phone — go single column. */
@media (max-width: 560px) {
    .etymology-grid {
        grid-template-columns: 1fr;
    }
}

/* ---- Etymology dialog — flip-to-expand ----
   Shell mirrors .auth-modal-backdrop (fixed inset-0, flex-centred, dim + blur)
   but wider, since this holds several paragraphs rather than a sign-in form.
   `perspective` here is what makes the child's rotateY read as a flip rather
   than a squash. */
.etym-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    perspective: 1200px;
}

.etym-modal-backdrop.is-open { display: flex; }

.etym-modal {
    position: relative;
    width: 100%;
    max-width: 560px;
    max-height: 84vh;
    overflow-y: auto;
    padding: 32px 30px 28px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: 18px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
    backface-visibility: hidden;
    animation: etym-flip-in 340ms var(--ease-out);
}

@keyframes etym-flip-in {
    from { opacity: 0; transform: rotateY(-90deg) scale(0.94); }
    to   { opacity: 1; transform: rotateY(0deg) scale(1); }
}

.etym-modal-close {
    position: absolute;
    top: 12px;
    right: 14px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 50%;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
}

.etym-modal-close:hover { color: var(--text-primary); }

.etym-modal .etymology-char { font-size: 5rem; margin-bottom: 6px; }
.etym-modal .etymology-pinyin { margin-bottom: 10px; }

.etym-modal-title {
    font-size: 1.35rem;
    text-align: center;
    margin: 0 0 18px;
    color: var(--text-primary);
}

.etym-modal-body { text-align: left; }

.etym-modal-body p {
    font-size: 0.95rem;
    color: var(--text-secondary);
    margin: 0 0 14px;
}

.etym-modal-body ul {
    margin: 0 0 14px;
    padding-left: 20px;
    list-style: disc;
    font-size: 0.92rem;
    color: var(--text-secondary);
}

.etym-modal-body li { margin-bottom: 6px; }
.etym-modal-body strong { color: var(--text-primary); }

@media (prefers-reduced-motion: reduce) {
    /* Keep the dialog, drop the rotation. */
    .etym-modal { animation: none; }
}

/* Foundational theories 2x2 */
.theories-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 18px;
}

.theory-card {
    padding: 28px;
    display: flex;
    gap: 18px;
    align-items: flex-start;
    transition: transform var(--med) var(--ease);
}

.theory-card:hover {
    transform: translateY(-3px);
}

.theory-icon {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: var(--gold-soft);
    border: 1px solid var(--gold);
    color: var(--gold);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Noto Serif SC', serif;
    font-size: 1.4rem;
    font-weight: 700;
}

.theory-body h4 {
    margin-bottom: 4px;
    font-size: 1.05rem;
}

.theory-body .pinyin-sub {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    display: block;
}

.theory-body p {
    margin: 0;
    font-size: 0.92rem;
}

@media (max-width: 720px) {
    .theories-grid {
        grid-template-columns: 1fr;
    }
}

/* Timeline */
.timeline {
    position: relative;
    max-width: 920px;
    margin: 0 auto;
    padding: 20px 0;
}

.timeline::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 2px;
    background: linear-gradient(180deg, transparent, var(--gold), var(--gold), transparent);
    transform: translateX(-1px);
}

.timeline-row {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 80px 1fr;
    gap: 16px;
    margin-bottom: 32px;
    align-items: center;
}

.timeline-row:last-child {
    margin-bottom: 0;
}

.timeline-marker {
    grid-column: 2;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--bg-base);
    border: 2px solid var(--gold);
    margin: 0 auto;
    box-shadow: 0 0 14px var(--gold-glow);
}

.timeline-card {
    padding: 22px 24px;
}

.timeline-card h4 {
    margin-bottom: 6px;
    font-size: 1rem;
}

.timeline-era {
    display: block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 8px;
}

.timeline-card p {
    margin: 0;
    font-size: 0.9rem;
}

.timeline-row:nth-child(odd) .timeline-card {
    grid-column: 1;
}

.timeline-row:nth-child(even) .timeline-card {
    grid-column: 3;
}

@media (max-width: 720px) {
    .timeline::before {
        left: 8px;
    }

    .timeline-row {
        grid-template-columns: 24px 1fr;
        gap: 12px;
    }

    .timeline-marker {
        grid-column: 1;
        margin: 0;
    }

    .timeline-row:nth-child(odd) .timeline-card,
    .timeline-row:nth-child(even) .timeline-card {
        grid-column: 2;
    }
}

/* Two pillars */
.pillars-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 22px;
}

.pillar-card {
    padding: 36px 32px;
    text-align: center;
}

.pillar-char {
    font-family: 'Noto Serif SC', serif;
    font-size: 5rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 8px;
    color: var(--gold);
}

.pillar-card h3 {
    margin-bottom: 10px;
}

.pillar-card p {
    margin: 0 0 6px;
    font-size: 0.95rem;
}

.pillars-tagline {
    text-align: center;
    margin-top: 28px;
    font-family: 'Space Grotesk', sans-serif;
    font-style: italic;
    color: var(--gold);
    font-size: 1.05rem;
}

@media (max-width: 720px) {
    .pillars-grid {
        grid-template-columns: 1fr;
    }
}

/* Three talents / four philosophies */
.talents-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 18px;
}

.philosophies-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
}

.talent-card,
.philosophy-card {
    padding: 28px;
    text-align: center;
}

.talent-emoji,
.philosophy-emoji {
    font-size: 2rem;
    margin-bottom: 12px;
}

.talent-card h4,
.philosophy-card h4 {
    margin-bottom: 6px;
    font-size: 1rem;
}

.talent-card .pinyin-sub,
.philosophy-card .pinyin-sub {
    display: block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 10px;
}

.talent-card p,
.philosophy-card p {
    margin: 0;
    font-size: 0.88rem;
}

.talents-example {
    margin-top: 24px;
    padding: 18px 24px;
    text-align: center;
    border-left: 2px solid var(--gold);
    background: var(--gold-soft);
    border-radius: 0 12px 12px 0;
    color: var(--text-secondary);
    font-style: italic;
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
}

@media (max-width: 880px) {
    .talents-grid,
    .philosophies-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 520px) {
    .talents-grid,
    .philosophies-grid {
        grid-template-columns: 1fr;
    }
}

/* Ba Men table */
.bamen-table-wrap {
    padding: 8px;
    overflow-x: auto;
}

.bamen-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}

.bamen-table th,
.bamen-table td {
    padding: 14px 16px;
    text-align: left;
    border-bottom: 1px solid var(--border-subtle);
}

.bamen-table th {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-muted);
    font-weight: 500;
    background: rgba(0, 0, 0, 0.03);
}

.bamen-table tbody tr {
    transition: background var(--fast) var(--ease);
}

.bamen-table tbody tr:hover {
    background: var(--gold-soft);
}

.bamen-table .pinyin-cell {
    font-weight: 600;
    color: var(--text-primary);
}

.bamen-table .char-cell {
    font-family: 'Noto Serif SC', serif;
    font-size: 1.3rem;
    color: var(--gold);
}

.bamen-table .auspicious {
    color: var(--success);
    font-weight: 600;
}

.bamen-table .neutral {
    color: var(--text-muted);
    font-weight: 600;
}

.bamen-table .inauspicious {
    color: var(--danger);
    font-weight: 600;
}

/* 3x3 Paipan mock */
.paipan-mock {
    max-width: 540px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.paipan-cell {
    position: relative;
    aspect-ratio: 1;
    padding: 18px;
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    cursor: help;
    transition: all var(--fast) var(--ease);
}

.paipan-cell:hover {
    border-color: var(--gold);
    background: var(--gold-soft);
    transform: scale(1.03);
}

.paipan-cell .gong-name {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.paipan-cell .gong-content {
    font-family: 'Noto Serif SC', serif;
    font-size: 1.1rem;
    color: var(--text-primary);
    font-weight: 600;
}

.paipan-cell .gong-tooltip {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--bg-elevated);
    border: 1px solid var(--gold);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 0.78rem;
    color: var(--text-primary);
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--fast) var(--ease);
    z-index: 10;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}

.paipan-cell:hover .gong-tooltip {
    opacity: 1;
}

/* Modern applications */
.apps-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
}

.app-card {
    padding: 28px 22px;
    transition: transform var(--med) var(--ease), border-color var(--med) var(--ease);
}

.app-card:hover {
    transform: translateY(-3px);
    border-color: var(--blue);
}

.app-card h4 {
    margin-bottom: 8px;
    font-size: 1rem;
}

.app-card p {
    margin: 0;
    font-size: 0.88rem;
}

.app-emoji {
    font-size: 1.8rem;
    margin-bottom: 10px;
    display: inline-block;
}

@media (max-width: 880px) {
    .apps-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .apps-grid {
        grid-template-columns: 1fr;
    }
}

/* Qimen × AI comparison */
.fusion-intro {
    max-width: 720px;
    margin: 0 auto 36px;
    text-align: center;
    font-size: 1.02rem;
}

.fusion-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.94rem;
}

.fusion-table th {
    padding: 18px 20px;
    text-align: left;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1rem;
    font-weight: 600;
    border-bottom: 1px solid var(--border-strong);
}

.fusion-table th:nth-child(2) { color: var(--gold); }
.fusion-table th:nth-child(3) { color: var(--blue); }

.fusion-table td {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: top;
}

.fusion-table td:first-child {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    width: 200px;
}

.fusion-cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 18px;
    margin-top: 32px;
}

.fusion-card {
    padding: 28px;
}

.fusion-card h4 {
    margin-bottom: 8px;
}

.fusion-card p {
    margin: 0;
    font-size: 0.92rem;
}

.fusion-closing {
    margin-top: 56px;
    padding: 36px 24px;
    text-align: center;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.4rem;
    font-style: italic;
    line-height: 1.4;
    color: var(--text-primary);
    background: linear-gradient(135deg, var(--gold-soft), var(--blue-soft));
    border-top: 1px solid var(--gold-soft);
    border-bottom: 1px solid var(--blue-soft);
}

@media (max-width: 720px) {
    .fusion-cards {
        grid-template-columns: 1fr;
    }

    .fusion-table td:first-child {
        width: auto;
    }
}

/* Closing CTA band */
.cta-band {
    padding: 56px 40px;
    text-align: center;
    background:
        radial-gradient(600px 240px at 50% 50%, var(--gold-soft), transparent 70%),
        var(--bg-glass);
    border: 1px solid var(--gold-soft);
}

.cta-band h2 {
    margin-bottom: 12px;
}

.cta-band p {
    max-width: 580px;
    margin: 0 auto 24px;
    font-size: 1.02rem;
}

.cta-buttons {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 12px;
    justify-content: center;
}

/* ============================================================
   Page: Subscription (subscription.html)
   ============================================================ */

.pricing-hero {
    padding: 80px 0 32px;
    text-align: center;
}

.pricing-hero h1 {
    margin-bottom: 14px;
}

.pricing-hero .lede {
    font-size: 1.1rem;
    max-width: 600px;
    margin: 0 auto 32px;
}

.billing-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px;
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-pill);
    margin: 0 auto;
}

.billing-toggle button {
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 500;
    padding: 9px 20px;
    border-radius: var(--r-pill);
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all var(--fast) var(--ease);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.billing-toggle button.is-active {
    background: var(--gold);
    color: #1A140A;
    font-weight: 600;
    box-shadow: 0 4px 14px var(--gold-glow);
}

.billing-toggle .save-badge {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    background: var(--success);
    color: #07150C;
    padding: 2px 6px;
    border-radius: var(--r-pill);
    font-weight: 600;
}

.pricing-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 22px;
    padding: 32px 0 64px;
}

.pricing-card {
    padding: 36px 30px;
    display: flex;
    flex-direction: column;
    position: relative;
    transition: transform var(--med) var(--ease);
}

.pricing-card:hover {
    transform: translateY(-4px);
}

.pricing-card.is-recommended {
    border-color: var(--gold);
    box-shadow: 0 0 0 1px var(--gold), 0 12px 36px var(--gold-glow);
}

.pricing-ribbon {
    position: absolute;
    top: -12px;
    left: 50%;
    transform: translateX(-50%);
    padding: 6px 16px;
    background: linear-gradient(135deg, var(--gold), var(--gold-bright));
    color: #1A140A;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    border-radius: var(--r-pill);
    box-shadow: 0 4px 14px var(--gold-glow);
    white-space: nowrap;
}

.tier-name {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.tier-title {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.65rem;
    font-weight: 600;
    margin-bottom: 6px;
}

.tier-tagline {
    color: var(--text-secondary);
    font-size: 0.92rem;
    margin-bottom: 24px;
    min-height: 44px;
}

.tier-price {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-bottom: 4px;
}

.tier-price .currency {
    font-size: 1.4rem;
    color: var(--text-secondary);
    font-weight: 600;
}

.tier-price .amount {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 3.25rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--text-primary);
    transition: opacity var(--med) var(--ease);
}

.tier-price .period {
    font-size: 0.95rem;
    color: var(--text-muted);
}

.tier-billed-note {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-bottom: 24px;
    min-height: 18px;
}

.tier-features {
    list-style: none;
    padding: 0;
    margin: 0 0 28px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 1;
}

.tier-features li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 0.92rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

.tier-features .check {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--gold-soft);
    color: var(--gold);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.7rem;
    font-weight: 700;
    margin-top: 2px;
}

.pricing-card.is-recommended .tier-features .check {
    background: var(--gold);
    color: #1A140A;
}

/* ---- Credit-based plan cards (4-up) ---- */
.pricing-grid--4 {
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
}

.pricing-grid--4 .pricing-card { padding: 40px 22px 28px; }   /* extra top room for the per-month bubble */
.pricing-grid--4 .tier-title { font-size: 1.45rem; margin-bottom: 2px; }
.pricing-grid--4 .tier-tagline { min-height: 56px; font-size: 0.86rem; margin-bottom: 18px; }
.pricing-grid--4 .tier-price .amount { font-size: 2.3rem; }
.pricing-grid--4 .tier-price .period { font-size: 0.8rem; }
.pricing-grid--4 .pricing-card .btn { margin-top: auto; }   /* pin CTA to the bottom */

.plan-cadence {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 14px;
}

.plan-questions {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--gold);
    line-height: 1;
    margin-bottom: 8px;
}

.plan-questions span {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.tier-renewal-note {
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin-top: 4px;
}

.tier-renewal-note strong { color: var(--text-primary); }

.per-q-note {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    color: var(--text-muted);
    margin: 4px 0 20px;
}

/* Per-month value bubble — top-right of Half-Yearly & Yearly cards */
.plan-bubble {
    position: absolute;
    top: 12px;
    right: 14px;
    padding: 4px 10px;
    background: var(--gold-soft);
    border: 1px solid var(--gold-soft);
    border-radius: 999px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--gold);
    white-space: nowrap;
}

/* On the featured card, drop the bubble below the centred "Best Value" ribbon */
.pricing-card.is-recommended .plan-bubble {
    top: 20px;
}

/* ---- Centered section head ---- */
.section-head--center {
    text-align: center;
    margin: 8px auto 24px;
    max-width: 620px;
}

/* ---- Free-trial strip ---- */
.free-trial-strip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 18px 26px;
    margin: 8px 0 12px;
    flex-wrap: wrap;
}

.free-trial-text {
    display: flex;
    align-items: center;
    gap: 16px;
}

.free-trial-badge {
    flex-shrink: 0;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: #07150C;
    background: var(--success);
    padding: 5px 12px;
    border-radius: var(--r-pill);
}

.free-trial-text strong { display: block; }

.free-trial-sub {
    font-size: 0.85rem;
    color: var(--text-secondary);
}

/* ---- Every-plan-includes strip ---- */
.includes-strip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 28px;
    padding: 22px 26px;
    margin: 8px 0 8px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-lg);
}

.includes-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.includes-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 10px 24px;
    flex: 1;
}

.includes-list li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.88rem;
    color: var(--text-secondary);
}

/* ---- One-time pack band ---- */
.onetime-band {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 28px;
    padding: 28px 32px;
    margin: 40px 0 8px;
    border-color: var(--blue-soft);
    flex-wrap: wrap;
}

.onetime-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.onetime-tag {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--text-primary);
}

.onetime-questions {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.8rem;
    color: var(--blue);
}

.onetime-info p {
    color: var(--text-secondary);
    font-size: 0.92rem;
    max-width: 440px;
    margin: 0;
}

.onetime-buy {
    display: flex;
    align-items: center;
    gap: 22px;
}

.onetime-buy .tier-price { margin-bottom: 0; }
.onetime-buy .tier-price .amount { font-size: 2.4rem; }

/* ---- Top-ups ---- */
.topup-head { margin-top: 48px; }

.topup-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 18px;
    max-width: 560px;
    margin: 0 auto;
}

.topup-card {
    padding: 26px 24px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

.topup-q {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--gold);
    line-height: 1;
}

.topup-q span {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.topup-validity {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-bottom: 8px;
}

.topup-card .tier-price { margin: 4px 0 16px; }
.topup-card .tier-price .amount { font-size: 2rem; }

/* ---- Compare table footnote ---- */
.compare-foot {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin-top: 16px;
    text-align: center;
}

@media (max-width: 1080px) {
    .pricing-grid--4 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 900px) {
    .pricing-grid {
        grid-template-columns: 1fr;
        max-width: 460px;
        margin: 0 auto;
    }
}

@media (max-width: 600px) {
    .pricing-grid--4 {
        grid-template-columns: 1fr;
        max-width: 420px;
        margin: 0 auto;
    }
    .topup-row { grid-template-columns: 1fr; max-width: 360px; }
    .onetime-band, .free-trial-strip { flex-direction: column; align-items: flex-start; }
    .onetime-buy { width: 100%; justify-content: space-between; }
}

/* Comparison table accordion */
.compare-section {
    padding: 32px 0 64px;
}

.compare-toggle {
    width: 100%;
    text-align: left;
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: 18px 22px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: all var(--fast) var(--ease);
}

.compare-toggle:hover {
    border-color: var(--gold);
    color: var(--gold);
}

.compare-toggle .toggle-icon {
    transition: transform var(--med) var(--ease);
}

.compare-toggle[aria-expanded="true"] .toggle-icon {
    transform: rotate(180deg);
}

.compare-content {
    overflow: hidden;
    max-height: 0;
    transition: max-height var(--slow) var(--ease);
}

.compare-content.is-open {
    max-height: 1400px;
}

.compare-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 16px;
    font-size: 0.92rem;
}

.compare-table th,
.compare-table td {
    padding: 14px 16px;
    text-align: center;
    border-bottom: 1px solid var(--border-subtle);
}

.compare-table th {
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 600;
    color: var(--text-primary);
    background: var(--bg-glass);
}

.compare-table th:first-child,
.compare-table td:first-child {
    text-align: left;
    color: var(--text-secondary);
}

.compare-table .yes {
    color: var(--success);
    font-weight: 600;
}

.compare-table .no {
    color: var(--text-muted);
}

.compare-table .highlight-col {
    background: var(--gold-soft);
    color: var(--gold);
}

/* FAQ */
.faq-section {
    padding: 32px 0 96px;
}

.faq-list {
    max-width: 720px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.faq-item {
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    overflow: hidden;
}

.faq-question {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    padding: 18px 22px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.98rem;
    font-weight: 500;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
}

.faq-question:hover {
    color: var(--gold);
}

.faq-question .toggle-icon {
    flex-shrink: 0;
    transition: transform var(--med) var(--ease);
    color: var(--gold);
}

.faq-item.is-open .faq-question .toggle-icon {
    transform: rotate(45deg);
}

/* Animates to the answer's ACTUAL height via 0fr → 1fr, rather than to a
   fixed max-height. The old `max-height: 320px` was written for one-line
   answers and silently CLIPPED the longer ones on the Dashboard's "How to
   ask" FAQ (its "keep a copy" answer is ~425px on a phone). Raising the
   magic number would only move the problem — and a too-large max-height
   makes the collapse animation start with a dead pause. */
.faq-answer {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--med) var(--ease);
}

.faq-item.is-open .faq-answer {
    grid-template-rows: 1fr;
}

/* The grid child does the clipping; min-height:0 lets it shrink below its
   content size, which grid items otherwise refuse to do. */
.faq-answer > .faq-answer-inner {
    overflow: hidden;
    min-height: 0;
}

.faq-answer-inner {
    /* Vertical padding is applied ONLY when open. On a 0fr grid row the row
       collapses to zero but padding still occupies space, so keeping it here
       unconditionally left ~18px of dead gap under every closed question. */
    padding: 0 22px;
    color: var(--text-secondary);
    font-size: 0.92rem;
    line-height: 1.6;
}

.faq-item.is-open .faq-answer-inner {
    padding-bottom: 18px;
}

/* Answers were plain text until the Dashboard's "How to ask" FAQ, which
   uses paragraphs, lists and a worked example. */
.faq-answer-inner p { margin: 0 0 10px; }
.faq-answer-inner p:last-child { margin-bottom: 0; }

.faq-answer-inner ul {
    margin: 0;
    padding-left: 18px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.faq-answer-inner strong { color: var(--text-primary); font-weight: 600; }

.faq-answer-inner a {
    color: var(--gold);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* The copy-paste question template — set apart so it reads as a specimen
   rather than more prose. */
.faq-example {
    margin: 12px 0 0 !important;
    padding: 10px 14px;
    border-left: 2px solid var(--gold);
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    background: var(--gold-soft);
    color: var(--text-primary);
    font-style: italic;
}

/* ---- Wu Xing colour legend (Dashboard FAQ) ----
   Swatch and element name are painted from the SAME --wx-* tokens the chart
   uses (via the --wx indirection, matching .paipan-terminal .wx-*), so the
   legend cannot drift from the Paipan when a hue is retuned. */
.wx-legend {
    margin: 12px 0 14px;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.wx-legend-row {
    display: grid;
    grid-template-columns: 14px minmax(76px, auto) 1fr;
    align-items: baseline;
    gap: 10px;
}

.wx-legend .wx-wood  { --wx: var(--wx-wood); }
.wx-legend .wx-fire  { --wx: var(--wx-fire); }
.wx-legend .wx-earth { --wx: var(--wx-earth); }
.wx-legend .wx-metal { --wx: var(--wx-metal); }
.wx-legend .wx-water { --wx: var(--wx-water); }

.wx-swatch {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--wx);
    align-self: center;
    flex: none;
}

.wx-name {
    color: var(--wx);
    font-weight: 600;
}

.wx-name .zh {
    font-family: 'Noto Serif SC', serif;
    margin-right: 3px;
}

.wx-terms {
    color: var(--text-secondary);
    font-size: 0.9em;
}

@media (max-width: 480px) {
    /* Stack the descriptor under the element name so neither is squeezed. */
    .wx-legend-row {
        grid-template-columns: 14px 1fr;
        row-gap: 2px;
    }
    .wx-terms { grid-column: 2; }
}

/* ---- Legal long-form pages (privacy.html) ---- */
.legal-doc {
    padding-top: 72px;
    padding-bottom: 96px;
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.75;
}

.legal-doc h3 {
    margin: 34px 0 10px;
    font-size: 1.05rem;
    color: var(--text-primary);
}

.legal-doc h3:first-of-type { margin-top: 8px; }

.legal-doc p { margin: 0 0 14px; }

.legal-doc strong { color: var(--text-primary); font-weight: 600; }

/* Inline links in prose follow the FAQ convention (gold + underline), not the
   global --blue, which reads as a UI control rather than body text. */
.legal-doc a {
    color: var(--gold);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* The reset strips list markers globally; legal prose needs them back. */
.legal-doc ul {
    margin: 0 0 14px;
    padding-left: 22px;
    list-style: disc;
}

.legal-doc li {
    margin-bottom: 6px;
}

/* Credit/validity table. Wrapper scrolls on its own so a narrow phone never
   makes the whole page scroll sideways. */
.legal-table-wrap {
    overflow-x: auto;
    margin: 0 0 18px;
}

.legal-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.legal-table th,
.legal-table td {
    padding: 10px 12px 10px 0;
    text-align: left;
    border-bottom: 1px solid var(--border-subtle);
}

/* Only the validity column is protected from wrapping. Letting the credits
   column wrap keeps "Valid for" on screen at narrow widths — it's the most
   consequential term here, so it must never be the bit that scrolls away. */
.legal-table th:last-child,
.legal-table td:last-child {
    white-space: nowrap;
    padding-right: 0;
}

.legal-table th {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    border-bottom-color: var(--border-strong);
}

.legal-table td:first-child { color: var(--text-primary); font-weight: 500; }

.legal-updated {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.74rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px !important;
}

/* Pulled out of the prose — the one paragraph a reader must not skim past */
.legal-callout {
    margin: 18px 0 !important;
    padding: 14px 18px;
    border-left: 2px solid var(--gold);
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    background: var(--gold-soft);
    color: var(--text-primary);
}

/* Optional lede under a .section-head heading */
.section-sub {
    max-width: 560px;
    margin: 10px auto 0;
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.6;
}

/* "How to ask" hook inside the chat header — the guidance itself sits
   below the fold while the chat panel is sticky. */
.chat-howto-link {
    margin-left: auto;
    flex: 0 0 auto;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text-muted);
    text-decoration: none;
    white-space: nowrap;
    padding: 4px 8px;
    border-radius: var(--r-pill);
    transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.chat-howto-link:hover {
    color: var(--gold);
    background: var(--gold-soft);
}

/* "Save as PDF" — opens the print dialog (see wirePdfExport in chat.js) */
.chat-pdf-btn {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-subtle);
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease),
                background var(--fast) var(--ease);
}

.chat-pdf-btn:hover {
    color: var(--gold);
    border-color: var(--gold);
    background: var(--gold-soft);
}

/* The chat header runs out of room on a phone: avatar + title + "How to
   ask" + PDF + expand crushed the title to ~46px wide and 172px tall.
   Drop the two least-needed pieces there — on mobile the how-to-ask FAQ
   sits directly beneath the chat anyway, so the link earns its place only
   on desktop, where the sticky panel hides the FAQ below the fold. */
@media (max-width: 560px) {
    .chat-howto-link { display: none; }
    .chat-header .subtitle { display: none; }
}

/* Masthead shown ONLY in the printed keepsake */
.print-masthead { display: none; }

/* ============================================================
   Page: Shop (shop.html)
   ============================================================ */

.shop-hero {
    padding: 80px 0 32px;
    text-align: center;
}

.shop-hero .lede {
    font-size: 1.05rem;
    max-width: 580px;
    margin: 0 auto;
}

.shop-section {
    padding: 32px 0 56px;
}

.shop-section-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 28px;
    gap: 24px;
    flex-wrap: wrap;
}

.shop-section-head h2 {
    margin: 0;
}

.shop-section-head p {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.92rem;
}

.shop-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
}

.product-card,
.service-card {
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: all var(--med) var(--ease);
}

.product-card:hover,
.service-card:hover {
    transform: translateY(-4px);
    border-color: var(--gold);
    box-shadow: 0 16px 36px rgba(0, 0, 0, 0.10), 0 0 0 1px var(--gold-soft);
}

.product-image {
    position: relative;
    aspect-ratio: 4 / 3;
    background:
        radial-gradient(circle at 50% 45%, rgba(212, 175, 55, 0.18), transparent 65%),
        linear-gradient(135deg, var(--bg-elevated), var(--bg-deep));
    display: flex;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid var(--border-subtle);
    overflow: hidden;
}

.product-image .icon-large {
    font-family: 'Noto Serif SC', serif;
    font-size: 4.5rem;
    font-weight: 700;
    color: var(--gold);
    line-height: 1;
}

.product-image .icon-large.blue {
    color: var(--blue);
    text-shadow: 0 0 32px var(--blue-glow);
}

.product-body {
    padding: 22px;
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 8px;
}

.product-body h4 {
    margin: 0;
    font-size: 1.05rem;
}

.product-body .product-desc {
    margin: 0;
    font-size: 0.88rem;
    color: var(--text-secondary);
    flex: 1;
}

.product-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-top: 8px;
}

.product-price {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--gold);
}

.product-action {
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    padding: 9px 16px;
    border-radius: var(--r-pill);
    border: 1px solid var(--gold);
    background: var(--gold-soft);
    color: var(--gold);
    cursor: pointer;
    transition: all var(--fast) var(--ease);
}

.product-action:hover {
    background: var(--gold);
    color: #1A140A;
    box-shadow: 0 0 14px var(--gold-glow);
}

.service-card .product-action {
    border-color: var(--blue);
    background: var(--blue-soft);
    color: var(--blue);
    width: 100%;
}

.service-card .product-action:hover {
    background: var(--blue);
    color: #07111E;
    box-shadow: 0 0 14px var(--blue-glow);
}

/* Floating cart button */
.cart-fab {
    position: fixed;
    top: 96px;
    right: 24px;
    z-index: 40;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    background: var(--bg-elevated);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    transition: all var(--fast) var(--ease);
}

.cart-fab.has-items {
    border-color: var(--gold);
    color: var(--gold);
    box-shadow: 0 6px 20px var(--gold-glow), 0 8px 24px rgba(0, 0, 0, 0.10);
}

.cart-fab:hover {
    transform: scale(1.06);
}

.cart-count {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border-radius: 10px;
    background: var(--gold);
    color: #1A140A;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    font-weight: 700;
    display: none;
    align-items: center;
    justify-content: center;
}

.cart-fab.has-items .cart-count {
    display: flex;
}

/* Cart drawer */
.cart-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    z-index: 60;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--med) var(--ease);
}

.cart-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
}

.cart-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 420px;
    max-width: 100%;
    background: var(--bg-elevated);
    border-left: 1px solid var(--border-strong);
    z-index: 70;
    transform: translateX(100%);
    transition: transform var(--slow) var(--ease-out);
    display: flex;
    flex-direction: column;
    box-shadow: -20px 0 50px rgba(0, 0, 0, 0.14);
}

.cart-drawer.is-open {
    transform: translateX(0);
}

.cart-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 22px 24px;
    border-bottom: 1px solid var(--border-subtle);
}

.cart-head h3 {
    margin: 0;
}

.cart-close {
    background: transparent;
    border: 0;
    color: var(--text-secondary);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    transition: all var(--fast) var(--ease);
}

.cart-close:hover {
    color: var(--gold);
    background: var(--bg-glass);
}

.cart-items {
    flex: 1;
    overflow-y: auto;
    padding: 16px 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.cart-empty {
    text-align: center;
    color: var(--text-muted);
    padding: 60px 24px;
    font-size: 0.92rem;
}

.cart-empty .empty-icon {
    font-size: 2.5rem;
    color: var(--gold);
    opacity: 0.5;
    margin-bottom: 12px;
}

.cart-item {
    display: grid;
    grid-template-columns: 56px 1fr auto;
    gap: 14px;
    padding: 14px;
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    align-items: center;
}

.cart-item-thumb {
    width: 56px;
    height: 56px;
    border-radius: 10px;
    background:
        radial-gradient(circle at 50% 50%, var(--gold-soft), transparent 70%),
        var(--bg-deep);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--gold);
    font-family: 'Noto Serif SC', serif;
    font-weight: 700;
    font-size: 1.4rem;
}

.cart-item-info h5 {
    margin: 0 0 4px;
    font-size: 0.92rem;
}

.cart-item-info .price {
    margin: 0;
    font-size: 0.82rem;
    color: var(--text-muted);
}

.cart-item-qty {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--bg-deep);
    border-radius: var(--r-pill);
    padding: 2px;
}

.qty-btn {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    transition: all var(--fast) var(--ease);
}

.qty-btn:hover {
    background: var(--gold-soft);
    color: var(--gold);
}

.qty-val {
    min-width: 22px;
    text-align: center;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.82rem;
    color: var(--text-primary);
    font-weight: 600;
}

.cart-foot {
    border-top: 1px solid var(--border-subtle);
    padding: 22px 24px;
    background: rgba(0, 0, 0, 0.02);
}

.cart-subtotal {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 16px;
}

.cart-subtotal .label {
    color: var(--text-secondary);
    font-size: 0.95rem;
}

.cart-subtotal .value {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--gold);
}

/* Modal — booking + checkout confirmation */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(6px);
    z-index: 80;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
    opacity: 0;
    transition: opacity var(--med) var(--ease);
}

.modal-backdrop.is-open {
    display: flex;
    opacity: 1;
}

.modal {
    width: 100%;
    max-width: 480px;
    padding: 32px;
    background: var(--bg-elevated);
    border: 1px solid var(--gold-soft);
    border-radius: var(--r-lg);
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.18);
    transform: scale(0.95);
    transition: transform var(--med) var(--ease-out);
}

.modal-backdrop.is-open .modal {
    transform: scale(1);
}

.modal h3 {
    margin-bottom: 8px;
}

.modal-subtitle {
    color: var(--text-secondary);
    margin-bottom: 22px;
    font-size: 0.92rem;
}

.modal-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.modal-field label {
    display: block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.modal-field input,
.modal-field textarea {
    width: 100%;
    background: var(--bg-deep);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: 12px 14px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.92rem;
    transition: border-color var(--fast) var(--ease);
}

.modal-field input:focus,
.modal-field textarea:focus {
    outline: none;
    border-color: var(--gold);
    box-shadow: 0 0 0 3px var(--gold-soft);
}

.modal-field textarea {
    resize: vertical;
    min-height: 80px;
}

.modal-actions {
    display: flex;
    gap: 10px;
    margin-top: 8px;
    justify-content: flex-end;
}

.modal-success {
    text-align: center;
    padding: 20px 0;
}

.modal-success .success-icon {
    width: 60px;
    height: 60px;
    margin: 0 auto 16px;
    border-radius: 50%;
    background: rgba(46, 204, 113, 0.15);
    border: 1px solid var(--success);
    color: var(--success);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.8rem;
}

@media (max-width: 480px) {
    .cart-fab {
        top: auto;
        bottom: 24px;
        right: 16px;
    }
}

/* ============================================================
   Theme Toggle button (in nav) + Dark-theme hardcoded overrides
   ============================================================ */

.theme-toggle {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: var(--r-pill);
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all var(--fast) var(--ease);
}

.theme-toggle:hover {
    color: var(--gold);
    border-color: var(--gold);
    background: var(--gold-soft);
}

/* Icon swap: moon shown in light mode (click → dark), sun in dark mode */
body:not(.dark-theme) .theme-toggle .icon-sun { display: none; }
body.dark-theme .theme-toggle .icon-moon { display: none; }

/* --- Dark overrides for values hardcoded during the light-theme pass --- */
body.dark-theme .site-footer {
    background: var(--bg-elevated);
}

/* Phone detail sheet on dark. The neon element inks now come from
   body.dark-theme itself, so only the shadow needs overriding here. */
body.dark-theme .palace-sheet {
    box-shadow: 0 -12px 44px rgba(0, 0, 0, 0.55);
}
body.dark-theme .palace-sheet-backdrop { background: rgba(2, 5, 10, 0.62); }

/* Hero painting becomes a moodier, darker "ink wash" version: a gentle
   indigo veil over the whole image (keeps silver text legible), deepening
   to fully dissolve into the indigo background at the bottom. */
/* 80% transparent indigo nav so the dark painting shows through */
body.dark-theme .site-nav {
    background: rgba(21, 30, 45, 0.2);
}

body.dark-theme .hero-ink-wrapper {
    background-image:
        linear-gradient(to bottom,
            rgba(11, 17, 26, 0.45) 0%,
            rgba(11, 17, 26, 0.42) 45%,
            rgba(11, 17, 26, 0.85) 85%,
            var(--bg-base) 100%),
        url('../Ink Splash sansui dark.png');
}

/* Subtle hero text halo flips dark so charcoal→silver text stays legible */
body.dark-theme .hero-content .hero-band-text h1,
body.dark-theme .hero-content .hero-band-text p {
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

body.dark-theme .chat-bubble--ai pre {
    background: #0E1622;
}

body.dark-theme .chat-bubble--ai code {
    color: var(--gold-bright);
}

body.dark-theme .chat-lock {
    background: rgba(11, 17, 26, 0.82);
}

body.dark-theme .lo-shu-grid div {
    background: #0E1622;
}

/* Faint separator washes were dark-on-light; flip to light-on-dark */
body.dark-theme .terminal-header,
body.dark-theme .chat-input-wrap,
body.dark-theme .chat-bubble--ai th,
body.dark-theme .bamen-table th,
body.dark-theme .cart-foot {
    background: rgba(255, 255, 255, 0.04);
}

/* Dark-mode Paipan — the full "Neon Circuit": the light "Day Circuit"
   base flips to a deep dark panel with silver inks, pure neon Wu Xing,
   strong glow halos, and full-neon cyan rings. Every consumer reads
   these scoped vars, so this one block re-themes the whole chart. */
body.dark-theme .paipan-terminal {
    background: radial-gradient(ellipse at 50% 30%,
        #10162A 0%, #0A0E1C 55%, #05070F 100%);
    --text-primary: #E8ECF4;
    --text-secondary: rgba(232, 236, 244, 0.65);
    --text-muted: rgba(232, 236, 244, 0.45);
    --border-subtle: rgba(232, 236, 244, 0.12);
    --ink-strong: #E8ECF4;
    --ink-soft: rgba(232, 236, 244, 0.55);
    /* Pure neon Wu Xing is inherited from body.dark-theme — not re-declared
       here, so the chart and the FAQ legend can never disagree. */
    /* Full-neon chrome: cyan ring + silver halos. (The neon wx text glow
       lives in explicit body.dark-theme rules next to the base wx rules —
       see the note there about per-element --wx resolution.) */
    --ring-hue: #00ffff;
    --ink-glow: 0 0 8px rgba(232, 236, 244, 0.3);
    --ink-glow-soft: 0 0 6px rgba(232, 236, 244, 0.2);
    --tag-bg: rgba(5, 10, 20, 0.8);
    /* Bagua trigram watermark ink — faint silver on the dark panel */
    --trigram-ink: rgba(255, 255, 255, 0.15);
}

body.dark-theme .terminal-header {
    background: rgba(255, 255, 255, 0.03);
}

body.dark-theme .time-control {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.14);
}

body.dark-theme .time-input {
    color-scheme: dark;
}

body.dark-theme .time-input::-webkit-calendar-picker-indicator {
    filter: invert(1);
}

/* ============================================================
   PRINT — the "Save as PDF" keepsake (Dashboard)

   Deliberately uses the browser's own renderer rather than an
   html2canvas screenshot: the Paipan depends on container-query ring
   sizing, color-mix() inks, mix-blend-mode and ::before rings, which
   html2canvas renders badly. Letting the browser draw it makes the
   chart pixel-accurate for free.

   chat.js (wirePdfExport) handles the four things CSS cannot: expanding
   the collapsed deduction, dropping dark-theme, setting the filename via
   document.title, and stamping the masthead.
   ============================================================ */
@media print {
    /* ---- Chrome that has no place on paper ---- */
    .site-nav,
    .nav-peek-zone,
    .nav-reveal-fab,
    .back-to-top,
    .etym-modal-backdrop,
    .hero-ink-wrapper,
    .faq-section,
    .site-footer,
    .chat-input-wrap,
    .chat-lock,
    .chat-backdrop,
    .chat-expand-btn,
    .chat-howto-link,
    .chat-pdf-btn,
    .chat-jump,
    .reply-fold-toggle,
    .time-control,
    .terminal-icon-btn,
    .theme-toggle,
    .paipan-hint,
    .palace-sheet,
    .palace-sheet-backdrop {
        display: none !important;
    }

    /* ---- The keepsake masthead ---- */
    .print-masthead {
        display: block;
        margin-bottom: 18px;
        padding-bottom: 12px;
        border-bottom: 1px solid #ddd;
    }
    .print-brand {
        font-family: 'Noto Serif SC', serif;
        font-size: 1.3rem;
        font-weight: 700;
        color: #1A1B20;
    }
    .print-meta {
        font-family: 'Space Grotesk', sans-serif;
        font-size: 0.72rem;
        color: #666;
        margin-top: 2px;
    }
    .print-disclaimer {
        margin: 8px 0 0;
        font-size: 0.68rem;
        line-height: 1.4;
        color: #777;
    }

    /* ---- Unclip every scroll container ----
       .chat-messages and the Paipan stage are fixed-height scroll boxes.
       Printed as-is, ONLY the visible slice reaches the page and the rest
       of the reading is silently lost. This is the single most important
       rule in this block. */
    .chat-panel,
    .chat-messages,
    .terminal-iframe-wrap,
    #paipan-container,
    .app-container,
    .paipan-terminal {
        position: static !important;
        overflow: visible !important;
        height: auto !important;
        max-height: none !important;
        min-height: 0 !important;
    }

    /* Chart and transcript stack down the page instead of side by side */
    .dashboard-grid {
        display: block !important;
    }

    .paipan-terminal { margin-bottom: 20px; }

    /* Keep the chart legible on paper */
    .paipan-grid {
        min-height: 0 !important;
        aspect-ratio: 1 / 1;
        max-width: 165mm;
        margin: 0 auto;
    }

    /* The deduction is collapsed on screen — force it open so the PDF
       carries the whole reading (chat.js does this too; belt and braces) */
    .reply-fold { display: block !important; }

    /* ---- Colour fidelity ----
       Browsers drop background images and colours when printing unless
       asked. Without this the Tai Chi watermark and the panel tone vanish
       and the chart prints washed out. */
    .paipan-terminal,
    .paipan-grid,
    .paipan-grid::before,
    .palace-disc,
    .paipan-core,
    .chat-bubble,
    .chat-bubble--ai,
    .chat-bubble--user,
    .faq-example {
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
    }

    /* Freeze the rotating Tai Chi and swinging stems so the chart prints
       at a deterministic position rather than mid-animation */
    *,
    *::before,
    *::after {
        animation: none !important;
        transition: none !important;
    }

    /* The blanket hide above drops .faq-section — correct on ask.html, where a
       printed reading shouldn't carry the FAQ. But on faq.html the FAQ IS the
       page, so without this it would print a blank sheet. */
    .faq-page .faq-section {
        display: block !important;
    }

    /* ---- Pagination ---- */
    @page { margin: 15mm; }

    body {
        background: #fff !important;
        color: #1A1B20 !important;
    }

    .chat-bubble,
    .paipan-terminal,
    .palace-disc {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    /* Bubbles read as a transcript on paper, not chat UI */
    .chat-bubble {
        max-width: 100% !important;
        box-shadow: none !important;
    }

    .chat-panel,
    .paipan-terminal {
        border: 1px solid #e5e5e5 !important;
        box-shadow: none !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
    }
}
