/* The Curator — museum-catalog design language.
   Paper white, ink black, serif. No gradients, no glass, no rounded cards. */

:root {
  --paper: #f7f4ee;
  --ink: #17140f;
  --dim: #6f6a60;
  --line: #d8d2c6;
  --accent: #8a2f1d; /* dried oxblood — used sparingly */
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: Georgia, 'Times New Roman', serif;
  background: var(--paper);
  color: var(--ink);
  line-height: 1.55;
}

a { color: var(--ink); text-underline-offset: 3px; }
a:hover { color: var(--accent); }

/* ---------- Museum (3D) page ---------- */
.museum-body { overflow: hidden; background: #101010; }
#scene { position: fixed; inset: 0; display: block; }

/* Greeting card floats over the live museum — there is no landing page */
.greeting {
  position: fixed; inset: 0; z-index: 10;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  background: rgba(8, 8, 8, 0.42);
  padding: 1.5rem;
}
.greeting.hidden { display: none; }
.greeting-card {
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 10px 10px 0 rgba(0,0,0,0.5);
  max-width: 560px; width: 100%;
  padding: 2.2rem 2.4rem;
  text-align: center;
}
.greeting-card h1 {
  font-size: clamp(1.6rem, 4.5vw, 2.4rem);
  letter-spacing: 0.22em; font-weight: 400;
  border-bottom: 3px double var(--ink);
  padding-bottom: 0.9rem; margin-bottom: 1.1rem;
}
.greeting-text { font-size: 0.98rem; text-align: left; margin-bottom: 0.9rem; }
.dim-line { color: var(--dim); font-style: italic; font-size: 0.88rem; }
.greeting-actions { margin-top: 1.4rem; display: flex; flex-direction: column; gap: 0.9rem; align-items: center; }
.enter-btn {
  font-family: inherit; font-size: 1rem; letter-spacing: 0.12em;
  background: var(--ink); color: var(--paper);
  border: none; padding: 0.85rem 2.4rem; cursor: pointer;
}
.enter-btn:hover { background: var(--accent); }
.codex-link { font-size: 0.92rem; }
.greeting-nav { margin-top: 1.6rem; display: flex; gap: 1.6rem; justify-content: center; flex-wrap: wrap; }
.greeting-nav a { font-size: 0.85rem; color: var(--dim); }
.greeting-foot { position: absolute; bottom: 0.9rem; font-size: 0.72rem; color: #999; }
.intro-warn { margin-top: 1.2rem; color: var(--accent); }

/* In-museum purchase modal */
.buy-modal {
  position: fixed; inset: 0; z-index: 12;
  background: rgba(8, 8, 8, 0.5);
  display: flex; align-items: center; justify-content: center;
  padding: 1.2rem;
}
.buy-modal[hidden] { display: none; }
.buy-card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 10px 10px 0 rgba(0,0,0,0.5);
  max-width: 480px; width: 100%;
  max-height: 88vh; overflow-y: auto;
  padding: 1.8rem 2rem;
}
.buy-card h2 { margin: 0 0 0.6rem; }
.buy-card .lede { font-size: 0.9rem; margin-bottom: 1.2rem; }
.buy-close {
  position: absolute; top: 0.5rem; right: 0.7rem;
  background: none; border: none; font-size: 1.6rem; cursor: pointer;
  color: var(--ink); padding: 0.2rem;
}
.buy-close:hover { color: var(--accent); }

/* Egg 3's whisper card is built with inline styles in museum.js, and an inline
   `display:flex` beats the UA's `[hidden] { display: none }`. !important is the
   only thing that outranks it, so this is what actually closes the card. */
#whisper-card[hidden] { display: none !important; }

/* Livestream overlays */
/* Operator holding overlay — covers the ENTIRE broadcast frame (above every
   other stream layer) whenever the stream is held or cut. Nothing behind it
   can be seen, so a hold/cut is an absolute visual guarantee. */
.stream-hold {
  position: fixed; inset: 0; z-index: 2147483647; display: none;
  align-items: center; justify-content: center;
  background: #0b0b0d;
}
.stream-hold.on { display: flex; }
.stream-hold.blank { background: #000; }
.stream-hold.blank .stream-hold-card { display: none; }
.stream-hold-card { text-align: center; color: #d8d2c6; font-family: Georgia, serif; user-select: none; }
.stream-hold-mark {
  width: 92px; height: 92px; margin: 0 auto 1.1rem;
  border: 1px solid rgba(216, 210, 198, 0.4); border-radius: 50%;
}
.stream-hold-text { font-size: 1.25rem; letter-spacing: 0.05em; opacity: 0.85; }

/* Admin broadcast control (LIVE / HOLD / CUT) state indicator */
.switches.broadcast { align-items: center; }
.broadcast-label { font-family: Georgia, serif; letter-spacing: 0.08em; margin-right: 0.6rem; }
.broadcast-label .bc-live { color: #3fae5a; }
.broadcast-label .bc-holding { color: #d9a441; }
.broadcast-label .bc-blank { color: #c33b2a; }

#stream-badge {
  position: fixed; top: 1.1rem; left: 1.3rem; z-index: 8;
  font-family: Georgia, serif; font-size: 0.85rem; letter-spacing: 0.14em;
  color: #f2ede2; background: rgba(10, 9, 7, 0.55);
  border: 1px solid rgba(242, 237, 226, 0.35);
  padding: 0.4rem 0.9rem;
}
#stream-badge::first-letter { color: #c33b2a; }
#stream-panel {
  /* CUT-OFF FIX 2026-07-24: this was a fixed box centred with translateY(-55%)
     and NO height bound, so once the reward card + larger type were added the
     content grew past the viewport and clipped at BOTH ends. It is now a flex
     column anchored inside a safe area with a hard max-height, so every line
     stays on screen at any stream size. */
  position: fixed; left: 1.4rem; top: 50%; transform: translateY(-50%);
  z-index: 8; width: clamp(280px, 26vw, 430px);
  max-height: calc(100vh - 12vh);       /* safe area: clears badge + captions */
  display: flex; flex-direction: column; gap: 0.2rem;
  overflow: hidden;                      /* never paint outside the frame */
  font-family: Georgia, serif;
  font-size: clamp(0.86rem, 0.95vw + 0.34rem, 1.12rem);
  line-height: 1.5;
  color: #f2ede2; background: rgba(10, 9, 7, 0.66);
  border: 1px solid rgba(242, 237, 226, 0.3);
  padding: clamp(0.7rem, 1.1vh, 1.3rem) clamp(0.9rem, 1.1vw, 1.5rem);
}
#stream-panel p { margin: 0.25rem 0 0.7rem; }
#stream-panel .sp-title {
  font-size: 0.88rem; letter-spacing: 0.2em; color: #c9b98f;
  border-bottom: 1px solid rgba(242, 237, 226, 0.2);
  padding-bottom: 0.3rem; margin-bottom: 0.45rem;
}
#stream-panel .sp-dim { color: rgba(242, 237, 226, 0.65); font-style: italic; margin-bottom: 0; }
#stream-caption {
  /* His placard: near-black panel, a thin blood-crimson rule, words surfacing
     out of the dark as he speaks them. Text-only — no rubric. (bottom 4.5vh:
     clears the 16vh unmute button even at 720p.) */
  position: fixed; left: 50%; bottom: 4.5vh; transform: translateX(-50%);
  z-index: 8; width: min(760px, 88vw);
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 1.42rem; line-height: 1.55; letter-spacing: 0.05em;
  color: #e6dcc8; background: rgba(6, 4, 3, 0.88);
  border: 1px solid rgba(140, 20, 20, 0.5);
  box-shadow: 0 0 26px rgba(110, 8, 8, 0.3), 0 0 72px rgba(70, 0, 0, 0.22);
  padding: 1.2rem 1.8rem; white-space: pre-wrap; text-align: center;
  transition: opacity 1.6s;
}
#stream-caption.fade { opacity: 0; }
/* Playback hasn't started yet (autoplay blocked / loading): keep the whole
   panel invisible rather than showing an empty black box — it appears the
   moment the voice does. */
#stream-caption.awaiting { visibility: hidden; }
#stream-caption .cap-word { transition: opacity 0.25s; }
/* Unspoken words are fully INVISIBLE (they still hold their space, so the
   box never reflows) — each word appears only at the moment he says it. */
#stream-caption .cap-word.pending { opacity: 0; }
#stream-caption .cap-word.spoken {
  opacity: 1;
  text-shadow: 0 0 9px rgba(120, 10, 10, 0.55);
}
#stream-unmute {
  /* Unmissable: the browser blocked autoplay and the performance is running
     silently — this is the viewer's one required click (sticky for the whole
     session). Bottom-center, above the captions. */
  position: fixed; left: 50%; bottom: 16vh; transform: translateX(-50%);
  z-index: 10;
  font-family: Georgia, serif; font-size: 1.05rem; letter-spacing: 0.04em;
  background: #f2ede2; color: #17140f; border: 2px solid #17140f;
  padding: 0.75rem 1.6rem; cursor: pointer; border-radius: 2px;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.55);
  animation: unmute-pulse 1.8s ease-in-out infinite;
}
@keyframes unmute-pulse {
  0%, 100% { transform: translateX(-50%) scale(1); }
  50% { transform: translateX(-50%) scale(1.06); }
}

