/* ============================================================
   CODEX OF THE RIFTBORN — GRIMOIRE TREATMENT
   ------------------------------------------------------------
   Layered on top of style.css + book.css.  Adds:

     - Theme tokens (--cdx-*) on body.codex-theme-grimoire-dark/light
     - Leather frame chrome around #codex-app (.codex-frame*)
     - Page-edge stripe stacks + spine seam with Enochian glyph
     - Floating .codex-toolbar overlay (.codex-tb-*)
     - .codex-drawer slide-out (Contents / Bookmarks / Notes)
     - .codex-reading-panel + .codex-theme-panel popovers
     - .codex-tooltip-card hover/long-press for [data-related] refs
     - Mobile-portrait single-page layout below 1024px

   Does NOT touch:
     - The existing 3-D book-flip transitions in book.css/book.js
     - Cover → TOC → Chapter → Entry view structure
     - The mature-tier age-gate modal (.age-gate-overlay)
     - The KS attribution block (renderAttribution in main.js)
     - Existing .codex-float-nav / .codex-float-footer islands

   All sub-class names use the .codex- / .codex-tb- / .codex-frame__
   prefix family to avoid collision with .lore-* and .timeline-*
   sibling pages.
   ============================================================ */

/* ============================================================
   1. THEME TOKENS
   ============================================================ */

/* PALETTE DECISION 2026-05-10: dark wine-leather tones (#18070a, #2a0c0a,
   #2a1408) replaced with warm obsidian + umber leather. Wine-burgundy clashed
   against the gold/ember accent stack ("looks awful" — owner). Unified gold
   design: obsidian (#1a1612 / #0c0408) + gold (#d4a44a–#e8c870) + ember
   (#ff7a4a) + wax-seal red accent (#6b1a1a–#8a2418) + parchment (#f5e8c2).
   Same token shape now mirrors lore-map + timeline grimoire surfaces. */