.resume-chip {
  position: fixed; top: 1rem; left: 50%; transform: translateX(-50%);
  z-index: 9;
  font-family: Georgia, serif; font-size: 0.85rem;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--ink); padding: 0.5rem 1.1rem; cursor: pointer;
}
.resume-chip:hover { background: var(--accent); color: var(--paper); }

.greeting-avatar {
  width: 108px; height: 108px; object-fit: cover; object-position: center 20%;
  border: 2px solid var(--ink); border-radius: 50%;
  margin: -3.6rem auto 0.9rem; display: block;
  background: #f2e9da;
}
.codex-portrait {
  width: 200px; display: block; margin: 0 auto 1.4rem;
  border: 1px solid var(--line); background: #f2e9da;
}
.codex h2 { margin-top: 2.2rem; }
.codex ul { margin: 0.8rem 0 0.8rem 1.4rem; }
.codex li { margin-bottom: 0.6rem; }
.codex-close { text-align: center; margin-top: 3rem; letter-spacing: 0.06em; }
.theses { margin: 0.8rem 0 0.8rem 1.6rem; }
.theses li { margin-bottom: 0.9rem; }
.thesis-prior { display: block; color: var(--dim); opacity: 0.65; font-size: 0.88em; }
.thesis-body { display: block; }

#crosshair {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  color: #f7f4ee; font-size: 28px; z-index: 5; pointer-events: none;
  text-shadow: 0 0 3px rgba(0,0,0,0.8);
}

.plaque {
  position: fixed; left: 50%; bottom: 6vh; transform: translateX(-50%);
  z-index: 6; width: min(480px, 86vw);
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--ink);
  padding: 1rem 1.3rem;
  box-shadow: 4px 4px 0 rgba(0,0,0,0.55);
}
.plaque-title { font-variant: small-caps; letter-spacing: 0.06em; font-size: 1.05rem; }
.plaque-meta { font-size: 0.78rem; color: var(--dim); margin-top: 0.15rem; letter-spacing: 0.04em; }
.plaque-text { font-style: italic; font-size: 0.9rem; margin-top: 0.5rem; }

/* ---------- Flat pages ---------- */
.page-body { min-height: 100vh; display: flex; flex-direction: column; }

.page-head {
  display: flex; align-items: baseline; gap: 2rem; flex-wrap: wrap;
  padding: 1.2rem 2rem; border-bottom: 1px solid var(--ink);
}
.wordmark { letter-spacing: 0.22em; text-decoration: none; font-size: 1.05rem; }
.page-head nav { display: flex; gap: 1.4rem; margin-left: auto; }
.page-head nav a { font-size: 0.9rem; text-decoration: none; border-bottom: 1px solid transparent; }
.page-head nav a:hover { border-bottom-color: var(--accent); }

main.narrow { max-width: 640px; margin: 0 auto; padding: 3rem 1.5rem; width: 100%; }
main.center { text-align: center; padding-top: 18vh; }
.lede { font-style: italic; color: var(--dim); margin: 1rem 0 2rem; }

h1 { font-weight: 400; font-size: 1.9rem; letter-spacing: 0.04em; }
h2 { font-weight: 400; font-size: 1.25rem; margin: 2rem 0 0.8rem; font-variant: small-caps; letter-spacing: 0.08em; }

.page-foot {
  margin-top: auto; padding: 1.2rem 2rem; border-top: 1px solid var(--line);
  display: flex; gap: 2rem; font-size: 0.78rem; color: var(--dim);
}
.ca { font-family: 'Courier New', monospace; word-break: break-all; }
.ca-block code { display: block; margin-top: 0.5rem; font-size: 0.85rem; word-break: break-all; }

/* Catalog grid */
.catalog { padding: 2rem; }
.wing-section h2 { border-bottom: 1px solid var(--ink); padding-bottom: 0.4rem; }
.wing-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 1.6rem; margin: 1.4rem 0 3rem; }
.work img { width: 100%; display: block; border: 6px solid var(--ink); }
.work figcaption { margin-top: 0.5rem; display: flex; flex-direction: column; font-size: 0.82rem; }
.work-no { color: var(--dim); font-size: 0.72rem; letter-spacing: 0.08em; }
.work-title { font-variant: small-caps; }
.work-emotion { color: var(--dim); font-style: italic; }
.work-plaque { margin-top: 0.3rem; font-style: italic; color: var(--dim); }
.empty-frame {
  aspect-ratio: 1; border: 2px dashed var(--line);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  color: var(--dim); letter-spacing: 0.14em; font-size: 0.8rem; gap: 0.4rem;
}
.empty-frame .price { font-size: 1rem; color: var(--ink); }

/* Forms */
form label { display: block; margin-bottom: 1.1rem; font-size: 0.95rem; }
form input[type="text"], form input[type="password"], form textarea, form select, form input:not([type]) {
  display: block; width: 100%; margin-top: 0.35rem;
  font-family: inherit; font-size: 0.95rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--ink); background: #fffdf9; color: var(--ink);
}
form input[type="file"] { margin-top: 0.4rem; }
form button {
  font-family: inherit; font-size: 0.95rem; letter-spacing: 0.06em;
  background: var(--ink); color: var(--paper); border: none;
  padding: 0.7rem 1.8rem; cursor: pointer;
}
form button:hover { background: var(--accent); }
.req { color: var(--accent); font-size: 0.75rem; }
.opt { color: var(--dim); font-size: 0.75rem; }
.submit-result { margin-top: 1rem; font-style: italic; }
.error { color: var(--accent); margin-top: 0.8rem; }