body.codex-theme-grimoire-dark {
    --cdx-bg:                 #0a0806;
    --cdx-bg-deep:            #060403;
    --cdx-leather:            #1f1612;
    --cdx-leather-mid:        #15100c;
    --cdx-leather-edge:       #2a1f16;
    --cdx-spine:              #100b08;
    --cdx-spine-seam:         rgba(0, 0, 0, .9);
    --cdx-ember:              #ff7a4a;
    --cdx-ember-dim:          rgba(255, 122, 74, .25);
    --cdx-ember-faint:        rgba(255, 122, 74, .12);
    --cdx-gold:               #d4a44a;
    --cdx-gold-bright:        #e8c870;
    --cdx-gold-dim:           rgba(212, 164, 74, .35);
    --cdx-rule:               rgba(212, 164, 74, .25);
    --cdx-text:               #e8dcc4;
    --cdx-text-dim:           #b6a382;
    --cdx-text-mute:          #7a6a52;
    --cdx-page-bg:            #1a1612;
    --cdx-page-edge:          #d6a44a;
    --cdx-page-edge-dark:     #3a2818;
    --cdx-glyph:              rgba(212, 164, 74, .55);
    --cdx-glyph-glow:         rgba(255, 122, 74, .35);
    --cdx-tb-bg:              linear-gradient(180deg, rgba(20, 14, 10, .94), rgba(7, 5, 10, .96));
    --cdx-tb-border:          rgba(212, 164, 74, .28);
    --cdx-tb-text:            #e8dcc4;
    --cdx-tb-text-hover:      #fff5d6;
    --cdx-tb-bracket:         #f4d27a;
    --cdx-tb-active-bg:       rgba(255, 122, 74, .12);
    --cdx-drawer-bg:          linear-gradient(180deg, #1a0d05, #0c0408);
    --cdx-drawer-border:      rgba(212, 164, 74, .28);
    --cdx-tooltip-bg:         #14100a;
    --cdx-tooltip-border:     rgba(212, 164, 74, .35);
    --cdx-tooltip-shadow:     0 14px 40px rgba(0, 0, 0, .65), 0 0 0 1px rgba(255, 122, 74, .08) inset;
    --cdx-spine-glyph-color:  #d4a44a;
}

body.codex-theme-grimoire-light {
    /* Light grimoire: parchment body + deeper umber leather frame so the
       binding reads dark against cream (was saddle-brown #6e3a1c — too mid-
       tone, blended into parchment). Mirrors timeline-grimoire light tokens. */
    --cdx-bg:                 #f5e8c2;
    --cdx-bg-deep:            #e8d4a0;
    --cdx-leather:            #3a2818;
    --cdx-leather-mid:        #2a1810;
    --cdx-leather-edge:       #5a3e22;
    --cdx-spine:              #2a1810;
    --cdx-spine-seam:         rgba(20, 8, 0, .55);
    --cdx-ember:              #b53020;
    --cdx-ember-dim:          rgba(181, 48, 32, .32);
    --cdx-ember-faint:        rgba(181, 48, 32, .14);
    --cdx-gold:               #8a5e1a;
    --cdx-gold-bright:        #6b1a1a;
    --cdx-gold-dim:           rgba(107, 26, 26, .35);
    --cdx-rule:               rgba(107, 26, 26, .25);
    --cdx-text:               #2a1f12;
    --cdx-text-dim:           #5a3a2a;
    --cdx-text-mute:          #8a6a3a;
    --cdx-page-bg:            #fff5d6;
    --cdx-page-edge:          #d6b078;
    --cdx-page-edge-dark:     #5a3e22;
    --cdx-glyph:              #8a2418;
    --cdx-glyph-glow:         rgba(138, 36, 24, .25);
    --cdx-tb-bg:              linear-gradient(180deg, rgba(255, 246, 219, .96), rgba(245, 232, 200, .98));
    --cdx-tb-border:          rgba(74, 32, 14, .35);
    --cdx-tb-text:            #4a200e;
    --cdx-tb-text-hover:      #1f0a02;
    --cdx-tb-bracket:         #8a2418;
    --cdx-tb-active-bg:       rgba(138, 36, 24, .1);
    --cdx-drawer-bg:          linear-gradient(180deg, #fff5d6, #f1ce7a);
    --cdx-drawer-border:      rgba(74, 32, 14, .35);
    --cdx-tooltip-bg:         #fdf6e1;
    --cdx-tooltip-border:     rgba(74, 32, 14, .35);
    --cdx-tooltip-shadow:     0 14px 40px rgba(74, 32, 14, .25), 0 0 0 1px rgba(138, 36, 24, .12) inset;
    --cdx-spine-glyph-color:  #8a2418;
}

/* Body backdrop swap by theme — never touch the existing .age-gate-overlay
   or the .codex-float-nav / .codex-float-footer islands. */
body.codex-theme-grimoire-dark {
    background:
        radial-gradient(ellipse at top, rgba(255, 122, 74, .04), transparent 55%),
        var(--cdx-bg);
}
body.codex-theme-grimoire-light {
    background:
        radial-gradient(ellipse at top, rgba(255, 245, 214, .9) 0%, var(--cdx-bg-deep) 60%, #c9a876 100%);
    color: var(--cdx-text);
}

/* ============================================================
   2. FRAME CHROME (.codex-frame__*)
   Wraps the existing #codex-app — purely additive, decorative.
   ============================================================ */

.codex-frame {
    position: relative;
    width: 100%;
    /* Issue 1 (2026-05-08 polish): clamp frame width so its inner content
       area exactly matches the .codex-canvas width. Canvas is min(90vw,920px)
       so frame is min(90vw + 2*cover-w, 920px + 2*cover-w). This makes the
       edge stripes (positioned at var(--cdx-cover-w) from each side) sit
       FLUSH against the canvas — reads as the page's own paper-stack edge
       instead of a decorative stripe floating in the leather. */
    --cdx-cover-w: 18px;
    --cdx-cover-h: 14px;
    max-width: calc(min(90vw, 920px) + 2 * var(--cdx-cover-w));
    margin: 0 auto;
    padding: var(--cdx-cover-h) var(--cdx-cover-w);
    border-radius: 7px;
    /* Issue 3: removed ember-faint diagonal tint that bled wine into the
       whole frame. Pure leather gradient now. */
    background:
        linear-gradient(180deg, var(--cdx-leather) 0%, var(--cdx-leather-mid) 50%, var(--cdx-leather) 100%);
    box-shadow:
        inset 0 0 0 1px var(--cdx-gold-dim),
        0 0 0 1px var(--cdx-gold-dim),
        0 0 80px -10px rgba(0, 0, 0, .65),
        inset 0 0 60px rgba(0, 0, 0, .35);
}

body.codex-theme-grimoire-light .codex-frame {
    box-shadow:
        inset 0 0 0 1px rgba(212, 164, 74, .35),
        0 0 0 1px rgba(74, 32, 14, .15),
        0 0 60px -8px rgba(74, 32, 14, .35);
}

/* Page-edge stripe stacks — left and right of the frame body. */
.codex-frame__edge {
    position: absolute;
    top: var(--cdx-cover-h);
    bottom: var(--cdx-cover-h);
    width: 5px;
    z-index: 4;
    pointer-events: none;
    background: repeating-linear-gradient(180deg,
        var(--cdx-page-edge) 0,
        var(--cdx-page-edge) 1px,
        var(--cdx-page-edge-dark) 1px,
        var(--cdx-page-edge-dark) 2px);
    box-shadow:
        inset 0 0 5px rgba(0, 0, 0, .55),
        0 0 4px rgba(0, 0, 0, .4);
    opacity: .85;
}
.codex-frame__edge--left  { left:  var(--cdx-cover-w); }
.codex-frame__edge--right { right: var(--cdx-cover-w); }

/* Spine seam — runs vertically through the centre of the frame.  The
   existing book-open layout already paints its own crease shadow; this
   layer adds the leather binding stitch + the centred Enochian glyph
   ornament so the codex reads as a bound grimoire even when on Cover. */
.codex-frame__spine {
    position: absolute;
    top: var(--cdx-cover-h);
    bottom: var(--cdx-cover-h);
    left: 50%;
    width: 22px;
    transform: translateX(-50%);
    z-index: 3;
    pointer-events: none;
    background:
        linear-gradient(90deg,
            transparent 0%,
            var(--cdx-spine-seam) 45%,
            var(--cdx-spine-seam) 55%,
            transparent 100%),
        linear-gradient(180deg,
            var(--cdx-ember-faint) 0%,
            transparent 8%,
            transparent 92%,
            var(--cdx-ember-faint) 100%);
    opacity: .55;
}
/* Spine glyph (centre Enochian ornament) DELETED 2026-05-10 per UAT —
   the binding seam alone gives the bound-grimoire feel; the floating sigil
   was distracting. Selector kept as `display: none !important` to neutralise
   any cached HTML still shipping the legacy div. */
.codex-frame__spine-glyph { display: none !important; }

/* Issue 3 (2026-05-08 polish): corner Enochian glyph ornaments REMOVED.
   The legacy classes stay declared as `display: none` so any cached HTML
   that still ships the corner divs renders nothing. Spine glyph stays. */
.codex-frame__glyph,
.codex-frame__glyph--tl,
.codex-frame__glyph--tr,
.codex-frame__glyph--bl,
.codex-frame__glyph--br { display: none !important; }

/* The original book.css uses opaque page backgrounds.  Re-tint via the
   --cdx-* tokens so light theme reads as parchment. */
body.codex-theme-grimoire-light .page {
    background:
        linear-gradient(135deg, transparent 0%, rgba(74, 32, 14, .04) 100%),
        var(--cdx-page-bg);
    color: var(--cdx-text);
}
body.codex-theme-grimoire-light .toc-name,
body.codex-theme-grimoire-light .entry-item-title,
body.codex-theme-grimoire-light .entry-content,
body.codex-theme-grimoire-light .entry-content p,
body.codex-theme-grimoire-light .toc-subheader { color: var(--cdx-text); }
body.codex-theme-grimoire-light .toc-num,
body.codex-theme-grimoire-light .chapter-title,
body.codex-theme-grimoire-light .entry-title,
body.codex-theme-grimoire-light .toc-header { color: var(--cdx-gold-bright); text-shadow: none; }
body.codex-theme-grimoire-light .entry-type-badge {
    color: var(--cdx-gold-bright);
    border-color: var(--cdx-gold-dim);
}
body.codex-theme-grimoire-light .breadcrumb { color: var(--cdx-text-mute); }
body.codex-theme-grimoire-light .bc-link { color: var(--cdx-gold-bright); }
body.codex-theme-grimoire-light .search-bar input {
    background: rgba(255, 245, 214, .6);
    border-color: var(--cdx-gold-dim);
    color: var(--cdx-text);
}
body.codex-theme-grimoire-light .toc-item:hover,
body.codex-theme-grimoire-light .entry-item:hover {
    background: rgba(138, 36, 24, .06);
}

/* ============================================================
   3. FLOATING TOOLBAR (.codex-toolbar / .codex-tb-*)
   Bottom-centre on desktop, full-width bottom-bar on mobile.
   ============================================================ */

.codex-toolbar {
    position: fixed;
    bottom: clamp(84px, 11vh, 110px);
    left: 50%;
    transform: translateX(-50%) translateY(8px);
    z-index: 80;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    background: var(--cdx-tb-bg);
    border: 1px solid var(--cdx-tb-border);
    border-radius: 6px;
    backdrop-filter: blur(14px) saturate(1.15);
    -webkit-backdrop-filter: blur(14px) saturate(1.15);
    color: var(--cdx-tb-text);
    font-family: 'Rajdhani', system-ui, sans-serif;
    font-size: 12px;
    letter-spacing: .04em;
    box-shadow:
        0 18px 40px -12px rgba(0, 0, 0, .65),
        0 0 0 1px rgba(255, 255, 255, .04) inset;
    opacity: 0;
    transition: opacity .35s ease, transform .35s ease;
    pointer-events: none;
}
.codex-toolbar.is-ready {
    opacity: 1;
    transform: translateX(-50%);
    pointer-events: auto;
}

/* Corner brackets — same Hellreach signature pattern. */
.codex-toolbar::before,
.codex-toolbar::after {
    content: '';
    position: absolute;
    width: 9px;
    height: 9px;
    border: 1px solid var(--cdx-tb-bracket);
    pointer-events: none;
    opacity: .8;
}
.codex-toolbar::before { top: -1px; left: -1px; border-right: 0; border-bottom: 0; }
.codex-toolbar::after  { bottom: -1px; right: -1px; border-left: 0; border-top: 0; }

.codex-tb-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 9px;
    color: var(--cdx-tb-text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 4px;
    font: inherit;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-weight: 600;
    cursor: pointer;
    transition: color .18s ease, background .18s ease, border-color .18s ease;
    white-space: nowrap;
    line-height: 1;
}
.codex-tb-btn:hover {
    color: var(--cdx-tb-text-hover);
    background: var(--cdx-tb-active-bg);
    border-color: var(--cdx-tb-border);
}
.codex-tb-btn[data-active="1"] {
    color: var(--cdx-tb-bracket);
    background: var(--cdx-tb-active-bg);
    border-color: var(--cdx-tb-border);
}
.codex-tb-btn .codex-tb-icon { font-size: 12px; line-height: 1; }
.codex-tb-btn .codex-tb-state {
    color: var(--cdx-tb-bracket);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: .08em;
    margin-left: 1px;
}
.codex-tb-sep {
    width: 1px;
    height: 16px;
    background: var(--cdx-tb-border);
    margin: 0 3px;
    opacity: .55;
}

/* Page input + total */
.codex-tb-page {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--cdx-tb-text);
    font-family: 'Cinzel', serif;
    font-size: 11px;
    letter-spacing: .08em;
    padding: 4px 6px;
}
.codex-tb-page input {
    width: 38px;
    background: transparent;
    border: 1px solid var(--cdx-tb-border);
    color: var(--cdx-tb-text);
    font-family: inherit;
    font-size: inherit;
    text-align: center;
    border-radius: 3px;
    padding: 2px 0;
    outline: none;
}
.codex-tb-page input:focus { border-color: var(--cdx-tb-bracket); }
.codex-tb-page__total { color: var(--cdx-text-mute); }

/* ============================================================
   4. JUMP-TO DROPDOWN
   ============================================================ */

.codex-tb-jump { position: relative; }
.codex-tb-jump__menu {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 0;
    min-width: 240px;
    max-width: 320px;
    max-height: 60vh;
    overflow-y: auto;
    padding: .35rem;
    background: var(--cdx-tb-bg);
    border: 1px solid var(--cdx-tb-border);
    border-radius: 6px;
    box-shadow: 0 14px 32px rgba(0, 0, 0, .6);
    list-style: none;
    margin: 0;
    z-index: 90;
    display: none;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}
.codex-tb-jump[data-open="1"] .codex-tb-jump__menu { display: block; }
.codex-tb-jump__item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    color: var(--cdx-tb-text);
    font-family: 'Rajdhani', sans-serif;
    font-size: 12px;
    padding: .35rem .55rem;
    border-radius: 3px;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
    line-height: 1.35;
}
.codex-tb-jump__item:hover {
    background: var(--cdx-tb-active-bg);
    color: var(--cdx-tb-bracket);
}
.codex-tb-jump__item-num {
    font-family: 'Cinzel', serif;
    font-size: 10px;
    color: var(--cdx-text-mute);
    letter-spacing: .12em;
    margin-right: .4rem;
    min-width: 26px;
    display: inline-block;
}
.codex-tb-jump__item.is-saga {
    background: rgba(212, 164, 74, .06);
    color: var(--cdx-gold);
    text-transform: uppercase;
    font-weight: 700;
    font-size: 10px;
    letter-spacing: .12em;
    margin-top: 4px;
    pointer-events: none;
}
.codex-tb-jump__item.is-locked { opacity: .4; cursor: not-allowed; }
.codex-tb-jump__item.is-locked:hover { background: transparent; color: var(--cdx-tb-text); }

/* ============================================================
   5. DRAWER (right-side slide-out)
   ============================================================ */

.codex-drawer {
    position: fixed;
    top: 70px;
    right: 0;
    bottom: 70px;
    width: min(420px, 92vw);
    z-index: 75;
    background: var(--cdx-drawer-bg);
    border-left: 1px solid var(--cdx-drawer-border);
    border-top-left-radius: 10px;
    border-bottom-left-radius: 10px;
    box-shadow: -10px 0 30px rgba(0, 0, 0, .55);
    transform: translateX(105%);
    transition: transform .35s cubic-bezier(.5, .12, .14, 1);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    color: var(--cdx-text);
}
.codex-drawer.is-open { transform: translateX(0); }
.codex-drawer__head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--cdx-drawer-border);
    font-family: 'Cinzel', serif;
    font-size: 12px;
    color: var(--cdx-gold);
    letter-spacing: .12em;
    text-transform: uppercase;
}
.codex-drawer__title { flex: 1; }
.codex-drawer__close {
    background: transparent;
    border: 1px solid var(--cdx-drawer-border);
    color: var(--cdx-gold);
    width: 28px;
    height: 28px;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1;
}
.codex-drawer__close:hover { background: var(--cdx-tb-active-bg); }
.codex-drawer__tabs {
    display: flex;
    gap: 0;
    padding: 0 8px;
    border-bottom: 1px solid var(--cdx-drawer-border);
}
.codex-drawer__tab {
    flex: 1;
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--cdx-text-dim);
    padding: 8px 10px;
    font-family: 'Rajdhani', sans-serif;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .1em;
    font-weight: 700;
    cursor: pointer;
    transition: color .15s, border-color .15s;
}
.codex-drawer__tab:hover { color: var(--cdx-text); }
.codex-drawer__tab[data-active="1"] {
    color: var(--cdx-gold-bright);
    border-bottom-color: var(--cdx-ember);
}
.codex-drawer__body {
    flex: 1;
    overflow-y: auto;
    padding: 12px 14px;
}
.codex-drawer__panel { display: none; }
.codex-drawer__panel[data-active="1"] { display: block; }

/* Contents list inside drawer */
.codex-drawer-contents {
    list-style: none;
    margin: 0;
    padding: 0;
    font-family: 'Rajdhani', sans-serif;
    font-size: 13px;
}
.codex-drawer-contents .saga-head {
    font-family: 'Cinzel', serif;
    font-size: 10px;
    color: var(--cdx-gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin: 12px 0 4px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--cdx-rule);
}
.codex-drawer-contents .saga-head:first-child { margin-top: 0; }
.codex-drawer-contents li.chapter {
    padding: 6px 8px;
    border-radius: 3px;
    cursor: pointer;
    color: var(--cdx-text);
    display: flex;
    gap: 8px;
    align-items: baseline;
    transition: background .15s, color .15s;
}
.codex-drawer-contents li.chapter:hover {
    background: var(--cdx-tb-active-bg);
    color: var(--cdx-gold-bright);
}
.codex-drawer-contents li.chapter.is-locked {
    opacity: .35;
    cursor: default;
}
.codex-drawer-contents li.chapter.is-locked:hover { background: transparent; color: var(--cdx-text); }
.codex-drawer-contents li.chapter.is-mature::after {
    content: '18+';
    font-family: 'Cinzel', serif;
    font-size: 9px;
    color: var(--cdx-ember);
    border: 1px solid var(--cdx-ember-dim);
    padding: 1px 4px;
    border-radius: 2px;
    margin-left: auto;
    letter-spacing: .1em;
}
.codex-drawer-contents li.chapter .num {
    font-family: 'Cinzel', serif;
    font-size: 10px;
    color: var(--cdx-text-mute);
    letter-spacing: .1em;
    min-width: 28px;
}