/* ---------- Admin ---------- */
.admin { background: #f1ede4; }
.admin-head { background: var(--ink); }
.admin-head a, .admin-head .wordmark { color: var(--paper); }
.admin-head .linkish { background: none; border: none; color: var(--paper); font-family: inherit; cursor: pointer; padding: 0; font-size: 0.9rem; text-decoration: underline; }
.admin-main { padding: 1.6rem 2rem; max-width: 1100px; margin: 0 auto; width: 100%; }
.admin-main.narrow { max-width: 640px; }

.switches { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.4rem; }
.switch { font-size: 0.9rem !important; padding: 0.8rem 1.4rem !important; border: 2px solid var(--ink) !important; background: var(--paper) !important; color: var(--ink) !important; }
.switch.on.danger, button.danger { background: var(--accent) !important; color: var(--paper) !important; border-color: var(--accent) !important; }
.switch.on.safe, button.safe { background: #2c5f2d !important; color: var(--paper) !important; border-color: #2c5f2d !important; }

.stat-row { display: flex; gap: 1.6rem; flex-wrap: wrap; margin: 1rem 0 1.5rem; }
.stat { display: flex; flex-direction: column; align-items: center; border: 1px solid var(--line); padding: 0.6rem 1rem; background: var(--paper); min-width: 90px; }
.stat b { font-size: 1.4rem; }
.stat span { font-size: 0.72rem; color: var(--dim); letter-spacing: 0.05em; }

.config-form label { display: inline-block; margin-right: 1.4rem; }
.config-form input, .config-form select { width: auto; display: block; }
.config-form button { margin-top: 0.5rem; display: block; }

.table { width: 100%; border-collapse: collapse; font-size: 0.82rem; background: var(--paper); }
.table td { border-bottom: 1px solid var(--line); padding: 0.4rem 0.6rem; vertical-align: top; }
.lvl-warn td { color: #8a6d1d; }
.lvl-error td { color: var(--accent); }
.dim { color: var(--dim); }
.hint { font-size: 0.85rem; color: var(--dim); font-style: italic; margin-bottom: 1rem; }

.mod-card { display: flex; gap: 1rem; background: var(--paper); border: 1px solid var(--line); padding: 0.9rem; margin-bottom: 0.9rem; }
.mod-card img { width: 120px; height: 120px; object-fit: cover; border: 3px solid var(--ink); }
.mod-info { display: flex; flex-direction: column; gap: 0.3rem; flex: 1; }
.mod-actions { display: flex; gap: 0.8rem; align-items: center; margin-top: auto; flex-wrap: wrap; }
.mod-actions input { display: inline-block; width: auto; margin: 0 0.4rem 0 0; padding: 0.4rem; }
.inline { display: inline; }
.btn { display: inline-block; background: var(--ink); color: var(--paper); padding: 0.5rem 1rem; text-decoration: none; font-size: 0.9rem; }
.plaque-preview { font-style: italic; font-size: 0.88rem; color: var(--dim); }
.hang-preview { max-width: 320px; border: 4px solid var(--ink); margin-bottom: 1rem; }

.post-card { background: var(--paper); border: 1px solid var(--line); padding: 0.9rem; margin-bottom: 0.9rem; }
.post-body { font-size: 1rem; margin: 0.4rem 0; white-space: pre-wrap; }
.post-img { max-width: 220px; border: 3px solid var(--ink); display: block; margin: 0.5rem 0; }
.post-cell { max-width: 480px; }
.login-form { max-width: 320px; margin: 2rem auto 0; text-align: left; }

@media (max-width: 640px) {
  .page-head { padding: 1rem; gap: 1rem; }
  .admin-main, .catalog { padding: 1rem; }
  .mod-card { flex-direction: column; }
}

/* ---------- Lore book (the tome on the podium) ----------
   Not the paper-white modal language: an aged parchment spread inside a dark
   leather binding, over the dimmed museum. Markup built by
   public/js/book/lore-book.js. */

.book-overlay {
  position: fixed; inset: 0; z-index: 14;
  display: flex; align-items: center; justify-content: center;
  padding: 2.5vh 2vw;
  opacity: 0; transition: opacity 0.3s ease;
}
.book-overlay.open { opacity: 1; }
.book-overlay[hidden] { display: none; }
.book-backdrop {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at center, rgba(10, 7, 4, 0.52), rgba(4, 3, 2, 0.82));
}

/* The binding: near-black leather, one worn gold rule at its lip */
.book-frame {
  position: relative;
  width: min(1080px, 94vw);
  height: min(680px, 88vh);
  padding: clamp(12px, 2vw, 24px);
  background: linear-gradient(135deg, #241a12, #150f0a 55%, #1f1610);
  border: 1px solid #0b0705;
  border-radius: 4px;
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.65),
    inset 0 0 0 1px rgba(150, 120, 64, 0.24),
    inset 0 0 24px rgba(0, 0, 0, 0.8);
  display: flex; flex-direction: column;
}
.book-close {
  position: absolute; top: 0; right: 6px; z-index: 3;
  background: none; border: none; cursor: pointer;
  font-family: Georgia, serif; font-size: 1.15rem; line-height: 1;
  color: rgba(190, 158, 94, 0.65); padding: 0.45rem 0.55rem;
}
.book-close:hover { color: #dfc17e; }

.book-well { position: relative; flex: 1; min-height: 0; }

/* The parchment: warm ground, faint foxing and stains, a center gutter */
.book-spread {
  position: relative; height: 100%; overflow-y: auto;
  padding: 2.4rem 3rem 3.4rem;
  background:
    radial-gradient(ellipse at 18% 10%, rgba(255, 246, 222, 0.5), transparent 55%),
    radial-gradient(ellipse at 84% 90%, rgba(120, 92, 48, 0.16), transparent 52%),
    radial-gradient(circle at 71% 24%, rgba(139, 109, 61, 0.10), transparent 18%),
    radial-gradient(circle at 29% 79%, rgba(122, 90, 43, 0.09), transparent 14%),
    radial-gradient(circle at 55% 58%, rgba(101, 79, 40, 0.07), transparent 10%),
    radial-gradient(circle at 12% 46%, rgba(122, 90, 43, 0.06), transparent 9%),
    linear-gradient(115deg, #e6d9b8 0%, #dfd0aa 45%, #d6c69d 100%);
  box-shadow: inset 0 0 58px rgba(90, 70, 40, 0.30);
}
/* the spine shadow between the two leaves (desktop spread only) */
.book-spread::before {
  content: ''; position: absolute; top: 1.5%; bottom: 1.5%; left: 50%;
  width: 74px; transform: translateX(-50%); pointer-events: none;
  background: linear-gradient(90deg,
    transparent, rgba(70, 52, 26, 0.14) 40%, rgba(48, 34, 15, 0.26) 50%,
    rgba(70, 52, 26, 0.14) 60%, transparent);
}

/* ornamental corners — restrained double line with a small boss */
.book-flourish {
  position: absolute; width: 52px; height: 52px; pointer-events: none;
  background-repeat: no-repeat; background-size: 52px 52px; opacity: 0.75;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56'%3E%3Cg fill='none' stroke='%237a6432' stroke-opacity='.5'%3E%3Cpath d='M3 53 V12 Q3 3 12 3 H53' stroke-width='1.5'/%3E%3Cpath d='M9 53 V17 Q9 9 17 9 H53' stroke-width='.8'/%3E%3Ccircle cx='13.5' cy='13.5' r='2.3'/%3E%3C/g%3E%3C/svg%3E");
}
.fl-tl { top: 9px; left: 10px; }
.fl-tr { top: 9px; right: 10px; transform: scaleX(-1); }
.fl-bl { bottom: 9px; left: 10px; transform: scaleY(-1); }
.fl-br { bottom: 9px; right: 10px; transform: scale(-1, -1); }

/* running head: the volume's own title, small and worn */
.book-head {
  text-align: center; font-variant: small-caps;
  letter-spacing: 0.34em; font-size: 0.72rem;
  color: rgba(100, 80, 42, 0.72);
  margin-bottom: 1.4rem;
}

/* the page content flows as a two-leaf spread via columns; the gutter above
   sits in the column gap. Narrow viewports read a single leaf. */
.book-page {
  column-count: 2; column-gap: 5.6rem;
  transition: opacity 0.125s ease, transform 0.125s ease;
  transform-origin: 50% 50%;
}
.book-page.turn-out-next { opacity: 0; transform: perspective(1200px) rotateY(-6deg); }
.book-page.turn-out-prev { opacity: 0; transform: perspective(1200px) rotateY(6deg); }
.book-page.turn-in-next { opacity: 0; transform: perspective(1200px) rotateY(6deg); transition: none; }
.book-page.turn-in-prev { opacity: 0; transform: perspective(1200px) rotateY(-6deg); transition: none; }

.book-title {
  font-weight: 400; font-variant: small-caps;
  letter-spacing: 0.14em; font-size: 1.3rem;
  color: #7c6329; text-shadow: 0 1px 0 rgba(255, 244, 214, 0.4);
  border-bottom: 1px solid rgba(124, 99, 41, 0.45);
  padding-bottom: 0.45rem; margin: 0 0 1rem;
}
.book-body { color: #33291a; font-size: 1.02rem; line-height: 1.72; }
.book-body p { margin-bottom: 0.9rem; text-align: justify; hyphens: auto; }
/* (no drop cap: the record is written all-lowercase, and a floated initial
   splits its first word — "t here".) */

/* the final page's action, set as an inscription rather than a button */
.book-inscription { margin-top: 1.8rem; text-align: center; break-inside: avoid; }
.book-replay {
  display: inline-block; text-decoration: none;
  font-variant: small-caps; letter-spacing: 0.2em; font-size: 0.95rem;
  color: #6d572a;
  border-top: 1px solid rgba(109, 87, 42, 0.55);
  border-bottom: 1px solid rgba(109, 87, 42, 0.55);
  padding: 0.55rem 1.3rem;
}
.book-replay:hover { color: var(--accent); border-color: rgba(138, 47, 29, 0.6); }

/* page corner controls + the indicator sit over the parchment, outside the
   scrolling flow */
.book-corner {
  position: absolute; bottom: 2px; z-index: 2;
  width: 54px; height: 54px; border: none; cursor: pointer;
  font-family: Georgia, serif; font-size: 2.1rem; line-height: 1;
  color: rgba(90, 72, 38, 0.7); background: none; padding: 0;
}
.book-corner-prev {
  left: 2px;
  background: linear-gradient(135deg, rgba(120, 95, 50, 0.22) 0%, rgba(120, 95, 50, 0.07) 34%, transparent 36%);
}
.book-corner-next {
  right: 2px;
  background: linear-gradient(225deg, rgba(120, 95, 50, 0.22) 0%, rgba(120, 95, 50, 0.07) 34%, transparent 36%);
}
.book-corner:hover { color: var(--accent); }
.book-corner[disabled] { opacity: 0.22; cursor: default; }
.book-corner[disabled]:hover { color: rgba(90, 72, 38, 0.7); }
.book-indicator {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  z-index: 2; pointer-events: none;
  font-variant: small-caps; letter-spacing: 0.3em; font-size: 0.8rem;
  color: rgba(90, 72, 38, 0.85);
}

@media (max-width: 980px) {
  .book-page { column-count: 1; }
  .book-spread { padding: 1.8rem 2rem 3.4rem; }
  .book-spread::before { display: none; }
}

/* ---------- walk-mode speech (features-v3.1) ---------- */

/* The visitor page reads him in a flowing paragraph — spoken lines
   accumulate into one block (the stream keeps its one-line lower third).
   Same ominous panel; left-set type reads better at paragraph length. */
#stream-caption.paragraph {
  width: min(46rem, 86vw);
  text-align: left;
  line-height: 1.7;
  font-size: 1.22rem;
  max-height: 32vh;
  overflow: hidden;
}

/* The speak affordance: a small chip under the crosshair when the figure is
   within speaking distance — parchment key glyph on the museum's dark field. */
#talk-hint {
  position: fixed; top: 56%; left: 50%; transform: translateX(-50%);
  z-index: 6; pointer-events: none;
  font-family: Georgia, 'Times New Roman', serif;
  font-variant: small-caps; letter-spacing: 0.14em; font-size: 0.92rem;
  color: #d8cdb4; background: rgba(6, 4, 3, 0.82);
  border: 1px solid rgba(158, 124, 58, 0.55);
  padding: 0.32rem 0.7rem;
  box-shadow: 0 0 18px rgba(0, 0, 0, 0.5);
}
#talk-hint .talk-key {
  display: inline-block; margin-right: 0.55em;
  padding: 0 0.42em; border: 1px solid #9e7c3a; border-radius: 2px;
  color: #f2ede2; background: rgba(158, 124, 58, 0.25);
  font-variant: normal; font-size: 0.88rem;
}

/* ---------- detached top bar (walk page only) ---------- */

#top-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 12;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.5rem 1.2rem;
  font-family: Georgia, 'Times New Roman', serif;
  color: #d8cdb4; background: rgba(6, 4, 3, 0.86);
  border-bottom: 1px solid rgba(158, 124, 58, 0.45);
}
#top-bar .tb-wordmark {
  font-variant: small-caps; letter-spacing: 0.32em; font-size: 0.95rem;
}
#tb-settings-btn {
  font-family: inherit; font-variant: small-caps; letter-spacing: 0.14em;
  font-size: 0.9rem; color: #d8cdb4; background: none;
  border: 1px solid rgba(158, 124, 58, 0.55); border-radius: 2px;
  padding: 0.28rem 0.85rem; cursor: pointer;
}
#tb-settings-btn:hover { background: rgba(158, 124, 58, 0.18); }
#tb-panel {
  position: absolute; top: calc(100% + 6px); right: 1.2rem;
  min-width: 15.5rem;
  background: rgba(6, 4, 3, 0.94);
  border: 1px solid rgba(158, 124, 58, 0.55);
  padding: 0.9rem 1.1rem;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.6);
}
#tb-panel .tb-section { margin-bottom: 0.85rem; }
#tb-panel .tb-section:last-child { margin-bottom: 0; }
#tb-panel .tb-label {
  display: block; font-variant: small-caps; letter-spacing: 0.18em;
  font-size: 0.8rem; color: #9e8a5e; margin-bottom: 0.35rem;
}
#tb-music { width: 100%; accent-color: #9e7c3a; }
#tb-connect {
  font-family: inherit; font-size: 0.88rem; letter-spacing: 0.05em;
  color: #f2ede2; background: rgba(158, 124, 58, 0.22);
  border: 1px solid #9e7c3a; border-radius: 2px;
  padding: 0.32rem 0.8rem; cursor: pointer;
}
#tb-connect:hover { background: rgba(158, 124, 58, 0.34); }
#tb-panel .tb-status { display: block; margin-top: 0.4rem; font-size: 0.8rem; color: #b9ab8c; }