.codex-drawer-empty {
    color: var(--cdx-text-mute);
    font-size: 12px;
    font-style: italic;
    text-align: center;
    padding: 28px 12px;
}

/* Bookmarks list */
.codex-drawer-bookmarks { list-style: none; margin: 0; padding: 0; }
.codex-drawer-bookmarks li {
    padding: 8px 10px;
    border-bottom: 1px dashed var(--cdx-rule);
    font-size: 12px;
    color: var(--cdx-text);
    display: flex;
    gap: 8px;
    align-items: center;
}
.codex-drawer-bookmarks li:last-child { border-bottom: 0; }
.codex-drawer-bookmarks .bm-title {
    flex: 1;
    cursor: pointer;
    color: var(--cdx-gold-bright);
}
.codex-drawer-bookmarks .bm-title:hover { color: var(--cdx-ember); }
.codex-drawer-bookmarks .bm-rm {
    background: transparent;
    border: 0;
    color: var(--cdx-text-mute);
    cursor: pointer;
    font-size: 14px;
    padding: 0 4px;
}
.codex-drawer-bookmarks .bm-rm:hover { color: var(--cdx-ember); }

/* Notes pane */
.codex-drawer-notes textarea {
    width: 100%;
    height: 100%;
    min-height: 260px;
    background: var(--cdx-bg-deep);
    color: var(--cdx-text);
    border: 1px solid var(--cdx-drawer-border);
    border-radius: 4px;
    padding: 10px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 12px;
    line-height: 1.55;
    resize: vertical;
    outline: none;
}
.codex-drawer-notes textarea:focus { border-color: var(--cdx-gold-bright); }
.codex-drawer-notes__hint {
    margin-top: 6px;
    font-size: 10.5px;
    color: var(--cdx-text-mute);
    font-style: italic;
}

/* ============================================================
   6. POPOVERS — Reading + Theme panels
   ============================================================ */

.codex-popover {
    position: fixed;
    z-index: 90;
    min-width: 260px;
    max-width: 320px;
    background: var(--cdx-tb-bg);
    border: 1px solid var(--cdx-tb-border);
    border-radius: 6px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .6);
    color: var(--cdx-tb-text);
    font-family: 'Rajdhani', sans-serif;
    font-size: 12px;
    padding: 10px 12px;
    display: none;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}
.codex-popover.is-open { display: block; }
.codex-popover__title {
    font-family: 'Cinzel', serif;
    font-size: 10px;
    color: var(--cdx-gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--cdx-rule);
}
.codex-popover__row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0;
}
.codex-popover__label {
    flex: 0 0 78px;
    font-size: 10.5px;
    color: var(--cdx-text-mute);
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 700;
}
.codex-popover__row select,
.codex-popover__row input[type="range"] {
    flex: 1;
    background: transparent;
    border: 1px solid var(--cdx-tb-border);
    color: var(--cdx-tb-text);
    font: inherit;
    border-radius: 3px;
    padding: 4px 6px;
    outline: none;
}
.codex-popover__row select { padding: 4px 8px; }
.codex-popover__row input[type="range"] { padding: 0; height: 22px; }
.codex-popover__row .codex-popover__val {
    flex: 0 0 36px;
    text-align: right;
    color: var(--cdx-gold-bright);
    font-family: 'Cinzel', serif;
    font-size: 11px;
}

.codex-popover__seg {
    display: flex;
    gap: 0;
    border: 1px solid var(--cdx-tb-border);
    border-radius: 4px;
    overflow: hidden;
    flex: 1;
}
.codex-popover__seg button {
    flex: 1;
    background: transparent;
    border: 0;
    color: var(--cdx-text-dim);
    padding: 5px 8px;
    font: inherit;
    font-size: 11px;
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: .08em;
    transition: background .12s, color .12s;
}
.codex-popover__seg button:not(:last-child) { border-right: 1px solid var(--cdx-tb-border); }
.codex-popover__seg button[data-active="1"] {
    background: var(--cdx-tb-active-bg);
    color: var(--cdx-gold-bright);
}

/* Reading-class side effects on .entry-content */
body.cdx-rd-size-sm  .entry-content { font-size: 13px; }
body.cdx-rd-size-md  .entry-content { font-size: 15px; }
body.cdx-rd-size-lg  .entry-content { font-size: 17px; }
body.cdx-rd-size-xl  .entry-content { font-size: 19px; }
body.cdx-rd-line-tight   .entry-content { line-height: 1.5; }
body.cdx-rd-line-normal  .entry-content { line-height: 1.75; }
body.cdx-rd-line-loose   .entry-content { line-height: 2.05; }
body.cdx-rd-fam-cinzel    .entry-content { font-family: 'Cinzel', Georgia, serif; }
body.cdx-rd-fam-rajdhani  .entry-content { font-family: 'Rajdhani', system-ui, sans-serif; }
body.cdx-rd-fam-mono      .entry-content { font-family: 'Share Tech Mono', monospace; }

/* ============================================================
   7. TOOLTIP CARD — hover/long-press for [data-related] refs
   ============================================================ */

.codex-tooltip-card {
    position: fixed;
    z-index: 95;
    width: min(360px, 88vw);
    background: var(--cdx-tooltip-bg);
    border: 1px solid var(--cdx-tooltip-border);
    border-radius: 6px;
    box-shadow: var(--cdx-tooltip-shadow);
    padding: 12px 14px;
    color: var(--cdx-text);
    font-family: 'Rajdhani', sans-serif;
    font-size: 12px;
    line-height: 1.5;
    pointer-events: none;
    opacity: 0;
    transform: translateY(6px);
    transition: opacity .18s ease, transform .18s ease;
    cursor: pointer;
}
.codex-tooltip-card.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}
.codex-tooltip-card__type {
    display: inline-block;
    font-family: 'Share Tech Mono', monospace;
    font-size: 9px;
    letter-spacing: .14em;
    text-transform: lowercase;
    color: var(--cdx-gold);
    border: 1px solid var(--cdx-gold-dim);
    background: rgba(212, 164, 74, .08);
    padding: 2px 8px;
    border-radius: 999px;
    margin-bottom: 6px;
}
.codex-tooltip-card__title {
    font-family: 'Cinzel', serif;
    font-size: 14px;
    color: var(--cdx-gold-bright);
    margin: 0 0 6px 0;
    line-height: 1.25;
}
.codex-tooltip-card__excerpt {
    color: var(--cdx-text-dim);
    font-size: 12px;
    line-height: 1.55;
    max-height: 6em;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Issue 2 (2026-05-08 polish): chip rows — Hellreach-style FACTION / TIER /
   ORIGIN / REALM / STATUS pills. Type-aware: rendered selectively by JS. */
.codex-tooltip-card__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 6px;
    margin-top: 8px;
}
.codex-tooltip-card__chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 9.5px;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: 3px;
    border: 1px solid var(--cdx-gold-dim);
    background: rgba(212, 164, 74, .06);
    color: var(--cdx-text-dim);
    line-height: 1.4;
}
.codex-tooltip-card__chip-label {
    color: var(--cdx-text-mute);
    font-weight: 600;
}
.codex-tooltip-card__chip-value {
    color: var(--cdx-text);
    font-weight: 700;
}
.codex-tooltip-card__chip--faction-heaven  { background: rgba(246, 196, 83,  .15); border-color: #f6c453; }
.codex-tooltip-card__chip--faction-hell    { background: rgba(192, 57,  43,  .18); border-color: #c0392b; color: var(--cdx-text); }
.codex-tooltip-card__chip--faction-void    { background: rgba(107, 63,  160, .18); border-color: #6b3fa0; }
.codex-tooltip-card__chip--faction-glitch  { background: rgba(109, 255, 181, .12); border-color: #6dffb5; }
.codex-tooltip-card__chip--faction-bone    { background: rgba(216, 199, 154, .12); border-color: #d8c79a; }
.codex-tooltip-card__chip--tier            { background: rgba(212, 164, 74,  .18); border-color: var(--cdx-gold); color: var(--cdx-gold-bright); }
/* Status dot prefix */
.codex-tooltip-card__status-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #999;
}
.codex-tooltip-card__chip--status-alive    .codex-tooltip-card__status-dot { background: #6aff9e; box-shadow: 0 0 4px #6aff9e; }
.codex-tooltip-card__chip--status-dead     .codex-tooltip-card__status-dot { background: #5a5147; }
.codex-tooltip-card__chip--status-trapped  .codex-tooltip-card__status-dot { background: #b53020; box-shadow: 0 0 4px rgba(181, 48, 32, .6); }
.codex-tooltip-card__chip--status-active   .codex-tooltip-card__status-dot { background: #6aff9e; }
.codex-tooltip-card__chip--status-dormant  .codex-tooltip-card__status-dot { background: #5a5147; }
.codex-tooltip-card__chip--status-unknown  .codex-tooltip-card__status-dot { background: #7a6a52; }
.codex-tooltip-card__hint {
    margin-top: 10px;
    padding-top: 6px;
    border-top: 1px dashed var(--cdx-rule);
    font-size: 10px;
    color: var(--cdx-text-mute);
    text-transform: uppercase;
    letter-spacing: .1em;
}
/* Creator-only canon indicator */
.codex-tooltip-card__canon-badge {
    display: inline-block;
    margin-left: 6px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 8.5px;
    letter-spacing: .12em;
    color: #ff7a4a;
    background: rgba(255, 122, 74, .12);
    border: 1px solid rgba(255, 122, 74, .35);
    padding: 0 4px;
    border-radius: 2px;
    vertical-align: middle;
}
/* Touch-only screens — disable hover-triggered card (no hover input available). */
@media (hover: none) {
    .codex-tooltip-card { display: none; }
}

/* Inline reference style — applied to entry-content links the JS finds. */
.codex-ref {
    color: var(--cdx-gold-bright);
    border-bottom: 1px dotted var(--cdx-gold-dim);
    cursor: help;
    transition: color .15s, border-color .15s;
}
.codex-ref:hover { color: var(--cdx-ember); border-bottom-color: var(--cdx-ember-dim); }

/* ============================================================
   8. MOBILE — single-page portrait below 1024px
   The existing book.css already collapses to single-column on
   mobile.  We just shrink the chrome + reposition the toolbar.
   ============================================================ */

@media (max-width: 1023px) {
    .codex-frame {
        --cdx-cover-w: 10px;
        --cdx-cover-h: 8px;
        max-width: 100%;
        margin: 0 auto;
        border-radius: 4px;
    }
    .codex-frame__edge { width: 3px; }
    .codex-frame__spine { width: 12px; }
    /* spine-glyph removed 2026-05-10 */
    .codex-frame__glyph { width: 20px; height: 20px; }
}

@media (max-width: 700px) {
    .codex-toolbar {
        bottom: 24px;
        left: 8px;
        right: 8px;
        transform: translateX(0) translateY(8px);
        gap: 2px;
        padding: 5px 7px;
        border-radius: 5px;
        font-size: 11px;
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: none;
        flex-wrap: nowrap;
        -webkit-overflow-scrolling: touch;
    }
    .codex-toolbar::-webkit-scrollbar { display: none; }
    .codex-toolbar.is-ready { transform: none; }
    .codex-tb-btn { padding: 5px 7px; font-size: 10.5px; }
    .codex-tb-btn .codex-tb-label { display: none; }
    .codex-tb-sep { height: 14px; margin: 0 1px; }
    .codex-tb-page { padding: 4px; font-size: 10px; }
    .codex-tb-page input { width: 30px; }
    .codex-tb-jump__menu { right: auto; left: 0; min-width: 200px; }

    .codex-drawer {
        top: 0;
        bottom: 0;
        width: 100vw;
        border-radius: 0;
        border-left: 0;
    }

    .codex-popover {
        left: 8px !important;
        right: 8px !important;
        max-width: none;
        width: auto;
    }

    /* Suppress legacy float islands while drawer/toolbar are active so
       chrome doesn't double-stack on tiny screens. */
    body.codex-drawer-open .codex-float-nav,
    body.codex-drawer-open .codex-float-footer { display: none; }
}

@media (max-width: 359px) {
    .codex-tb-btn .codex-tb-state { display: none; }
}

/* ============================================================
   9. FX TOGGLE — kills heavy filters on slow devices.
   ============================================================ */
body.codex-fx-off .codex-frame { box-shadow: 0 0 0 1px var(--cdx-gold-dim); }
body.codex-fx-off .codex-frame__spine { opacity: .35; }
body.codex-fx-off .codex-frame__glyph { filter: none; }
body.codex-fx-off .codex-toolbar { backdrop-filter: none; -webkit-backdrop-filter: none; }
body.codex-fx-off .codex-popover { backdrop-filter: none; -webkit-backdrop-filter: none; }
body.codex-fx-off .codex-tooltip-card { box-shadow: 0 4px 14px rgba(0, 0, 0, .55); }
body.codex-fx-off #enochian-particles { display: none; }
body.codex-fx-off .cursor-light { display: none; }

/* ============================================================
   10. REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
    .codex-toolbar,
    .codex-drawer,
    .codex-tooltip-card,
    .codex-tb-btn { transition: none !important; }
}

/* ============================================================
   11. MATURE-GATE PRESERVATION — never let theme re-tint break it.
   ============================================================ */
.age-gate-overlay { /* untouched — keep red imprint colours from index.html */ }
body.codex-theme-grimoire-light .age-gate-modal { color: #E8DCC4; }

/* ============================================================
   12. DARK MODE FRAME LEGIBILITY (Issue 3 — RED HUE REMOVED)
   2026-05-08: User feedback removed wine/ember atmospheric.
   Dark mode now reads as "ancient grimoire on black" — gold
   accents only, no red mood lighting bleed.
   ============================================================ */
body.codex-theme-grimoire-dark .codex-frame {
    /* Red ember halo removed — was rgba(255, 70, 30, .25) at 90px.
       Now only black depth + faint gold inner border. */
    box-shadow:
        inset 0 0 0 1px rgba(212, 164, 74, .18),
        0 0 0 1px rgba(212, 164, 74, .28),
        0 0 80px -10px rgba(0, 0, 0, .7),
        inset 0 0 60px rgba(0, 0, 0, .4);
}
body.codex-theme-grimoire-dark .codex-frame__edge {
    opacity: .9;
    /* Ember-tinted edge glow → faint gold underglow only. */
    box-shadow:
        inset 0 0 5px rgba(0, 0, 0, .55),
        0 0 4px rgba(212, 164, 74, .18);
}
body.codex-theme-grimoire-dark .codex-frame__glyph {
    color: #d4a44a;
    opacity: .8;
    /* Removed ember drop-shadow — kept subtle gold halo. */
    filter: drop-shadow(0 0 4px rgba(212, 164, 74, .35));
}
body.codex-theme-grimoire-dark .codex-frame__spine {
    opacity: .55;
    /* Removed ember-tinted vertical gradient — now pure spine seam. */
    background:
        linear-gradient(90deg,
            transparent 0%,
            var(--cdx-spine-seam) 45%,
            var(--cdx-spine-seam) 55%,
            transparent 100%);
}

/* Dark theme tokens: kill the ember-faint background tint that was
   creating the wine atmospheric halo around the whole page. */
body.codex-theme-grimoire-dark {
    background:
        radial-gradient(ellipse at top, rgba(212, 164, 74, .03), transparent 55%),
        var(--cdx-bg);
}

/* ============================================================
   13. BOOKMARK RIBBON (Issue 4) — gold ribbon top-right of
   the open book on entry view when current entry is marked.
   Uses body data-attr toggled by codex-grimoire.js.
   ============================================================ */
body[data-codex-bookmarked="1"] #view-entry .book-open::before {
    content: '';
    position: absolute;
    top: -4px;
    right: 28px;
    width: 26px;
    height: 56px;
    background:
        linear-gradient(180deg, #f3d8a0 0%, #d4a44a 55%, #8a5e1a 100%);
    clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
    box-shadow:
        0 4px 8px rgba(0, 0, 0, .55),
        inset 0 0 0 1px rgba(255, 230, 180, .6);
    z-index: 50;
    animation: codexRibbonDrop .35s cubic-bezier(.5, .12, .14, 1.05);
    pointer-events: none;
}
body[data-codex-bookmarked="1"].codex-theme-grimoire-light #view-entry .book-open::before {
    background: linear-gradient(180deg, #c8324a 0%, #8a1818 55%, #4a0808 100%);
    box-shadow:
        0 4px 8px rgba(74, 8, 8, .35),
        inset 0 0 0 1px rgba(255, 200, 200, .55);
}
@keyframes codexRibbonDrop {
    from { transform: translateY(-12px); opacity: 0; }
    to   { transform: translateY(0);     opacity: 1; }
}

/* Mark button "active" state mirrors body[data-codex-bookmarked]. */
.codex-tb-btn#codex-tb-mark[data-bookmarked="1"] {
    color: var(--cdx-gold-bright);
    background: var(--cdx-tb-active-bg);
    border-color: var(--cdx-tb-bracket);
}
.codex-tb-btn#codex-tb-mark[data-bookmarked="1"] .codex-tb-icon::before {
    /* Switch the bookmark icon to filled visually via FontAwesome unicode. */
    content: '\f02e'; /* fa-bookmark (solid, filled) */
}

/* ============================================================
   14. NOTES LIST (Issue 5) — drawer Notes tab now shows a list
   of all per-entry notes plus the active textarea below it.
   ============================================================ */
.codex-drawer-notes-list {
    list-style: none;
    margin: 0 0 12px 0;
    padding: 0;
    border-bottom: 1px solid var(--cdx-rule);
    padding-bottom: 10px;
}
.codex-drawer-notes-list:empty { display: none; }
.codex-drawer-notes-list li {
    padding: 6px 8px;
    margin-bottom: 4px;
    border-radius: 3px;
    cursor: pointer;
    color: var(--cdx-text);
    font-size: 12px;
    line-height: 1.4;
    display: flex;
    gap: 8px;
    align-items: flex-start;
    transition: background .12s, color .12s;
    border-left: 2px solid var(--cdx-gold-dim);
}
.codex-drawer-notes-list li:hover {
    background: var(--cdx-tb-active-bg);
    border-left-color: var(--cdx-ember);
}
.codex-drawer-notes-list .nl-title {
    flex: 1;
    color: var(--cdx-gold-bright);
    font-family: 'Cinzel', serif;
    font-size: 11px;
    letter-spacing: .04em;
}
.codex-drawer-notes-list .nl-snippet {
    flex: 2;
    color: var(--cdx-text-dim);
    font-size: 11px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 220px;
}
.codex-drawer-notes-list .nl-rm {
    background: transparent;
    border: 0;
    color: var(--cdx-text-mute);
    cursor: pointer;
    font-size: 13px;
    padding: 0 4px;
    line-height: 1;
}
.codex-drawer-notes-list .nl-rm:hover { color: var(--cdx-ember); }
.codex-drawer-notes__current-label {
    font-family: 'Cinzel', serif;
    font-size: 9px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--cdx-gold);
    margin-bottom: 4px;
}

/* ============================================================
   15. EDGE-GRAB / DRAG-FLIP AFFORDANCE (Issue 1) — physical
   page corners are draggable to flip forward/back. Enhances
   the existing custom flip system in book.js without touching
   it. The hover hotspots only show when entry/chapter view.
   ============================================================ */
.codex-drag-edge {
    position: absolute;
    top: 6%;
    bottom: 6%;
    width: 38px;
    z-index: 25;
    cursor: grab;
    background:
        linear-gradient(90deg,
            rgba(212, 164, 74, 0) 0%,
            rgba(212, 164, 74, .08) 50%,
            rgba(212, 164, 74, .18) 100%);
    opacity: 0;
    transition: opacity .25s ease, background .2s ease;
    pointer-events: auto;
    -webkit-user-select: none;
            user-select: none;
}
.codex-drag-edge--right { right: 0; border-radius: 0 6px 6px 0; }
.codex-drag-edge--left {
    left: 0;
    border-radius: 6px 0 0 6px;
    background:
        linear-gradient(270deg,
            rgba(212, 164, 74, 0) 0%,
            rgba(212, 164, 74, .08) 50%,
            rgba(212, 164, 74, .18) 100%);
}
.book-open:hover .codex-drag-edge,
.codex-drag-edge.is-active { opacity: 1; }
.codex-drag-edge.is-dragging {
    cursor: grabbing;
    background:
        linear-gradient(90deg,
            rgba(255, 122, 74, .12) 0%,
            rgba(255, 122, 74, .25) 60%,
            rgba(255, 122, 74, .35) 100%);
}
.codex-drag-edge--right::after,
.codex-drag-edge--left::after {
    content: '';
    position: absolute;
    top: 50%;
    width: 22px;
    height: 28px;
    transform: translateY(-50%);
    background:
        radial-gradient(ellipse at center,
            rgba(212, 164, 74, .55) 0%,
            transparent 70%);
    pointer-events: none;
}
.codex-drag-edge--right::after { right: 4px; }
.codex-drag-edge--left::after  { left: 4px; }
.codex-drag-edge[data-disabled="1"] { display: none; }

/* Page-curl preview during drag — pseudo 3D corner-fold. */
.book-open.codex-flipping-forward .page-right,
.book-open.codex-flipping-backward .page-left {
    transition: transform .08s linear;
    will-change: transform;
}
.book-open.codex-flipping-forward .page-right {
    transform-origin: left center;
    transform: perspective(2000px) rotateY(var(--codex-flip-angle, 0deg));
    box-shadow: -8px 0 24px rgba(0, 0, 0, .35);
}
.book-open.codex-flipping-backward .page-left {
    transform-origin: right center;
    transform: perspective(2000px) rotateY(var(--codex-flip-angle, 0deg));
    box-shadow: 8px 0 24px rgba(0, 0, 0, .35);
}

@media (max-width: 1023px) {
    /* Hide drag handles on portrait/mobile — use swipe gestures already
       in book.js mobileScroll path; PageFlip native usePortrait single-page. */
    .codex-drag-edge { display: none; }
}

/* ============================================================
   16. PAGEFLIP MODE — flat-page-list rendering (Issue 1)
   When body[data-codex-pageflip="1"] is set, the legacy 5-view
   #codex-app system is hidden and the new #codex-canvas takes
   over. PageFlip mounts each .codex-page as a leaf.
   ============================================================ */
body[data-codex-pageflip="1"] #codex-app { display: none !important; }

/* 2026-05-16 UAT fix #9 (revised 2026-05-17): body is display:flex
   (style.css), so .codex-frame (the codex-grimoire.js wrapper around
   #codex-app) competes for flex-row space against .codex-pageflip-host
   and pushes the host off-center on wide viewports. #codex-app inside
   is already hidden — the wrapper is orphaned.
   Hide the whole wrapper so pageflip-host is the only in-flow flex
   child; body's justify-content:center then actually centers it.
   Specificity note: Section 17 below has
   `body[data-codex-state="cover"] .codex-frame { display: flex !important }`
   at equal specificity (0,2,1). To beat it we chain BOTH attributes here,
   raising to (0,3,1). Matches any state value because [data-codex-state]
   exists on body whenever pageflip has mounted. */
body[data-codex-pageflip="1"][data-codex-state] .codex-frame {
    display: none !important;
}

/* Bookmark ribbon now follows the PageFlip page state, not the
   old 5-view #view-entry. Re-anchor the ::before. */
body[data-codex-pageflip="1"][data-codex-bookmarked="1"] #view-entry .book-open::before { display: none; }
body[data-codex-pageflip="1"][data-codex-bookmarked="1"] .codex-pageflip-host::before {
    content: '';
    position: absolute;
    top: -4px;
    right: 28px;
    width: 26px;
    height: 56px;
    background: linear-gradient(180deg, #f3d8a0 0%, #d4a44a 55%, #8a5e1a 100%);
    clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
    box-shadow:
        0 4px 8px rgba(0, 0, 0, .55),
        inset 0 0 0 1px rgba(255, 230, 180, .6);
    z-index: 50;
    pointer-events: none;
}

.codex-pageflip-host {
    position: relative;
    width: 100%;
    /* Issue 1 (2026-05-08): host width matches canvas so the edge stripes
       on .codex-frame land flush against the canvas boundary. */
    max-width: min(90vw, 920px);
    margin: 0 auto;
    min-height: min(80vh, 600px);
}
.codex-canvas {
    width: min(90vw, 920px);
    height: min(80vh, 600px);
    margin: 0 auto;
    position: relative;
}
@media (max-width: 1023px) {
    .codex-canvas { width: min(94vw, 600px); height: min(78vh, 760px); margin: 0 auto; }
}
/* E-reader stopgap (mobile): book significantly smaller than viewport,
   centred with chrome breathing room, prose-readable padding. The new
   /codex/entry/{slug} architecture moves most non-event entries OUT of
   the book — this stopgap keeps the in-book reading experience usable
   on small screens until that migration is fully wired. */
@media (max-width: 700px) {
    .codex-canvas {
        width: min(92vw, 440px);
        height: min(74vh, 640px);
        max-height: 74vh;
        margin: 24px auto 96px;   /* top breath + bottom toolbar clearance */
    }
    .codex-pageflip-host {
        min-height: 0;
        padding: 8px 0;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .codex-page-inner {
        padding: 20px 18px 28px;
        font-size: 15px;
        line-height: 1.55;
    }
    /* Mobile: still inset scrollbar inside page area */
    .codex-page--entry .codex-page-inner,
    .codex-page--chapter-toc .codex-page-inner {
        padding-right: 26px;
    }
    .codex-page h2 { font-size: 1.15rem; line-height: 1.25; }
    .codex-page h3 { font-size: 1rem; }
    /* Drag-edge hotspots stay disabled on touch (already handled by
       the existing < 1023px rule); native PageFlip swipe takes over. */
}
@media (max-width: 414px) {
    .codex-canvas { width: 94vw; height: 70vh; max-height: 70vh; margin: 16px auto 88px; }
    .codex-page-inner { padding: 16px 14px 24px; font-size: 14.5px; }
}
@media (max-width: 360px) {
    .codex-canvas { width: 96vw; height: 68vh; margin: 12px auto 80px; }
    .codex-page-inner { padding: 14px 12px 22px; font-size: 14px; }
}

/* All .codex-page children of the canvas — PageFlip clones them into
   its own structure. Background reuses --cdx-page-bg + the ruled
   parchment line repeats from book.css. */
.codex-page {
    width: 100%;
    height: 100%;
    background: var(--cdx-page-bg, #1a1610);
    color: var(--cdx-text, #e8dcc4);
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
    font-family: 'Rajdhani', system-ui, sans-serif;
}
.codex-page::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 1;
    background: repeating-linear-gradient(
        0deg,
        transparent,
        transparent 28px,
        rgba(212, 164, 74, .03) 28px,
        rgba(212, 164, 74, .03) 29px);
}
.codex-page-inner {
    position: relative;
    z-index: 2;
    padding: 36px 32px;
    height: 100%;
    overflow: hidden;
    box-sizing: border-box;
}
@media (max-width: 700px) {
    .codex-page-inner { padding: 22px 18px; }
}

/* ============================================================
   COVER — 3D leather book front (Issue 4, 2026-05-11 UAT)
   Obsidian leather + gold piping border + embossed monogram.
   The 3D float is done with stacked drop shadows so the cover
   reads as a closed book hovering above the page surface.
   ============================================================ */
.codex-page--cover {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    /* Deep obsidian leather — NO red. Subtle diagonal grain via two
       overlaid linear gradients; the bottom-right corner is the
       darkest so the highlight reads as a top-left light source. */
    background:
        radial-gradient(ellipse at 32% 22%, rgba(212, 164, 74, .14) 0%, transparent 55%),
        radial-gradient(ellipse at 50% 100%, rgba(0, 0, 0, .55) 0%, transparent 70%),
        linear-gradient(135deg, #2a1f16 0%, #1f1612 45%, #0c0907 100%);
    /* Two nested borders = "gold piping" effect. The outer thin gold
       hairline sits on top of the leather edge; the inner gold band
       creates the embossed inset. */
    border: 1px solid rgba(212, 164, 74, .55);
    border-radius: 8px;
    box-shadow:
        /* Inset gold piping — outer */
        inset 0 0 0 1px rgba(212, 164, 74, .35),
        /* Inset gold piping — inner band */
        inset 0 0 0 6px rgba(0, 0, 0, .35),
        inset 0 0 0 7px rgba(212, 164, 74, .25),
        /* Deep 3D float shadow (book floats above page) */
        0 30px 60px -20px rgba(0, 0, 0, .7),
        0 12px 22px -8px rgba(0, 0, 0, .5),
        /* Top-edge specular highlight on leather */
        inset 0 2px 0 rgba(255, 240, 200, .04);
    overflow: hidden;
    position: relative;
}
/* Leather grain — repeating subtle noise via radial gradients. */
.codex-page--cover::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(circle at 12% 32%, rgba(255, 240, 200, .04) 0, transparent 22%),
        radial-gradient(circle at 78% 64%, rgba(0, 0, 0, .25) 0, transparent 30%),
        radial-gradient(circle at 38% 88%, rgba(212, 164, 74, .05) 0, transparent 28%);
    mix-blend-mode: overlay;
    opacity: .8;
}
.codex-cover-inner {
    position: relative;
    z-index: 2;
    width: 82%;
    max-width: 380px;
    padding: 28px 22px 26px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}
/* Embossed gold monogram disc — the "L" sigil. */
.codex-cover-monogram {
    width: 78px;
    height: 78px;
    border-radius: 50%;
    background:
        radial-gradient(circle at 35% 30%, #f3d8a0 0%, #d4a44a 45%, #8a5e1a 85%, #4a2f0c 100%);
    box-shadow:
        inset 0 -3px 6px rgba(0, 0, 0, .45),
        inset 0 2px 4px rgba(255, 240, 200, .35),
        0 4px 12px rgba(0, 0, 0, .55),
        0 0 0 2px rgba(212, 164, 74, .4);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 4px;
    animation: emblemPulse 4s ease-in-out infinite;
}
.codex-cover-monogram-letter {
    font-family: 'Cinzel', Georgia, serif;
    font-weight: 900;
    font-size: 42px;
    color: #1a120a;
    text-shadow:
        0 1px 0 rgba(255, 240, 200, .35),
        0 -1px 1px rgba(0, 0, 0, .55);
    line-height: 1;
}
.codex-cover-title {
    font-family: 'Cinzel', Georgia, serif;
    font-size: clamp(20px, 4.2vw, 28px);
    font-weight: 700;
    color: #e8c870;
    line-height: 1.25;
    margin: 0;
    letter-spacing: .04em;
    text-shadow:
        0 1px 0 rgba(0, 0, 0, .55),
        0 0 18px rgba(212, 164, 74, .35);
}
.codex-cover-rule {
    width: 90px;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(212, 164, 74, .65), transparent);
    margin: 2px 0;
}
.codex-cover-subtitle {
    font-family: 'Cinzel', Georgia, serif;
    font-size: 11.5px;
    color: rgba(232, 220, 196, .82);
    font-style: italic;
    letter-spacing: .08em;
    margin: 0;
}
.codex-cover-glyphs { display: flex; gap: 20px; margin: 4px 0 2px; }
.codex-cover-glyphs img {
    /* Gold-tint, no inversion to white — keeps glyphs warm against leather. */
    filter:
        brightness(0) saturate(100%)
        invert(72%) sepia(36%) saturate(540%)
        hue-rotate(360deg) brightness(94%) contrast(88%)
        drop-shadow(0 0 6px rgba(212, 164, 74, .35));
    opacity: .85;
    object-fit: contain;
}
.codex-cover-open-btn {
    margin-top: 10px;
    padding: 11px 26px;
    border: 1px solid rgba(212, 164, 74, .55);
    border-radius: 3px;
    background: linear-gradient(180deg, rgba(212, 164, 74, .14), rgba(212, 164, 74, .04));
    color: #f3d8a0;
    font-family: 'Cinzel', Georgia, serif;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .2s ease, color .2s ease, border-color .2s ease, transform .12s ease;
    box-shadow:
        inset 0 1px 0 rgba(255, 240, 200, .12),
        0 4px 10px rgba(0, 0, 0, .4);
}
.codex-cover-open-btn:hover {
    background: linear-gradient(180deg, rgba(212, 164, 74, .26), rgba(212, 164, 74, .12));
    color: #fff5d6;
    border-color: rgba(232, 200, 112, .8);
    transform: translateY(-1px);
}
.codex-cover-open-btn:active { transform: translateY(0); }
.codex-cover-hint {
    font-family: 'Share Tech Mono', monospace;
    font-size: 9.5px;
    color: rgba(232, 220, 196, .45);
    text-transform: uppercase;
    letter-spacing: .16em;
    opacity: .65;
    margin: 6px 0 0;
}

/* Light mode — parchment-leather cover (still no red). */
body.codex-theme-grimoire-light .codex-page--cover {
    background:
        radial-gradient(ellipse at 32% 22%, rgba(255, 240, 200, .28) 0%, transparent 55%),
        radial-gradient(ellipse at 50% 100%, rgba(74, 32, 14, .25) 0%, transparent 70%),
        linear-gradient(135deg, #6b4a28 0%, #4a2f18 50%, #2a1810 100%);
    box-shadow:
        inset 0 0 0 1px rgba(212, 164, 74, .55),
        inset 0 0 0 6px rgba(0, 0, 0, .25),
        inset 0 0 0 7px rgba(212, 164, 74, .35),
        0 30px 60px -20px rgba(74, 32, 14, .5),
        0 12px 22px -8px rgba(74, 32, 14, .35);
}
body.codex-theme-grimoire-light .codex-cover-title { color: #f3d8a0; }
body.codex-theme-grimoire-light .codex-cover-subtitle { color: rgba(255, 245, 214, .85); }

/* Mobile-portrait scaling — cover stays prominent. */
@media (max-width: 700px) {
    .codex-cover-inner { width: 86%; max-width: 320px; padding: 22px 18px; gap: 12px; }
    .codex-cover-monogram { width: 64px; height: 64px; }
    .codex-cover-monogram-letter { font-size: 34px; }
    .codex-cover-title { font-size: clamp(18px, 5vw, 24px); }
    .codex-cover-open-btn { padding: 10px 22px; font-size: 11.5px; }
}
@media (max-width: 414px) {
    .codex-cover-inner { width: 88%; padding: 18px 14px; gap: 10px; }
    .codex-cover-glyphs { gap: 14px; }
}

/* Saga divider */
.codex-page--saga {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.codex-saga-inner { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.codex-saga-roman {
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    letter-spacing: .35em;
    text-transform: uppercase;
    color: var(--cdx-text-mute);
}
.codex-saga-name {
    font-family: 'Cinzel', serif;
    font-size: 30px;
    font-weight: 700;
    color: var(--cdx-gold-bright);
    letter-spacing: .04em;
    text-shadow: 0 0 22px rgba(212, 164, 74, .35);
}
.codex-saga-ornament {
    width: 80px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--cdx-gold-dim), transparent);
    margin-top: 8px;
}

/* Chapter intro */
.codex-page--chapter-intro { display: flex; align-items: center; justify-content: center; text-align: center; }
.codex-chapter-intro-inner { display: flex; flex-direction: column; gap: 14px; align-items: center; }
.codex-chapter-num {
    font-family: 'Share Tech Mono', monospace;
    font-size: 14px;
    letter-spacing: .2em;
    color: var(--cdx-gold);
    text-transform: uppercase;
}
.codex-chapter-title {
    font-family: 'Cinzel', serif;
    font-size: 26px;
    font-weight: 700;
    color: var(--cdx-gold-bright);
    margin: 0;
    line-height: 1.25;
    max-width: 86%;
}
.codex-chapter-rule {
    width: 60px;
    height: 1px;
    background: var(--cdx-gold-dim);
    margin: 6px 0;
}
.codex-chapter-saga {
    font-family: 'Cinzel', serif;
    font-size: 12px;
    color: var(--cdx-text-dim);
    font-style: italic;
    letter-spacing: .14em;
    text-transform: uppercase;
    margin: 0;
}

/* Chapter TOC */
.codex-page--chapter-toc .codex-page-inner {
    overflow-y: auto;
    /* Issue 3 (2026-05-10 UAT): inset scroll-bar so it sits inside the
       page area, not under the gold edge-stripe of the leather frame. */
    padding-right: 44px;
    scrollbar-gutter: stable;
}
.codex-toc-eyebrow {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--cdx-text-mute);
    letter-spacing: .2em;
    text-transform: uppercase;
}
.codex-toc-chapter {
    font-family: 'Cinzel', serif;
    font-size: 20px;
    color: var(--cdx-gold-bright);
    margin: 4px 0 18px;
}
.codex-toc-list { list-style: none; margin: 0; padding: 0; }
.codex-toc-item {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 6px;
    border-bottom: 1px dashed var(--cdx-rule);
    cursor: pointer;
    transition: background .14s ease, padding-left .14s ease;
}
.codex-toc-item:hover {
    background: rgba(212, 164, 74, .06);
    padding-left: 12px;
}
.codex-toc-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--cdx-gold-dim);
    flex-shrink: 0;
}
.codex-toc-name {
    flex: 1;
    font-family: 'Cinzel', serif;
    font-size: 14px;
    color: var(--cdx-text);
}
.codex-toc-type {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--cdx-ember);
    text-transform: uppercase;
    letter-spacing: .12em;
}

/* Gated placeholder */
.codex-page--gated {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.codex-gated-inner { padding: 24px; max-width: 420px; }
.codex-gated-imprint {
    display: inline-block;
    font-size: 10px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--cdx-gold);
    border: 1px solid var(--cdx-gold-dim);
    padding: 4px 10px;
    border-radius: 3px;
    margin-bottom: 14px;
}
.codex-gated-title { font-family: 'Cinzel', serif; font-size: 22px; color: var(--cdx-gold-bright); margin: 0 0 12px; }
.codex-gated-body { font-size: 13px; color: var(--cdx-text-dim); line-height: 1.6; }

/* Entry pages */
.codex-page--entry .codex-page-inner {
    overflow-y: auto;
    /* Issue 3 (2026-05-10 UAT): inset scroll-bar so it sits inside the
       page area, not under the gold edge-stripe on the right of the frame.
       padding-right > base 32px clears the stripe (edge-stripe width 5px +
       cover-w 18px + breathing room). scrollbar-gutter reserves the gutter
       space whether or not a scrollbar is shown so layout doesn't jump. */
    padding-right: 44px;
    scrollbar-gutter: stable;
}
/* Slim the scrollbar visually so the inset feels intentional, not blocky. */
.codex-page--entry .codex-page-inner::-webkit-scrollbar,
.codex-page--chapter-toc .codex-page-inner::-webkit-scrollbar {
    width: 6px;
}
.codex-page--entry .codex-page-inner::-webkit-scrollbar-thumb,
.codex-page--chapter-toc .codex-page-inner::-webkit-scrollbar-thumb {
    background: var(--cdx-gold-dim, rgba(212, 164, 74, .35));
    border-radius: 3px;
}
.codex-page--entry .codex-page-inner::-webkit-scrollbar-track,
.codex-page--chapter-toc .codex-page-inner::-webkit-scrollbar-track {
    background: transparent;
}
.codex-page--entry .codex-page-inner,
.codex-page--chapter-toc .codex-page-inner {
    scrollbar-width: thin;
    scrollbar-color: var(--cdx-gold-dim, rgba(212, 164, 74, .35)) transparent;
}
.codex-entry-content { font-size: 14px; line-height: 1.75; color: var(--cdx-text); }
.codex-entry-type-badge {
    display: inline-block;
    font-family: 'Share Tech Mono', monospace;
    font-size: 9px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--cdx-gold);
    border: 1px solid var(--cdx-gold-dim);
    padding: 2px 8px;
    border-radius: 3px;
    margin-bottom: 6px;
}
.codex-entry-portrait { margin: 12px 0 8px; text-align: center; }
.codex-portrait-img {
    max-width: 85%;
    max-height: 240px;
    object-fit: contain;
    border: 1px solid var(--cdx-gold-dim);
    border-radius: 4px;
    box-shadow: 0 0 20px rgba(0, 0, 0, .4);
}
.codex-portrait-caption {
    font-family: 'Share Tech Mono', monospace;
    font-size: 9px;
    color: var(--cdx-text-mute);
    font-style: italic;
    margin: 6px 0 0;
}
.codex-entry-title {
    font-family: 'Cinzel', serif;
    font-size: 22px;
    color: var(--cdx-gold-bright);
    margin: 8px 0 14px;
}
.codex-entry-content p { margin-bottom: 12px; }
.codex-entry-content strong { color: var(--cdx-gold-bright); }
.codex-entry-content em { color: var(--cdx-text-dim); }
/* Issue 4 (2026-05-08 polish): blockquote treatment for the Codex's own
   marginalia voice ("The Codex shudders at this page…"). Italic, gold
   left-rule, parchment wash, soft drop-cap on first letter, slightly
   desaturated text colour for that margin-note feel. */
.codex-entry-content blockquote,
.codex-page blockquote,
.codex-page-inner blockquote {
    position: relative;
    border-left: 3px solid var(--cdx-gold);
    padding: 10px 16px 10px 20px;
    margin: 14px 0 16px;
    color: var(--cdx-text-dim);
    font-style: italic;
    background:
        linear-gradient(90deg,
            rgba(212, 164, 74, .08) 0,
            rgba(0, 0, 0, .12) 60%,
            rgba(0, 0, 0, .15) 100%);
    border-radius: 0 4px 4px 0;
    box-shadow: inset 0 0 12px rgba(0, 0, 0, .25);
    letter-spacing: .005em;
}
.codex-entry-content blockquote::before,
.codex-page blockquote::before,
.codex-page-inner blockquote::before {
    content: '“';
    position: absolute;
    top: -10px;
    left: 6px;
    font-family: 'Cinzel', serif;
    font-size: 38px;
    color: var(--cdx-gold);
    opacity: .35;
    line-height: 1;
    pointer-events: none;
}
/* Subtle drop-cap on the first letter of the first paragraph inside the
   quote — uses ::first-letter on the inner <p> when present. Falls back
   gracefully when the quote has no <p>. */
.codex-entry-content blockquote p:first-of-type::first-letter,
.codex-page blockquote p:first-of-type::first-letter,
.codex-page-inner blockquote p:first-of-type::first-letter {
    font-family: 'Cinzel', serif;
    font-size: 1.4em;
    color: var(--cdx-gold-bright);
    font-style: normal;
    margin-right: 1px;
    line-height: 1;
}
/* Light theme — switch left rule to wax-seal red, lift wash to parchment. */
body.codex-theme-grimoire-light .codex-entry-content blockquote,
body.codex-theme-grimoire-light .codex-page blockquote,
body.codex-theme-grimoire-light .codex-page-inner blockquote {
    border-left-color: #b53020;
    background:
        linear-gradient(90deg,
            rgba(181, 48, 32, .05) 0,
            rgba(74, 32, 14, .04) 60%,
            rgba(74, 32, 14, .06) 100%);
    color: #5a3a2a;
    box-shadow: inset 0 0 8px rgba(74, 32, 14, .08);
}
body.codex-theme-grimoire-light .codex-entry-content blockquote::before,
body.codex-theme-grimoire-light .codex-page blockquote::before,
body.codex-theme-grimoire-light .codex-page-inner blockquote::before {
    color: #b53020;
    opacity: .4;
}
body.codex-theme-grimoire-light .codex-entry-content blockquote p:first-of-type::first-letter,
body.codex-theme-grimoire-light .codex-page blockquote p:first-of-type::first-letter,
body.codex-theme-grimoire-light .codex-page-inner blockquote p:first-of-type::first-letter {
    color: #6b1a1a;
}
.codex-entry-content h3 {
    font-family: 'Cinzel', serif;
    color: var(--cdx-gold);
    font-size: 16px;
    margin: 18px 0 8px;
}

.codex-entry-related { margin-top: 24px; padding-top: 14px; border-top: 1px solid var(--cdx-rule); }
.codex-entry-related h4 { font-family: 'Cinzel', serif; font-size: 13px; color: var(--cdx-gold); margin: 0 0 8px; }
.codex-related-list { list-style: none; margin: 0; padding: 0; }
.codex-rel, .codex-rel-locked {
    padding: 4px 0;
    font-size: 13px;
    color: var(--cdx-gold-bright);
    cursor: pointer;
    transition: color .14s ease;
}
.codex-rel:hover { color: var(--cdx-ember); }
.codex-rel-locked { color: var(--cdx-text-mute); font-style: italic; cursor: default; }
.codex-rel-locked::before { content: '🔒 '; }

/* Issue 4 (2026-05-10 UAT) — wiki-page links inside the related panel and
   inside entry prose. Real <a href="/codex/entry/{id}"> elements that route
   to the wiki surface (NOT in-book flips). Right-click "Open in new tab" /
   middle-click work because they're real anchors. */
.codex-rel-link {
    color: var(--cdx-gold-bright);
    text-decoration: none;
    transition: color .14s ease;
    display: inline;
}
.codex-rel-link:hover { color: var(--cdx-ember); text-decoration: underline; }
.codex-rel--wiki::before {
    content: '↗ ';
    color: var(--cdx-gold-dim);
    font-size: 11px;
    margin-right: 2px;
}
.codex-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted var(--cdx-gold-dim);
    cursor: pointer;
    transition: color .14s ease, border-color .14s ease;
}
.codex-link strong { color: var(--cdx-gold-bright); }
.codex-link:hover {
    color: var(--cdx-ember);
    border-bottom-color: var(--cdx-ember);
}
.codex-link:hover strong { color: var(--cdx-ember); }

.codex-entry-attribution {
    margin-top: 18px;
    padding-top: 10px;
    border-top: 1px dashed var(--cdx-rule);
    font-size: 11px;
    opacity: .8;
}
.codex-attr-prefix { color: var(--cdx-text-mute); }
.codex-attr-link { color: var(--cdx-gold-bright); text-decoration: underline; }
.codex-attr-tier { color: var(--cdx-text-mute); margin-left: .25rem; font-style: italic; }

/* ============================================================
   17. ISSUE 1 (2026-05-10 HARD FIX) — COVER STATE: DELETE NOT HIDE
   Previous opacity-fade approach left frame artifacts visible
   (leather edges, hash-line patterns, off-center cover card).
   New rule: on cover state, EVERY piece of frame chrome is
   `display: none !important` and the .codex-frame container is
   stripped to a transparent flex-centered host so the cover card
   sits dead-centre. PageFlip's left-page slot (.stf__block:first-child)
   is also display:none so the cover doesn't render in the right half.
   On open state, all rules revert (chrome shows, two-page spread).
   ============================================================ */
body[data-codex-state="cover"] .codex-frame__edge,
body[data-codex-state="cover"] .codex-frame__edge--left,
body[data-codex-state="cover"] .codex-frame__edge--right,
body[data-codex-state="cover"] .codex-frame__spine,
body[data-codex-state="cover"] .codex-frame__spine-glyph,
body[data-codex-state="cover"] .codex-frame__glyph,
body[data-codex-state="cover"] .codex-frame__glyph--tl,
body[data-codex-state="cover"] .codex-frame__glyph--tr,
body[data-codex-state="cover"] .codex-frame__glyph--bl,
body[data-codex-state="cover"] .codex-frame__glyph--br {
    display: none !important;
}
/* Frame container: strip ALL leather chrome on cover. Becomes a
   transparent flex-centered shell so the cover card floats centred. */
body[data-codex-state="cover"] .codex-frame {
    background: transparent !important;
    box-shadow: none !important;
    padding: 0 !important;
    border: none !important;
    border-radius: 0 !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
}
body.codex-theme-grimoire-light[data-codex-state="cover"] .codex-frame,
body.codex-theme-grimoire-dark[data-codex-state="cover"] .codex-frame {
    background: transparent !important;
    box-shadow: none !important;
    border: none !important;
}
/* PageFlip renders the cover into one of two .stf__block spread
   slots. With showCover=true it paints into the right block, leaving
   the left block as an empty leather/paper gap that bleeds frame
   artifacts. Hide the left slot entirely on cover state. */
body[data-codex-state="cover"] .codex-canvas .stf__block:first-child {
    display: none !important;
}
/* Suppress the parchment ruled-line repeat-gradient overlay on cover.
   The hash-line pattern visible to the LEFT of the cover card was the
   .codex-page::before page-rule lines bleeding from the left block. */
body[data-codex-state="cover"] .codex-page::before {
    display: none !important;
}

/* When OPEN, full two-page spread + chrome reappears. Default rules
   (no `display: none` overrides above) take effect because the
   cover-state selectors no longer match. Nothing to do here — the
   absence of the cover-state rule IS the open-state behaviour. */

/* ============================================================
   18. (Reserved — corner glyph positioning superseded by Issue 3
   removal 2026-05-08; rules kept as `display: none` above.)
   ============================================================ */
.codex-frame { overflow: visible; }

/* ============================================================
   18b. (Reserved — Issue 3 polish 2026-05-08 removed the corner
   sigils per user feedback. Block intentionally left blank so
   future canon work can reinstate via display: block here.)
   ============================================================ */

/* ISSUE 2 (2026-05-10 HARD FIX) — disable EnochianParticles entirely
   on the Codex page. The ambient loop spawned img glyphs at
   `rand(5, 95)vw` which produced floating dark-glyph artifacts in
   the top-left corner (visible against the body radial-gradient).
   The codex itself has its own decorative chrome — atmospheric
   particles are redundant and were the source of the artifact.
   The container itself stays clipped as a belt-and-braces guard
   in case any third-party hook re-spawns particles. */
#enochian-particles {
    position: fixed;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
    display: none !important;
}
#enochian-particles .enochian-particle,
#enochian-particles .enochian-burst {
    display: none !important;
}

/* If any fontface fallback inserts orphan Arabic-presentation /
   Enochian-style glyphs into the cursor-light or spell-circle
   layers, they must not escape their parent. */
.cursor-light, .spell-circle { overflow: hidden; }

/* ============================================================
   19. ISSUE 5 — AUTH AVATAR
   Avatar element renders the user's profile image as a
   circular background-image. Falls back to first-letter
   initial when no URL is provided or load fails.
   ============================================================ */
.auth-avatar {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background-color: var(--cdx-leather, #1c1610);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: 'Cinzel', serif;
    font-size: 11px;
    font-weight: 700;
    color: var(--cdx-gold-bright, #f3d8a0);
    border: 1px solid var(--cdx-gold-dim, rgba(212, 164, 74, .35));
    overflow: hidden;
    flex-shrink: 0;
}
.auth-avatar.has-image {
    /* When image is mounted as background, hide any text fallback. */
    color: transparent;
    text-shadow: none;
}
.auth-avatar.is-initial {
    background-image: none !important;
    /* Solid background so the initial letter reads clearly. */
    background-color: var(--cdx-leather-edge, #2a1f16);
}

/* Slightly larger avatar in the toolbar context for clarity. */
.auth-badge .auth-avatar { width: 24px; height: 24px; font-size: 12px; }

/* ============================================================
   20. ISSUE 1 (2026-05-10 HARD FIX) — COVER STATE CANVAS LAYOUT
   The cover card must sit dead-centre with no two-page spread
   layout, no seam, no curl shadow. Section 17 above hides the
   left .stf__block; this section narrows the canvas to cover
   width and kills all PageFlip seam/shadow chrome.
   ============================================================ */
body[data-codex-state="cover"] .codex-canvas {
    /* Narrow the canvas so the single cover card centres in the
       viewport rather than occupying half of a wide spread host. */
    max-width: min(60vw, 460px) !important;
    margin: 0 auto !important;
}
body[data-codex-state="cover"] .codex-canvas .stf__spine,
body[data-codex-state="cover"] .stf__shadow,
body[data-codex-state="cover"] .codex-canvas .stf__shadow,
body[data-codex-state="cover"] .codex-canvas .stf__hard-shadow,
body[data-codex-state="cover"] .codex-canvas .stf__outerShadow,
body[data-codex-state="cover"] .codex-canvas .stf__innerShadow {
    display: none !important;
}
@media (max-width: 1023px) {
    body[data-codex-state="cover"] .codex-canvas {
        max-width: min(80vw, 420px) !important;
    }
}
@media (max-width: 700px) {
    body[data-codex-state="cover"] .codex-canvas {
        max-width: min(88vw, 360px) !important;
    }
}

/* ============================================================
   21. ISSUE 6 (2026-05-08) — SAGA DIVIDER VERTICAL CENTRE
   The divider was anchored too high. Force the inner stack to
   centre vertically with extra top padding to balance optical
   weight of the long ornament rule.
   ============================================================ */
.codex-page--saga .codex-page-inner,
.codex-page--saga {
    display: flex;
    align-items: center;
    justify-content: center;
}
.codex-saga-inner {
    margin-top: 0;
    padding-top: 8%;
    padding-bottom: 8%;
}

/* ============================================================
   22. ISSUE 7 (2026-05-08) — CLOSE-BOOK BUTTON
   Floating button top-right of the canvas — visible only when
   the book is OPEN. Click flips back to the cover (page 0) so
   the native PageFlip cover-flip animation plays.
   ============================================================ */
.codex-close-book {
    position: fixed;
    top: 72px;
    right: 24px;
    z-index: 90;
    width: 38px;
    height: 38px;
    display: none;
    align-items: center;
    justify-content: center;
    background: var(--cdx-tb-bg, rgba(20, 14, 10, .94));
    border: 1px solid var(--cdx-gold-dim, rgba(212, 164, 74, .35));
    border-radius: 50%;
    color: var(--cdx-gold-bright, #f3d8a0);
    font-size: 16px;
    cursor: pointer;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .45);
    transition: transform .14s ease, color .14s ease, border-color .14s ease;
    font-family: 'Cinzel', serif;
    line-height: 1;
}
body[data-codex-state="open"] .codex-close-book { display: inline-flex; }
.codex-close-book:hover {
    color: var(--cdx-ember, #ff7a4a);
    border-color: var(--cdx-ember, #ff7a4a);
    transform: scale(1.06);
}
@media (max-width: 700px) {
    .codex-close-book { top: 64px; right: 12px; width: 34px; height: 34px; font-size: 14px; }
}

/* ============================================================
   23. ISSUE 4 (2026-05-08) — DRAG-EDGE: NO HOVER FLIP
   Earlier rule .book-open:hover .codex-drag-edge { opacity: 1 }
   merely set visibility, but combined with a click handler that
   fired on near-zero drag, plain mouse-over could chain into a
   navigation flip. Lock the edge to require explicit pointerdown
   before any visual feedback / activation.
   ============================================================ */
.codex-drag-edge { pointer-events: auto; }
.codex-drag-edge:not(.is-active):not(.is-dragging) { pointer-events: none; }
/* Hover hint: show via parent's hover-on pseudo only — no event activation. */
.book-open:hover .codex-drag-edge { pointer-events: auto; }

/* ============================================================
   24. ISSUE 9 (2026-05-08) — SEARCHABLE CONTENTS DRAWER
   Adds a search input above the chapter list; rows that don't
   match the typed query collapse to display:none.
   ============================================================ */
.codex-drawer-search {
    position: relative;
    padding: 6px 0 10px;
    border-bottom: 1px solid var(--cdx-rule, rgba(212, 164, 74, .25));
    margin-bottom: 8px;
}
.codex-drawer-search input {
    width: 100%;
    padding: 7px 10px 7px 30px;
    background: rgba(0, 0, 0, .25);
    border: 1px solid var(--cdx-gold-dim, rgba(212, 164, 74, .35));
    border-radius: 4px;
    font-family: 'Rajdhani', system-ui, sans-serif;
    font-size: 13px;
    color: var(--cdx-text, #e8dcc4);
    outline: none;
    transition: border-color .14s ease, box-shadow .14s ease;
}
.codex-drawer-search input:focus {
    border-color: var(--cdx-gold, #d4a44a);
    box-shadow: 0 0 0 1px var(--cdx-gold-dim, rgba(212, 164, 74, .35));
}
.codex-drawer-search::before {
    content: '\f002'; /* fa-search */
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    position: absolute;
    left: 9px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--cdx-text-mute, #7a6a52);
    font-size: 11px;
    pointer-events: none;
}
body.codex-theme-grimoire-light .codex-drawer-search input {
    background: rgba(255, 245, 214, .7);
    color: var(--cdx-text, #2a1f12);
}
.codex-drawer-contents li[hidden],
.codex-drawer-contents .saga-head[hidden] { display: none !important; }

/* ============================================================
   25. ISSUE 3 (2026-05-08) — JUMP MENU LOCKED ITEMS
   Already styled .is-locked but ensure click is fully suppressed
   visually + add a lock icon affordance.
   ============================================================ */
.codex-tb-jump__item.is-locked {
    cursor: not-allowed;
    opacity: .42;
    position: relative;
}
.codex-tb-jump__item.is-locked::after {
    content: '\f023'; /* fa-lock */
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    margin-left: auto;
    font-size: 10px;
    color: var(--cdx-text-mute, #7a6a52);
}

/* ============================================================
   26. ISSUE 5 (2026-05-11 UAT) — COVER → OPEN ANIMATION
   The canvas + host width transition smoothly between the
   centered cover state and the wide two-page spread. Layered
   on top of section 17/20 which set the cover-state widths.
   ============================================================ */
.codex-canvas,
.codex-pageflip-host {
    transition:
        max-width .65s cubic-bezier(.4, 0, .2, 1),
        width .65s cubic-bezier(.4, 0, .2, 1),
        transform .65s cubic-bezier(.4, 0, .2, 1);
}
/* Frame chrome (leather + edges + spine) fades in/out alongside the
   width transition so the chrome doesn't pop into place. */
.codex-frame__edge,
.codex-frame__spine,
.codex-frame {
    transition:
        background-color .55s ease,
        background .55s ease,
        box-shadow .55s ease,
        opacity .55s ease;
}
body[data-codex-state="cover"] .codex-frame__edge,
body[data-codex-state="cover"] .codex-frame__spine {
    opacity: 0;
}
body[data-codex-state="open"] .codex-frame__edge,
body[data-codex-state="open"] .codex-frame__spine {
    opacity: .85;
}

/* ============================================================
   27. ISSUE 3 (2026-05-11 UAT) — CHAPTER TOC GROUPS + WIKI LINKS
   The TOC page now splits entries into "Recorded events" (in-book
   flip targets) and "See also (wiki)" (external entry-page links).
   ============================================================ */
.codex-toc-group-label {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--cdx-gold-dim, rgba(212, 164, 74, .55));
    margin: 16px 0 6px;
    padding-bottom: 3px;
    border-bottom: 1px dotted var(--cdx-rule, rgba(212, 164, 74, .25));
}
.codex-toc-group-label:first-of-type { margin-top: 6px; }
.codex-toc-item--wiki {
    display: flex !important;
    align-items: baseline;
    gap: 10px;
    padding: 8px 6px;
    border-bottom: 1px dashed var(--cdx-rule);
    cursor: pointer;
    color: inherit;
    text-decoration: none;
    transition: background .14s ease, padding-left .14s ease;
}
.codex-toc-item--wiki:hover {
    background: rgba(212, 164, 74, .06);
    padding-left: 12px;
}
.codex-toc-item--wiki::after {
    content: '\f35d'; /* fa-arrow-up-right-from-square */
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    font-size: 9.5px;
    color: var(--cdx-gold-dim, rgba(212, 164, 74, .45));
    margin-left: 4px;
}
.codex-toc-empty {
    margin: 18px 4px 0;
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    color: var(--cdx-text-mute, #7a6a52);
    font-style: italic;
    letter-spacing: .04em;
}
body.codex-theme-grimoire-light .codex-toc-item--wiki:hover {
    background: rgba(138, 36, 24, .06);
}

/* ============================================================
   23. ISSUE (2026-05-11 UAT) — CODEX MARGINALIA PLACEHOLDER
   Rendered when a chapter has no event/codex_self entries. Keeps
   the book visible (cover + saga + intro + TOC + marginalia per
   chapter) before any events have been authored.
   ============================================================ */
.codex-page--marginalia {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.codex-marginalia-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 6% 8%;
}
.codex-marginalia-eyebrow {
    font-family: 'Share Tech Mono', monospace;
    font-size: 12px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--cdx-gold);
}
.codex-marginalia-title {
    font-family: 'Cinzel', serif;
    font-size: 22px;
    font-weight: 700;
    color: var(--cdx-gold-bright);
    margin: 0;
    line-height: 1.25;
    max-width: 86%;
}
.codex-marginalia-rule {
    width: 60px;
    height: 1px;
    background: var(--cdx-gold-dim);
    margin: 2px 0 8px;
}
.codex-marginalia-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-width: 86%;
}
.codex-marginalia-line {
    font-family: 'Cormorant Garamond', 'Garamond', serif;
    font-size: 16px;
    line-height: 1.55;
    color: var(--cdx-text, #d8c8a4);
    font-style: italic;
    margin: 0;
}
.codex-marginalia-sign {
    margin-top: 10px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    color: var(--cdx-text-mute, #7a6a52);
    letter-spacing: .12em;
}

/* ============================================================
   30. CENTERING FIX (2026-05-18) -- root cause of off-center
   pageflip-host. body uses display:flex justify-content:center
   to centre #codex-app. When pageflip is active we hide #codex-app
   via #codex-app{display:none} BUT the wrapper .codex-frame remained
   as an empty second flex item, pushing the host into the LEFT half
   of the body flex row.

   Fix: collapse the entire .codex-frame chrome wrapper when pageflip
   owns the render path. Also force the host to behave as a centered
   flex item with no horizontal stretching.
   ============================================================ */
body[data-codex-pageflip="1"] .codex-frame {
    display: none !important;
}
body[data-codex-pageflip="1"] #codex-pageflip-host {
    flex: 0 0 auto;
    margin-left: auto !important;
    margin-right: auto !important;
}

/* Hide the close-book button in cover state. The default has
   display:none; an explicit rule keeps it from leaking into cover
   if any future state-machine sets it visible. */
body:not([data-codex-state="open"]) .codex-close-book {
    display: none !important;
}

/* Hide the legacy toolbar in cover state too. Toolbar opacity=0 by
   default, becomes 1 only with .is-ready class. Explicit cover-state
   suppression prevents flicker during cover-to-open transition. */
body:not([data-codex-state="open"]) .codex-toolbar:not(.is-ready) {
    opacity: 0 !important;
    pointer-events: none !important;
}