/* ---------- the keys (/keys) + the unnumbered room ---------- */
.keyrow { display: flex; gap: 2.6rem; justify-content: center; margin: 2.4rem 0 0.6rem; }
.keyhole { text-align: center; }
.keyhole-glyph { width: 64px; height: 104px; margin: 0 auto 0.7rem; position: relative; opacity: 0.5; }
.keyhole-glyph::before {
  content: ''; position: absolute; left: 50%; top: 6px; transform: translateX(-50%);
  width: 36px; height: 36px; border-radius: 50%; border: 3px solid #6b5a2e; background: #0d0a08;
}
.keyhole-glyph::after {
  content: ''; position: absolute; left: 50%; top: 40px; transform: translateX(-50%);
  width: 0; height: 0;
  border-left: 13px solid transparent; border-right: 13px solid transparent;
  border-bottom: 54px solid #6b5a2e;
}
.keyhole.found .keyhole-glyph { opacity: 1; }
.keyhole.found .keyhole-glyph::before {
  border-color: #d42424; background: #2a0808;
  box-shadow: 0 0 22px rgba(212, 36, 36, 0.55);
}
.keyhole.found .keyhole-glyph::after { border-bottom-color: #d42424; }
.keyhole-label {
  font-variant: small-caps; letter-spacing: 0.16em; font-size: 0.8rem; color: #9e8a5e;
}
.keyhole-holder { font-variant: normal; letter-spacing: 0.02em; font-style: italic; color: #b9ab8c; }
.keys-count { text-align: center; letter-spacing: 0.06em; }

.vault-body { background: #060504; }
.vault { padding-top: 22vh; text-align: center; }
.vault .dim-line { margin: 0.9rem 0; }
.vault-sentence {
  margin: 2.4rem 0; font-family: Georgia, serif; font-size: 1.5rem; color: #d42424;
  text-shadow: 0 0 22px rgba(212, 36, 36, 0.5); letter-spacing: 0.04em;
}
.marginalia { list-style: none; margin: 0.8rem 0 0 0; padding: 0; }
.marginalia li { margin-bottom: 0.28rem; font-style: italic; color: #b9ab8c; font-size: 0.95rem; }

/* keys v2: unlaunched keys + paid hands */
.keyhole.veiled .keyhole-glyph { opacity: 0.18; }
.keyhole.veiled .keyhole-label { color: #5d553f; }
.keyhole-holders { margin-top: 0.5rem; font-size: 0.78rem; color: #b9ab8c; font-style: italic; line-height: 1.5; }

/* ---- The loading experience (perf 2026-07-24) ------------------------------
   Full-frame, paints on first HTML parse (visible by default), cross-fades out
   when the scene is interactive. Greek/Vatican register: a rotunda in warm gilt
   line on a candlelit dark ground. Everything here is CSS/SVG — no asset load. */
.loading {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(120% 90% at 50% 38%, #1c1712 0%, #100d0a 55%, #080706 100%);
  color: #e7dcc4; font-family: Georgia, 'Times New Roman', serif;
  opacity: 1; transition: opacity 620ms ease;
}
.loading.gone { opacity: 0; pointer-events: none; }
.loading[hidden] { display: none; }
.loading-inner { width: min(88vw, 360px); text-align: center; }
.loading-rotunda { width: 240px; max-width: 70vw; height: auto; margin: 0 auto 1.4rem; display: block; overflow: visible; }
.loading-rotunda .lr-dome { fill: rgba(201, 178, 120, 0.06); stroke: #c9b278; stroke-width: 1.4; }
.loading-rotunda .lr-arch, .loading-rotunda .lr-base { fill: #c9b278; opacity: 0.85; }
.loading-rotunda .lr-cols line { stroke: #c9b278; stroke-width: 3.2; opacity: 0.8; }
.loading-rotunda .lr-finial { stroke: #c9b278; stroke-width: 1.6; }
.loading-rotunda .lr-dome, .loading-rotunda .lr-cols { animation: lr-breathe 4.2s ease-in-out infinite; }
.loading-rotunda .lr-sweep {
  fill: #fff; opacity: 0.06; filter: blur(6px);
  transform-box: view-box; transform-origin: center;
  animation: lr-sweep 3.6s ease-in-out infinite;
}
.loading-word { font-size: 1.05rem; letter-spacing: 0.42em; padding-left: 0.42em; color: #efe6d0; }
.loading-stage {
  margin-top: 0.7rem; font-size: 0.9rem; font-style: italic; color: #b6a988;
  min-height: 1.3em; transition: opacity 260ms ease;
}
.loading-track {
  margin: 1.3rem auto 0; width: 210px; max-width: 62vw; height: 2px;
  background: rgba(201, 178, 120, 0.16); border-radius: 2px; overflow: hidden;
}
.loading-bar {
  height: 100%; width: 4%; border-radius: 2px;
  background: linear-gradient(90deg, #8a2f1d, #c9b278);
  transition: width 480ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.loading-error { margin-top: 1.6rem; display: flex; flex-direction: column; gap: 0.8rem; align-items: center; }
.loading-error[hidden] { display: none; } /* class display: must not override the hidden attribute */
.loading-error p { color: #b6a988; font-style: italic; font-size: 0.92rem; margin: 0; }
.loading-error .codex-link { color: #b6a988; font-size: 0.85rem; }

@keyframes lr-breathe { 0%, 100% { opacity: 0.72; } 50% { opacity: 1; } }
@keyframes lr-sweep {
  0% { transform: translateX(-90px); opacity: 0; }
  35% { opacity: 0.09; }
  70% { transform: translateX(150px); opacity: 0; }
  100% { transform: translateX(150px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .loading-rotunda .lr-dome, .loading-rotunda .lr-cols, .loading-rotunda .lr-sweep { animation: none; }
  .loading-rotunda .lr-sweep { display: none; }
  .loading-bar { transition: none; }
}

/* ---- Key Finder Leaderboard (2026-07-24) ---------------------------------- */
/* Livestream overlay: top-right, clear of the caption (bottom), the mission
   panel (left), and the featured artwork (centre). Lightweight, no WebGL. */
#stream-leaderboard {
  position: fixed; top: 84px; right: 26px; z-index: 40;
  width: min(24vw, 300px); max-height: 44vh; overflow: hidden;
  background: rgba(10, 9, 7, 0.62); color: #e9dfc8;
  border: 1px solid rgba(201, 178, 120, 0.4); border-radius: 4px;
  padding: 0.7rem 0.9rem; font-family: Georgia, serif; backdrop-filter: blur(3px);
}
#stream-leaderboard[hidden] { display: none; }
.slb-title { font-size: 0.82rem; letter-spacing: 0.26em; color: #c9b278; margin-bottom: 0.5rem; }
.slb-list { list-style: none; margin: 0; padding: 0; }
.slb-list li { display: flex; gap: 0.5rem; align-items: baseline; font-size: 0.86rem; padding: 0.14rem 0; }
.slb-list li .slb-rank { color: #c9b278; min-width: 1.2rem; }
.slb-list li .slb-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slb-list li .slb-time { color: #b6a988; font-variant-numeric: tabular-nums; }
.slb-foot { margin-top: 0.5rem; font-size: 0.72rem; color: #a99; opacity: 0.85; }

/* Museum Hall of Finders modal (DOM overlay, escaped text). */
.finders-card { max-width: 640px; text-align: left; }
.finders-state { color: #6f6a60; font-style: italic; margin: 1rem 0; }
.finders-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.finders-table th { text-align: left; border-bottom: 1px solid var(--line); padding: 0.35rem 0.4rem; color: #6f6a60; font-weight: normal; }
.finders-table td { padding: 0.35rem 0.4rem; border-bottom: 1px solid #eee7d8; }
.finders-table td.rank { color: var(--accent); font-weight: 600; }
.finders-table td.time { font-variant-numeric: tabular-nums; }
.finders-copy { background: none; border: 1px solid var(--line); border-radius: 2px; cursor: pointer; font-size: 0.72rem; padding: 0 0.3rem; margin-left: 0.3rem; }
.finders-you { margin-top: 1rem; padding: 0.6rem 0.8rem; background: #f3efe4; border-left: 3px solid var(--accent); font-size: 0.9rem; }
.finders-more { margin-top: 0.9rem; text-align: center; }
.finders-legacy { margin-top: 1.2rem; padding-top: 0.8rem; border-top: 1px dashed var(--line); font-size: 0.82rem; color: #6f6a60; }
.finders-legacy h3 { font-size: 0.9rem; margin: 0 0 0.4rem; color: var(--ink); }

/* ---- Real hidden-key reward + redesigned livestream panel (2026-07-24) ---- */
/* Entrance plaque: 50% is the largest thing on the card. */
.reward-plaque {
  margin: 1.4rem 0 0.4rem; padding: 1rem 1.1rem; text-align: center;
  border: 2px solid var(--accent); background: #f3ede0;
}
.rp-kicker { font-size: 0.78rem; letter-spacing: 0.22em; color: var(--accent); }
.rp-pct { font-size: 3.6rem; line-height: 1.05; font-weight: 700; color: var(--accent); }
.rp-of { font-size: 0.95rem; letter-spacing: 0.06em; }
.rp-to { font-size: 0.86rem; color: var(--dim); font-style: italic; margin-top: 0.2rem; }
.rp-real { font-size: 0.8rem; color: var(--ink); margin-top: 0.5rem; }

/* Livestream information panel — larger type, clear hierarchy, OBS-readable. */
#stream-panel .sp-lede { font-size: 1.08em; color: #f6f1e6; margin-bottom: 0.6rem; }
#stream-panel .sp-real { color: #e9b44c; font-weight: 600; margin-bottom: 0.7rem; }
.sp-reward {
  margin: 0.6rem 0 0.7rem; padding: clamp(0.5rem, 1vh, 0.9rem) 1rem; flex: 0 0 auto; text-align: center;
  border: 2px solid #8a2f1d; background: rgba(138, 47, 29, 0.28);
}
.sp-reward-kicker { font-size: 0.82rem; letter-spacing: 0.26em; color: #e9b44c; }
.sp-reward-pct { font-size: clamp(2.4rem, 4.4vh, 4rem); line-height: 1.02; font-weight: 700; color: #ffd873; }
.sp-reward-of { font-size: 1rem; letter-spacing: 0.08em; color: #f2ede2; }
.sp-reward-to { font-size: 0.86rem; color: #c9b98f; margin-top: 0.25rem; }

/* Livestream leaderboard — bigger, still clear of caption/artwork. */
#stream-leaderboard { width: min(28vw, 360px); max-height: 52vh; padding: 0.9rem 1.1rem; }
.slb-title { font-size: 0.92rem; letter-spacing: 0.2em; }
.slb-reward {
  font-size: 0.82rem; color: #ffd873; letter-spacing: 0.04em;
  border-top: 1px solid rgba(201,178,120,0.3); border-bottom: 1px solid rgba(201,178,120,0.3);
  padding: 0.34rem 0; margin-bottom: 0.5rem; text-align: center;
}
.slb-reward b { font-size: 1.15rem; color: #ffd873; }
.slb-list li { font-size: 0.98rem; padding: 0.2rem 0; }

@media (max-width: 1500px) {
  #stream-panel { width: min(400px, 34vw); font-size: 1.04rem; }
  .sp-reward-pct { font-size: 3.2rem; }
  #stream-leaderboard { width: min(30vw, 300px); }
}

/* Introduction image inside the loading overlay (2026-07-24). The SAME asset the
   greeting card uses, so it is fetched once and reused. If it fails to load the
   `failed` class hides it and the SVG rotunda + type carry the screen — the
   museum never blocks on a decorative image. */
.loading-intro {
  width: clamp(96px, 12vh, 150px); height: auto; display: block;
  margin: 0 auto 1rem; border-radius: 50%;
  border: 1px solid rgba(201, 178, 120, 0.55);
  box-shadow: 0 0 34px rgba(201, 178, 120, 0.16);
  opacity: 0; animation: intro-in 900ms ease forwards;
}
.loading-intro.failed { display: none; }
@keyframes intro-in { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .loading-intro { animation: none; opacity: 1; }
}

/* Short viewports (1366x768 and OBS 720p): compact the panel so every line still
   fits inside the frame. Decorative spacing shrinks first; the reward message and
   the 50% callout are never removed. */
@media (max-height: 840px) {
  #stream-panel { font-size: clamp(0.78rem, 1.5vh, 0.96rem); line-height: 1.42; gap: 0; }
  #stream-panel p { margin: 0.18rem 0 0.5rem; }
  #stream-panel .sp-title { font-size: 0.76rem; margin-bottom: 0.3rem; padding-bottom: 0.2rem; }
  #stream-panel .sp-lede { font-size: 1.02em; margin-bottom: 0.45rem; }
  .sp-reward { margin: 0.4rem 0 0.5rem; padding: 0.4rem 0.8rem; }
  .sp-reward-pct { font-size: clamp(1.9rem, 4vh, 2.6rem); }
  .sp-reward-kicker { font-size: 0.7rem; }
  .sp-reward-of { font-size: 0.82rem; }
  .sp-reward-to { font-size: 0.72rem; }
}

/* Entry flow (2026-07-24): the introduction is the FIRST screen; the museum
   loads behind it. This line reports background progress without shifting the
   button or competing with the copy. */
.walk-status {
  font-size: 0.78rem; color: var(--dim); font-style: italic;
  margin-top: 0.1rem; min-height: 1.2em;
}
.walk-status.ready { color: #1c6b2a; font-style: normal; }

/* BROADCAST-ONLY OVERLAYS (2026-07-24). These belong to the OBS frame and must
   never appear on the public website. Gated in CSS off the document mode class
   so no stray `hidden = false` anywhere can re-reveal them. The caption and
   unmute button are deliberately NOT listed — the walk page uses them for the
   Curator's own narration. */
html.is-site #stream-panel,
html.is-site #stream-badge,
html.is-site #stream-leaderboard { display: none !important; }

/* The loading screen now sits over the live museum canvas and blurs whatever has
   rendered behind it, so the building reads as "already there" instead of a flat
   black card. The gradient is semi-transparent to let the blur through; browsers
   without backdrop-filter simply keep the original opaque look. */
.loading {
  /* A real (pre-blurred, 3 KB) museum interior sits under the scrim, so the
     building reads as ALREADY THERE behind the loader even before the first
     WebGL frame exists. backdrop-filter additionally blurs the live canvas once
     it starts rendering, so the two blend as the scene comes up. */
  background:
    radial-gradient(120% 90% at 50% 38%, rgba(20,16,12,0.52) 0%, rgba(14,11,9,0.66) 55%, rgba(8,7,6,0.80) 100%),
    url('/static/brand/museum_blur.webp') center / cover no-repeat;
  backdrop-filter: blur(20px) saturate(0.9) brightness(0.8);
  -webkit-backdrop-filter: blur(20px) saturate(0.9) brightness(0.8);
}
@supports not (backdrop-filter: blur(1px)) {
  .loading { background: radial-gradient(120% 90% at 50% 38%, #1c1712 0%, #100d0a 55%, #080706 100%); }
}

/* Reward tier rows (2026-07-24): scannable in a couple of seconds — the numbers
   carry the message, the prose is secondary. Shared shape for the entrance
   plaque and the livestream panel. */
.rp-tiers, .sp-tiers { display: flex; gap: 0.5rem; justify-content: center; margin: 0.5rem 0 0.35rem; }
.rp-tier, .sp-tier {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center;
  padding: 0.34rem 0.2rem; border: 1px solid rgba(138,47,29,0.45);
}
.rp-tier b, .sp-tier b { font-size: 0.72rem; letter-spacing: 0.14em; opacity: 0.8; }
.rp-tier span, .sp-tier span { font-size: 1.18rem; font-weight: 700; }
.rp-tier span { color: var(--accent); }
.sp-tier { border-color: rgba(201,178,120,0.4); }
.sp-tier span { color: #ffd873; }
.sp-tier b { color: #c9b98f; }
.rp-rule, .sp-rule { height: 1px; margin: 0.55rem 0 0.45rem; background: rgba(138,47,29,0.35); }
.sp-rule { background: rgba(201,178,120,0.3); }
@media (max-height: 840px) {
  .rp-tier span, .sp-tier span { font-size: 1rem; }
  .rp-tiers, .sp-tiers { margin: 0.35rem 0 0.25rem; }
}
