
/* ─── Fonts & design tokens ────────────────────────────────────────────── */

@import url('https://fonts.googleapis.com/css2?family=UnifrakturMaguntia&family=IM+Fell+English:ital@0;1&family=Crimson+Pro:ital,wght@0,300;0,400;0,600;1,300;1,400&family=Cinzel:wght@500;600&display=swap');
:root {
  --lodge-bg: #0e0b08;
  --lodge-panel: #17120d;
  --lodge-surface: #1f1810;
  --lodge-border: #3a2e1e;
  --lodge-amber: #c8922a;
  --lodge-amber-dim: #7a5418;
  --lodge-cream: #e8dfc8;
  --lodge-muted: #c0a882;
  --lodge-ash: #9a8a74;
  --lodge-fire: #d4621a;
  --lodge-gold: #e8b84b;
  --lodge-parchment: #f2e8d0;
  --lodge-ember-1: #ff6b1a;
  --lodge-ember-2: #e8922a;
  --lodge-ember-3: #c8621a;
  /* #235 — graph node/edge colors distinct from the UI chrome palette above:
     the UI colors (amber-dim, lodge-border, #3a3220, #2a2436) read fine as
     borders/backgrounds but drop below 3:1 against --lodge-panel when used
     as small node fills or thin edge strokes, verified with a WCAG relative-
     luminance calc, not by eye. These are lightened until each combination
     (fill or stroke-at-rendered-opacity, over --lodge-panel) clears 3:1. */
  --lodge-graph-member-fill: #b8842a;
  --lodge-graph-text-fill: #8a7c4c;
  --lodge-graph-theme-fill: #8880b8;
  --lodge-graph-edge-library: #a89468;
}

/* ─── Global reset & masthead ──────────────────────────────────────────── */

* { box-sizing: border-box; margin: 0; padding: 0; }
.lodge-root { background: var(--lodge-bg); color: var(--lodge-cream); font-family: 'Crimson Pro', Georgia, serif; }

/* #358 — visually hidden until focused: a keyboard/screen-reader path to
   the provocation/casting/convene controls that doesn't require tabbing
   through the room's witness-controls and canvas first. Principle 4
   (Accessibility): the room becoming the primary surface at rest must not
   make it the primary surface for keyboard/AT navigation too. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--lodge-panel); color: var(--lodge-amber);
  border: 1px solid var(--lodge-amber-dim); border-radius: 0 0 2px 0;
  padding: 8px 16px; font-family: 'IM Fell English', serif; font-size: 13px;
  text-decoration: none; letter-spacing: 1px;
}
.skip-link:focus { left: 0; }

/* #358 — the masthead was a hero (portrait, title, tagline, nav, ember bar
   each on their own row, ~380px+ tall) sized for a page whose next section
   was itself header art (a paste box). Now that the room sits directly
   beneath it and needs the fold, the masthead condenses to a single slim
   identity bar -- #303's "the header portrait does not keep hero-level fold
   real estate" is effectively resolved by this change, not answered
   separately. The ember bar stays (setEmber() in app.js still targets its
   ids every time setStatus() runs) but shrinks with it, via the .hearth-glow
   height override below rather than removing any element setEmber() reaches
   into. */
.lodge-mantel {
  position: relative; width: 100%;
  background: linear-gradient(180deg, #0a0704 0%, var(--lodge-panel) 100%);
  border-bottom: 2px solid var(--lodge-border);
}
.mantel-row { display: flex; align-items: center; justify-content: space-between; gap: 14px 20px; padding: 8px 20px; flex-wrap: wrap; }
.mantel-identity { display: flex; align-items: center; gap: 12px; }
.dorian-frame {
  width: 42px; height: 51px; position: relative; cursor: pointer; flex-shrink: 0;
  border-radius: 3px;
  box-shadow: 0 0 8px rgba(200,146,42,0.16);
  animation: frameGlow 6s ease-in-out infinite;
  transition: box-shadow 0.3s ease;
}
.dorian-frame:hover { animation-play-state: paused; box-shadow: 0 0 24px rgba(232,184,75,0.42), 0 0 4px rgba(232,184,75,0.55); }
@keyframes frameGlow {
  0%, 100% { box-shadow: 0 0 12px rgba(200,146,42,0.16); }
  50% { box-shadow: 0 0 18px rgba(200,146,42,0.26); }
}
.dorian-frame svg { width: 100%; height: 100%; display: block; }
/* #295 — ambient "self-adjusting" life for the portrait: a slow varnish
   sheen sweeps the canvas and the decay cracks breathe, both understated
   enough to read as atmosphere rather than a distraction at 140x170. Each
   element's resting (pre-animation) value below is what prefers-reduced-motion
   falls back to — see the masthead-motion media query at the end of this
   section — so disabling the loop still leaves a sane static frame, not a
   half-applied effect. */
.frame-sheen { mix-blend-mode: screen; opacity: 0; animation: sheenSweep 13s ease-in-out infinite; }
@keyframes sheenSweep {
  0%, 78% { transform: translateX(-70px); opacity: 0; }
  86% { opacity: 0.55; }
  94%, 100% { transform: translateX(70px); opacity: 0; }
}
.decay-crack-1 { opacity: 0.4; animation: crackFlicker1 7s ease-in-out infinite; }
.decay-crack-2 { opacity: 0.28; animation: crackFlicker2 8.5s ease-in-out 1.6s infinite; }
@keyframes crackFlicker1 { 0%, 100% { opacity: 0.4; } 50% { opacity: 0.62; } }
@keyframes crackFlicker2 { 0%, 100% { opacity: 0.28; } 50% { opacity: 0.46; } }
.corner-stud { transform-box: fill-box; transform-origin: center; transform: rotate(45deg); }
/* Principle 4 (Accessibility) is unconditional per docs/PRINCIPLES.md, not
   gated on audience size — honor it for the masthead motion added here. */
@media (prefers-reduced-motion: reduce) {
  .dorian-frame, .frame-sheen, .decay-crack-1, .decay-crack-2 { animation: none; }
}
.lodge-title-block { text-align: left; }
.lodge-title { font-family: 'UnifrakturMaguntia', serif; font-size: 19px; color: var(--lodge-amber); letter-spacing: 1px; line-height: 1.15; text-shadow: 0 0 14px rgba(200,146,42,0.3); }
.lodge-subtitle { font-family: 'IM Fell English', serif; font-style: italic; font-size: 9px; color: var(--lodge-muted); letter-spacing: 2px; text-transform: uppercase; margin-top: 1px; }
.mantel-nav { display:flex; gap:8px; flex-wrap:wrap; }
.mantel-sessions-btn { font-size:12px; padding:5px 16px; border-color:var(--lodge-border); color:var(--lodge-muted); }
.mantel-sessions-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-cream); }

/* ─── Hearth glow & embers ─────────────────────────────────────────────── */

/* #358 — shrunk from 48px to 18px along with the rest of the masthead.
   setEmber() in app.js (called from every setStatus()) still targets
   #ember-bar/#s1-#s5 directly, so the elements and their ids stay exactly
   as they were; only this container's height (and the proportionally
   bottom-anchored ::before/::after glow, both already inside
   overflow:hidden) shrinks, so the "thinking" indicator keeps working
   without any JS change. */
.hearth-glow {
  width: 100%; height: 18px; position: relative; overflow: hidden;
  background: linear-gradient(180deg, #0a0704 0%, #1a0a04 40%, #0a0500 100%);
  display: flex; align-items: flex-end; justify-content: center;
}
.hearth-glow::before {
  content: '';
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 260px; height: 32px;
  background: radial-gradient(ellipse at 50% 100%, rgba(255,107,26,0.55) 0%, rgba(232,146,42,0.3) 35%, rgba(180,80,10,0.1) 65%, transparent 100%);
}
.hearth-glow::after {
  content: '';
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 140px; height: 18px;
  background: radial-gradient(ellipse at 50% 100%, rgba(255,160,60,0.7) 0%, rgba(220,100,20,0.4) 50%, transparent 100%);
}
.ember-bar {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 200px; height: 4px;
  background: linear-gradient(90deg, transparent, var(--lodge-ember-3), var(--lodge-ember-1), var(--lodge-ember-2), var(--lodge-ember-1), var(--lodge-ember-3), transparent);
  border-radius: 2px 2px 0 0;
  opacity: 0.8;
  animation: emberPulse 4s ease-in-out infinite;
}
.ember-bar.active { animation: emberBurn 1.8s ease-in-out infinite; opacity: 1; }
@keyframes emberPulse {
  0%,100% { opacity:0.5; width:200px; }
  50% { opacity:0.85; width:220px; }
}
@keyframes emberBurn {
  0%,100% { opacity:0.8; width:200px; box-shadow: 0 0 8px rgba(255,107,26,0.4); }
  33% { opacity:1; width:240px; box-shadow: 0 0 16px rgba(255,160,60,0.7); }
  66% { opacity:0.9; width:210px; box-shadow: 0 0 12px rgba(232,146,42,0.5); }
}
.ember-sparks {
  position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%);
  width: 180px; height: 28px; pointer-events: none;
}
.spark { position: absolute; bottom: 0; width: 2px; height: 2px; border-radius: 50%; background: var(--lodge-ember-1); opacity: 0; }
.spark.active { animation: sparkRise 2.5s ease-out infinite; }
.spark:nth-child(1) { left: 30%; animation-delay: 0s; }
.spark:nth-child(2) { left: 50%; animation-delay: 0.7s; background: var(--lodge-gold); }
.spark:nth-child(3) { left: 70%; animation-delay: 1.4s; }
.spark:nth-child(4) { left: 40%; animation-delay: 1.9s; background: var(--lodge-ember-2); }
.spark:nth-child(5) { left: 60%; animation-delay: 0.4s; }
@keyframes sparkRise {
  0% { opacity:0; transform: translateY(0) scale(1); }
  20% { opacity:0.9; }
  80% { opacity:0.3; }
  100% { opacity:0; transform: translateY(-22px) scale(0.3) translateX(8px); }
}

/* ─── Convene panel — journal input & member roster ────────────────────── */

/* #358 — the room (#stage-record) reads as widescreen, letterboxed to the
   room's own real proportions (see scene.js's HEARTH_ANGLE comment, which
   already anticipated this widening the camera's effective horizontal FOV
   further, not narrowing it) -- so it gets a wider column than the
   provocation/casting/convene controls below it, which stay a readable
   960px measure. .lodge-body itself widens to give the room that room;
   .control-rail/.after-panel/.status-bar re-narrow and re-center below. */
.lodge-body { display:flex; flex-direction:column; flex:1; padding:16px 24px 24px; gap:16px; max-width:1440px; width:100%; margin:0 auto; }
#stage-record { width:100%; max-width:1400px; margin:0 auto; }
/* #358 — provocation, casting, and convene used to be three full-width
   panels stacked *above* the room (1339px of them, at the measurement that
   opened this issue), forcing it below the fold. They live in the same
   full-width stacked shape below the room instead -- a two-column
   side-by-side attempt (Provocation | Cast) was tried and dropped: the
   roster grid (up to 50 members, see roster.js) wrapping into a ~320px
   column ran to 900+px tall, far worse than the 960px-wide grid it uses
   here. "Around the room, not stacked above it" is satisfied by position
   (below/reachable, not gatekeeping the fold) rather than by forcing them
   into a cramped multi-column shape that fights the roster's own size. */
.control-rail { position:relative; display:flex; flex-direction:column; gap:16px; width:100%; max-width:960px; margin:0 auto; }
.after-panel, .status-bar, .pre-convene-guide { width:100%; max-width:960px; margin:0 auto; }

/* #342: dismissible preamble + numbered stepper for the pre-convene flow.
   Sits above .control-rail rather than inside it -- .control-rail-gate is
   position:absolute;inset:0 against .control-rail (see below), so anything
   placed inside that box, gated or not, would render underneath the gate
   overlay for an unauthenticated visitor. This is orientation content: it
   should stay legible for everyone, per the same diegetic-not-hidden
   reasoning the gate itself uses. */
.pre-convene-guide { display:flex; flex-direction:column; gap:8px; margin-bottom:-4px; }
.preamble-banner { display:flex; align-items:flex-start; gap:14px; background:var(--lodge-surface); border:1px solid var(--lodge-border); border-left:3px solid var(--lodge-amber-dim); border-radius:2px; padding:12px 16px; }
.preamble-banner[hidden] { display:none; }
.preamble-text { font-family:'IM Fell English',serif; font-style:italic; font-size:14px; color:var(--lodge-cream); line-height:1.6; flex:1; margin:0; }
.preamble-dismiss { background:none; border:none; color:var(--lodge-ash); cursor:pointer; font-size:13px; line-height:1; padding:2px 4px; flex-shrink:0; }
.preamble-dismiss:hover { color:var(--lodge-cream); }

.convene-stepper { display:flex; align-items:center; list-style:none; margin:0; padding:6px 4px; }
.convene-step { flex:0 0 auto; }
.step-rule { flex:1; height:1px; background:var(--lodge-border); margin:0 8px; align-self:center; }
.step-btn { display:flex; align-items:center; gap:8px; background:none; border:none; padding:4px; margin:-4px; cursor:pointer; font:inherit; }
.step-btn:hover .step-label { color:var(--lodge-cream); }
.step-badge { display:flex; align-items:center; justify-content:center; width:22px; height:22px; border-radius:50%; border:1px solid var(--lodge-ash); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:12px; flex-shrink:0; transition:all 0.2s; }
.step-label { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:0.5px; color:var(--lodge-ash); white-space:nowrap; transition:color 0.2s; }
.convene-step.is-active .step-badge { border-color:var(--lodge-amber); color:var(--lodge-amber); background:rgba(200,146,42,0.12); box-shadow:0 0 6px rgba(200,146,42,0.4); }
.convene-step.is-active .step-label { color:var(--lodge-cream); }
.convene-step.is-complete .step-badge { border-color:var(--lodge-amber-dim); color:var(--lodge-amber-dim); }
.convene-step.is-complete .step-label { color:var(--lodge-muted); }
@media (max-width: 640px) {
  .step-label { display:none; }
  .step-rule { margin:0 4px; }
}

/* #379: public read tier. control-rail-content wraps the actual provocation/
   casting/convene controls at unchanged flex-item positions (display:contents
   removes only its own box, not its children's) so app.js can `inert` the
   whole group in one place for an unauthenticated visitor, rather than
   walking every child of control-rail individually. The gate sits absolutely
   over that content once .is-gated is set — dimmed-but-legible underneath, so
   a visitor can see the room is convenable, per docs/PRINCIPLES.md Principle
   6 (diegetic, not hidden) — with the sign-in prompt as the one live control. */
.control-rail-content { display:contents; }
.control-rail-gate { display:none; }
.control-rail.is-gated .control-rail-gate {
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px;
  position:absolute; inset:0; z-index:5; text-align:center; padding:24px;
  background:rgba(10,8,5,0.78); border:1px solid var(--lodge-amber-dim); border-radius:2px;
}
/* display:contents has no box of its own, so the dimming has to target its
   children directly rather than the wrapper — opacity/filter on a
   display:contents element itself has no effect per spec. */
.control-rail.is-gated .control-rail-content > * { opacity:.35; filter:grayscale(.4); }
.control-rail-gate-text { font-family:'IM Fell English',serif; font-style:italic; font-size:15px; color:var(--lodge-cream); max-width:420px; line-height:1.6; }
.panel-label { font-family:'IM Fell English',serif; font-size:13px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-muted); margin-bottom:8px; }
.journal-panel, .member-panel, .transcript-panel, .after-panel, .panel { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:16px; }
.card { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:10px 12px; }
.journal-controls { display:flex; gap:10px; margin-bottom:12px; flex-wrap:wrap; }
.lodge-select { background:var(--lodge-panel); border:1px solid var(--lodge-border); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:15px; padding:7px 12px; border-radius:2px; cursor:pointer; flex:1; min-width:140px; appearance:none; }
.lodge-select option { background:var(--lodge-panel); }
.library-search-input { flex:1 1 100%; cursor:text; font-style:italic; font-size:14px; }
.library-search-input::placeholder { color:var(--lodge-muted); }
.library-search-input[hidden] { display:none; }
.lodge-btn { background:transparent; border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); font-family:'IM Fell English',serif; font-size:13px; padding:7px 16px; border-radius:2px; cursor:pointer; letter-spacing:1px; transition:all 0.2s; white-space:nowrap; }
.lodge-btn:hover { background:rgba(200,146,42,0.1); border-color:var(--lodge-amber); }
a.lodge-btn { display:inline-block; text-decoration:none; }
.lodge-btn:disabled { opacity:0.4; cursor:not-allowed; }
.lodge-btn.primary { background:rgba(200,146,42,0.15); border-color:var(--lodge-amber); }
.lodge-btn.primary:hover { background:rgba(200,146,42,0.25); }
.lodge-btn.export-dayone { border-color:#5a8a5a; color:#90c890; }
.lodge-btn.export-dayone:hover { background:rgba(90,138,90,0.15); }
.lodge-btn.export-txt { border-color:#6a7a8a; color:#a0b8c8; }
.lodge-btn.export-txt:hover { background:rgba(100,130,150,0.15); }
.lodge-btn.export-ulysses { border-color:#7a6a9a; color:#b8a8d8; }
.lodge-btn.export-ulysses:hover { background:rgba(120,100,160,0.15); }
.lodge-btn.export-obsidian { border-color:#5a7a5a; color:#90c890; }
.lodge-btn.export-obsidian:hover { background:rgba(80,130,80,0.15); }
.ulysses-group-input { background:var(--lodge-panel); border:1px solid var(--lodge-border); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:13px; font-style:italic; padding:3px 8px; border-radius:2px; width:180px; }
.ulysses-group-input:focus { outline:none; border-color:var(--lodge-amber-dim); }
.ulysses-group-input::placeholder { color:var(--lodge-ash); }
.journal-entry-display { background:var(--lodge-panel); border:1px solid var(--lodge-ash); border-left:3px solid var(--lodge-amber-dim); padding:14px 16px; font-size:15px; line-height:1.7; color:var(--lodge-cream); font-style:italic; min-height:80px; border-radius:0 2px 2px 0; white-space:pre-wrap; }
.journal-entry-display.placeholder { color:var(--lodge-muted); }
.journal-paste-area { background:var(--lodge-panel); border:1px solid var(--lodge-ash); border-left:3px solid var(--lodge-amber-dim); padding:14px 16px; font-family:'Crimson Pro',serif; font-size:15px; font-style:italic; line-height:1.7; color:var(--lodge-cream); border-radius:0 2px 2px 0; width:100%; min-height:100px; resize:vertical; }
.journal-paste-area::placeholder { color:var(--lodge-muted); }
.journal-paste-area:focus { outline:none; border-left-color:var(--lodge-amber); }
.file-pick-row { display:flex; align-items:center; gap:10px; margin-top:8px; }
.file-pick-btn { font-size:12px; padding:5px 12px; border-color:var(--lodge-ash); color:var(--lodge-muted); }
.file-pick-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-cream); }
.file-pick-name { font-family:'IM Fell English',serif; font-style:italic; font-size:13px; color:var(--lodge-muted); }
.member-count-badge { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:1px; color:var(--lodge-ash); font-style:italic; text-transform:none; }
.member-count-badge.warn { color:#a07840; cursor:help; }
.member-count-badge.over { color:#a05030; cursor:help; }
.members-grid { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:4px; }
.member-token { display:flex; align-items:center; gap:7px; background:var(--lodge-panel); border:1px solid var(--lodge-border); border-radius:2px; padding:6px 10px; cursor:pointer; transition:all 0.2s; user-select:none; position:relative; }
.member-token:hover { border-color:var(--lodge-amber-dim); }
.member-token.active { border-color:var(--lodge-amber); background:rgba(200,146,42,0.08); }
.member-dot { width:7px; height:7px; border-radius:50%; background:var(--lodge-ash); flex-shrink:0; }
.member-token.active .member-dot { background:var(--lodge-amber); box-shadow:0 0 6px rgba(200,146,42,0.6); }
.member-portrait { width:22px; height:22px; border-radius:50%; object-fit:cover; border:1px solid var(--lodge-border); flex-shrink:0; }
.member-token.active .member-portrait { border-color:var(--lodge-amber); box-shadow:0 0 6px rgba(200,146,42,0.6); }
.member-name { font-family:'IM Fell English',serif; font-size:14px; color:var(--lodge-muted); flex:1; }
.member-token.active .member-name { color:var(--lodge-cream); }

.member-filter-input { background:var(--lodge-surface); border:1px solid var(--lodge-border); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:12px; text-transform:none; letter-spacing:normal; padding:3px 8px; border-radius:2px; width:120px; }
.member-filter-input:focus { outline:none; border-color:var(--lodge-amber-dim); }
.member-filter-input::placeholder { color:var(--lodge-ash); font-style:italic; }
.members-empty-hint { font-family:'Crimson Pro',serif; font-size:13px; font-style:italic; color:var(--lodge-muted); padding:4px 2px; }
.members-cast-hint { font-family:'Crimson Pro',serif; font-size:13px; font-style:italic; color:var(--lodge-ash); padding:6px 2px 2px; max-width:52ch; line-height:1.5; }

/* ── Casting: regulars + the proposed cast (#185) ───────────────────────────
   The pin lives inside the member token but answers a different question —
   who is always here, not who is here tonight — so it stays dim until hovered
   or pinned rather than competing with the token's own active state. */
.member-pin { background:none; border:none; padding:0 0 0 2px; margin:0; line-height:1; cursor:pointer; font-size:11px; color:transparent; transition:color 0.2s; flex-shrink:0; }
.member-token:hover .member-pin { color:var(--lodge-ash); }
.member-pin:hover { color:var(--lodge-amber); }
.member-pin:focus-visible { outline:1px solid var(--lodge-amber-dim); outline-offset:2px; color:var(--lodge-ash); }
.member-pin.pinned, .member-token:hover .member-pin.pinned { color:var(--lodge-amber); text-shadow:0 0 6px rgba(200,146,42,0.5); }
.member-token.regular { border-left:2px solid var(--lodge-amber-dim); }

/* The heading row carries three things now (title+badge, ask, filter), which
   is more than a narrow viewport fits on one line — so it wraps rather than
   pushing the page sideways. */
.member-panel-head { display:flex; align-items:center; justify-content:space-between; gap:8px; flex-wrap:wrap; }
.member-panel-heading { display:flex; align-items:center; gap:8px; }
.member-panel-controls { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.cast-ask-btn { font-size:11px; padding:3px 9px; }

.cast-proposal { border:1px solid var(--lodge-amber-dim); border-left-width:3px; border-radius:2px; background:rgba(200,146,42,0.05); padding:10px 12px; margin-bottom:10px; }
.cast-proposal.pending { border-color:var(--lodge-border); border-left-color:var(--lodge-amber-dim); background:transparent; }
.cast-proposal-head { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.cast-proposal-title { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:1.5px; text-transform:uppercase; color:var(--lodge-amber); }
.cast-proposal.pending .cast-proposal-title { color:var(--lodge-ash); }
.cast-proposal-dismiss { background:none; border:none; color:var(--lodge-ash); cursor:pointer; font-size:13px; line-height:1; padding:2px 4px; }
.cast-proposal-dismiss:hover { color:var(--lodge-cream); }
.cast-proposal-names { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.cast-proposal-name { font-family:'IM Fell English',serif; font-size:14px; color:var(--lodge-cream); border:1px solid var(--lodge-border); border-radius:2px; padding:2px 8px; }
/* A regular in the proposal is a fact, not a suggestion — marked so it reads
   as "already coming" rather than as something the director chose. */
.cast-proposal-name.regular { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); }
.cast-proposal-name.regular::before { content:'✦ '; font-size:10px; }
.cast-proposal-reason { font-family:'Crimson Pro',serif; font-size:13px; font-style:italic; color:var(--lodge-muted); margin-top:8px; line-height:1.5; max-width:64ch; }
.cast-proposal-actions { display:flex; gap:8px; margin-top:12px; }

/* ─── Transcript — rounds, lulls & message bubbles ─────────────────────── */

.transcript-empty { text-align:center; padding:40px 20px; color:var(--lodge-muted); font-family:'IM Fell English',serif; font-style:italic; font-size:15px; line-height:1.8; }
.transcript-round-header { display:flex; align-items:center; gap:12px; margin:20px 0 14px; }
.transcript-round-header:first-child { margin-top:0; }
.round-rule { flex:1; height:1px; background:var(--lodge-border); }
.round-rule-label { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-muted); }
.branch-from-here-btn { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:1px; background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-muted); padding:2px 8px; border-radius:2px; cursor:pointer; white-space:nowrap; }
.branch-from-here-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); }

/* #245: the lull. Deliberately NOT .transcript-round-header's uppercase,
   letter-spaced section heading — a lull is the room drawing breath, so the
   note reads as an action line (italic, sentence case, ash) between two rules
   that fade out toward the margins. The rules keep it legible as a division
   of the transcript; everything else about it says pause, not chapter. */
.transcript-lull { display:flex; align-items:center; gap:14px; margin:22px 0 20px; animation:fadeIn 0.5s ease; }
.lull-rule { flex:1; height:1px; background:linear-gradient(to right, transparent, var(--lodge-border)); }
.lull-rule:last-of-type { background:linear-gradient(to left, transparent, var(--lodge-border)); }
/* #246: a slow, continuous rise and fall rather than the one-shot fadeIn
   everything else on the page gets — the note doesn't just arrive, it keeps
   breathing for as long as it's the room's current state. Delayed so it
   starts after the entrance settles, not layered on top of it. */
.lull-note { font-family:'IM Fell English','Crimson Pro',serif; font-style:italic; font-size:13px; color:var(--lodge-ash); letter-spacing:0.03em; text-align:center; opacity:0.85; animation:lullBreathe 4.5s ease-in-out 0.6s infinite; }
@keyframes lullBreathe { 0%,100% { opacity:0.85; } 50% { opacity:0.5; } }
.lull-actions { display:flex; gap:8px; flex-shrink:0; }
.lull-btn { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:1px; background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-muted); padding:3px 12px; border-radius:2px; cursor:pointer; white-space:nowrap; transition:all 0.2s; }
.lull-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); }
.lull-btn.continue { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); }
.lull-btn.continue:hover { background:rgba(200,146,42,0.15); }
/* ── Bubble layout ─────────────────────────────────────────────────────────── */
#transcript-content, .compare-panel-transcript { display:flex; flex-direction:column; padding:0 2px; }
.transcript-entry { max-width:74%; margin-bottom:14px; animation:fadeIn 0.4s ease; }
.transcript-entry.bubble-left { align-self:flex-start; }
.transcript-entry.bubble-right { align-self:flex-end; }
.bubble-body { background:rgba(23,18,13,0.5); border:1px solid var(--lodge-border); border-radius:2px 8px 8px 8px; padding:10px 14px; }
.bubble-right .bubble-body { border-radius:8px 2px 8px 8px; }
/* #457: the #witness-stage fallback's version of the room's card-entry-aside
   treatment -- no seat geometry there to draw a connector between, so the
   dashed border plus the "aside" tag (speechBodyHtml) is the whole signal. */
.transcript-entry.bubble-aside .bubble-body { border-style:dashed; }
.transcript-entry.bubble-aside .speech-text { font-style:italic; color:var(--lodge-muted); }
/* #579: the stage-fallback version of card-entry-confessional below. */
.transcript-entry.bubble-confessional .bubble-body { border-left:3px double var(--lodge-border); }
@keyframes fadeIn { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:translateY(0)} }
/* #266 — identity names (proper nouns) get their own typeface, distinct from
   .panel-label's IM Fell English (functional labels) and .lodge-title's
   UnifrakturMaguntia (masthead only, illegible-but-read-once is fine there,
   a transcript full of repeated speaker headers is not). */
.identity-name, .speaker-name, .witness-speaker, .dossier-name, .thread-header-name, .lodge-detail-name {
  font-family: 'Cinzel', serif;
  font-weight: 600;
}
.speaker-name { font-size:19px; color:var(--lodge-amber); margin-bottom:5px; letter-spacing:1px; display:flex; align-items:center; gap:6px; }
.speaker-name.observer-voice { color:#a0c8a0; }
.transcript-entry.bubble-right .speaker-name { justify-content:flex-end; }
.speaker-glyph { font-family:'Georgia',serif; font-size:13px; opacity:0.6; letter-spacing:0; line-height:1; flex-shrink:0; }
.speaker-avatar { width:20px; height:20px; border-radius:50%; object-fit:cover; border:1px solid var(--lodge-border); flex-shrink:0; }

/* ── Per-member voice classes (reserved for future avatar/identity work) ───── */
/* Typography is intentionally uniform — voice-{id} classes are hooks only.   */
.speech-text { font-family:'Crimson Pro',serif; font-size:18px; line-height:1.8; color:var(--lodge-parchment); }
.action-line { font-family:'IM Fell English','Crimson Pro',serif; font-style:italic; font-size:13px; color:var(--lodge-ash); text-align:center; align-self:center; max-width:55%; margin:14px 0 16px; letter-spacing:0.03em; opacity:0.8; }
.bubble-body .action-line { align-self:auto; max-width:none; margin:6px 0 2px; opacity:1; }
/* #373: distinct from .action-line -- this is spoken by voice.js, not
   silently skipped, and reads as emphasized/keyword text (foreign terms,
   phrases inviting exploration), not a stage direction, so it shouldn't
   look identical to one. */
/* No underline/border-bottom and no --lodge-amber -- both are already the
   app's real-link signals (see a.lodge-btn, a.archival-image-link below),
   and the dotted border-bottom here was reading as a dead/broken link.
   Underline is reserved exclusively for .inline-link (future markdown-link
   support, not yet parsed anywhere) so the two affordances never collide. */
.keyword-inline { font-style:italic; }
/* Reserved for future inline hyperlinks -- no parser emits this class yet.
   Underline must stay exclusive to it; .keyword-inline above must never
   carry one, or a real link stops being distinguishable from emphasis. */
.inline-link { color:var(--lodge-amber); text-decoration:underline; cursor:pointer; }
.inline-link:hover { color:var(--lodge-gold); }
.after-panel { display:none; }
/* #343: now toggled on every lull (runLullLoop), not just once at a
   meeting's true end -- the same fadeIn every other transcript/lull element
   already gets on arrival, so it reads as the room settling rather than a
   panel snapping in and out under repeated toggling. */
.after-panel.visible { display:block; animation:fadeIn 0.4s ease; }
.after-row { display:flex; gap:10px; flex-wrap:wrap; align-items:center; }
.after-row + .after-row { margin-top:10px; padding-top:10px; border-top:1px solid var(--lodge-border); }
.interject-form { display:flex; gap:10px; }
.interject-row { display:flex; gap:10px; }
.interject-input { background:var(--lodge-panel); border:1px solid var(--lodge-ash); border-left:3px solid #a0c8a0; color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:15px; font-style:italic; padding:8px 12px; border-radius:0 2px 2px 0; flex:1; }
.interject-input:focus { outline:none; border-left-color:#c0e0c0; }
.interject-input::placeholder { color:var(--lodge-ash); }

/* ─── Action menus & status bar ────────────────────────────────────────── */

/* #186: Continue/Preserve dropdown menus, replacing the ~11-control sprawl */
.menu-wrap { position:relative; display:inline-block; }
.lodge-menu { display:none; flex-direction:column; gap:2px; position:absolute; top:calc(100% + 6px); left:0; min-width:230px; background:var(--lodge-panel); border:1px solid var(--lodge-border); border-radius:2px; padding:6px; box-shadow:0 10px 28px rgba(0,0,0,0.5); z-index:50; }
.lodge-menu.open { display:flex; }
.lodge-menu .lodge-btn { border-color:transparent; text-align:left; width:100%; }
.lodge-menu .lodge-btn:hover { background:rgba(200,146,42,0.1); }
.lodge-menu-divider { height:1px; background:var(--lodge-border); margin:4px 2px; }
.status-bar { text-align:center; padding:10px; font-family:'IM Fell English',serif; font-style:italic; font-size:14px; color:var(--lodge-muted); min-height:36px; display:flex; align-items:center; justify-content:center; gap:12px; }
.status-bar.thinking { color:var(--lodge-amber); animation:flicker 2s ease-in-out infinite; }
.status-bar.error { color:#a06060; }
.status-retry-btn { font-size:11px; padding:3px 12px; border-color:#5a2a2a; color:#a06060; font-style:normal; }
.status-retry-btn:hover { background:rgba(120,40,40,0.15); border-color:#a06060; color:#d09090; }
@keyframes flicker { 0%,100%{opacity:1} 50%{opacity:0.6} }

/* #581: a quiet, permanent way back to the preamble content -- text-link
   weight, not a bordered lodge-btn, so it doesn't compete with the header's
   functional buttons. No color cue beyond the site's existing muted/cream
   pairing; italic plus the underline on hover is affordance enough. */
.lodge-footer { text-align:center; padding:2px 10px 16px; }
.footer-orient-btn { background:none; border:none; padding:2px 4px; font-family:'IM Fell English',serif; font-style:italic; font-size:12px; letter-spacing:0.5px; color:var(--lodge-ash); cursor:pointer; }
.footer-orient-btn:hover { color:var(--lodge-muted); text-decoration:underline; }
.tooltip-tag { font-size:12px; background:rgba(200,146,42,0.15); border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); padding:2px 7px; border-radius:2px; font-family:'IM Fell English',serif; letter-spacing:1px; }
.source-tag { font-size:12px; color:var(--lodge-muted); font-family:'IM Fell English',serif; font-style:italic; margin-left:6px; }
#verify-citations-btn { display:none; }
#verify-citations-btn.visible { display:inline-block; }
#reveal-player-turns-btn { display:none; }
#reveal-player-turns-btn.visible { display:inline-block; }

/* ─── Convene panel controls — artifact & play-as arcs ─────────────────── */

/* Convene panel — convene button is primary; arc config sits below, demoted */
.convene-panel { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; display:flex; flex-direction:column; }
.convene-panel-label { padding:14px 14px 0; margin-bottom:0; }
.convene-row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; padding:12px 14px; }

/* Shared arc-field styles (used by .artifact-panel's "Bring an artifact" details and .playeras-panel's "Play as" fields) */
.arc-summary { font-family:'IM Fell English',serif; font-size:13px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-muted); padding:10px 14px; cursor:pointer; list-style:none; user-select:none; }
.arc-summary-note { font-size:12px; letter-spacing:1px; color:var(--lodge-muted); text-transform:none; font-style:italic; }
.arc-summary::-webkit-details-marker { display:none; }
.arc-summary::before { content:'↳ '; color:var(--lodge-amber-dim); }
.arc-summary:hover { color:var(--lodge-muted); }
.arc-fields { display:flex; flex-direction:column; gap:10px; padding:0 14px 14px; }
.arc-field { display:flex; flex-direction:column; gap:4px; }
.arc-textarea { background:var(--lodge-panel); border:1px solid var(--lodge-ash); border-left:3px solid var(--lodge-amber-dim); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:14px; font-style:italic; line-height:1.6; padding:8px 12px; border-radius:0 2px 2px 0; resize:vertical; width:100%; }
.arc-textarea:focus { outline:none; border-left-color:var(--lodge-amber); }
.arc-textarea:disabled { opacity:0.6; cursor:not-allowed; }

/* #440: "Play as" is entered via the "You" chip in members-grid (below),
   same click-to-reveal shape as any other member token, rather than a
   collapsed <details> panel disconnected from how every other participant
   gets picked. Collapsed by default; .expanded is toggled by
   togglePlayAsCard() (and once, read-only, by restorePlayAsControlDisplay()
   for a restored session). */
.playeras-panel { display:none; border-top:1px solid var(--lodge-border); background:rgba(0,0,0,0.12); margin-top:12px; }
.playeras-panel.expanded { display:block; }
.playeras-panel .arc-fields { padding:12px 14px 14px; gap:8px; }

/* The "You" chip -- same .member-token shape as a real roster chip, portrait
   frame left empty since there's no portrait file for the player. The note
   reuses updateConvenePlayerStatus()'s label logic (ex-.convene-player-status,
   #348) and stays blank for the default "observe only" state -- untouched
   and deliberately-observe-only aren't worth distinguishing visually. */
.member-portrait-empty { background:transparent; }
.you-token-note { font-size:12px; font-style:italic; color:var(--lodge-ash); }
.you-token.active .you-token-note { color:var(--lodge-amber); }

/* ─── Transcript annotations & citations ───────────────────────────────── */

/* Player turn markers — invisible unless revealed, right-badge + background tint
   (distinct from .annotated's left border and .flagged-citation's right border) */
.transcript-entry.player-turn .speaker-name::after {
  content: '◆ played';
  margin-left: 6px;
  font-size: 10px;
  color: var(--lodge-gold);
  opacity: 0;
  transition: opacity 0.15s;
}
.reveal-player-turns .transcript-entry.player-turn .speaker-name::after { opacity: 0.8; }
.reveal-player-turns .transcript-entry.player-turn .bubble-body { background: rgba(200,146,42,0.05); }

.transcript-stream-live { font-family:'Crimson Pro',serif; font-size:17px; line-height:1.8; color:var(--lodge-muted); white-space:pre-wrap; padding:4px 0 12px; font-style:italic; animation:flicker 3s ease-in-out infinite; }

/* #115: per-speaker placeholder shown while their turn is still generating,
   swapped for a real addSpeech bubble the instant it settles. Reuses
   .speaker-name and .transcript-stream-live so it reads as a rough draft of
   the bubble it's about to become, not an unrelated UI element. */
.transcript-typing { padding:4px 0 12px; opacity:0.85; }
.transcript-typing .typing-text { padding:0; }

/* Annotations */
.transcript-entry .speech-text { cursor:pointer; }
.transcript-entry .speech-text:hover { background:rgba(200,146,42,0.04); border-radius:2px; }
.transcript-entry.annotating .bubble-body { background:rgba(200,146,42,0.04); }
.transcript-entry.annotated .bubble-body { border-left:2px solid var(--lodge-amber-dim); }
.annotation-area { padding:6px 0 4px; }
.annotation-input { width:100%; background:transparent; border:none; border-bottom:1px solid var(--lodge-border); color:var(--lodge-muted); font-family:'IM Fell English',serif; font-style:italic; font-size:14px; line-height:1.5; padding:4px 0; resize:none; outline:none; }
.annotation-input:focus { border-bottom-color:var(--lodge-amber-dim); color:var(--lodge-cream); }
.annotation-input::placeholder { color:var(--lodge-ash); }

/* Citation verification — right border, distinct from .annotated's left border, color-coded by verdict */
.transcript-entry.flagged-citation .bubble-body { border-right:2px solid var(--flag-color, var(--lodge-ash)); }
.transcript-entry.citation-verified .bubble-body { --flag-color:#6a9a6a; }
.transcript-entry.citation-unverified .bubble-body { --flag-color:var(--lodge-fire); }
.transcript-entry.citation-uncertain .bubble-body { --flag-color:var(--lodge-gold); }
.transcript-entry.flagged-citation .speech-text { cursor:help; }

/* Archival image (#30) — cover/title-page of the cited work, synced to its speech block */
.archival-image { margin-top:10px; }
.archival-image-link { display:inline-block; border:1px solid var(--lodge-border); border-radius:2px; padding:3px; background:rgba(0,0,0,0.2); transition:border-color 0.15s ease; }
a.archival-image-link:hover { border-color:var(--lodge-amber-dim); cursor:pointer; }
.archival-image-link img { display:block; max-height:120px; width:auto; border-radius:1px; filter:sepia(0.15); }

/* ─── Sessions drawer ──────────────────────────────────────────────────── */
.sessions-btn { border-color:var(--lodge-ash); color:var(--lodge-muted); }
.sessions-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-cream); }
.sessions-count { display:inline-block; background:rgba(200,146,42,0.2); color:var(--lodge-amber); font-size:11px; padding:1px 5px; border-radius:8px; margin-left:4px; font-family:'Crimson Pro',serif; vertical-align:middle; }
.sessions-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.55); z-index:100; }
.sessions-overlay.open { display:block; }
.sessions-drawer { position:fixed; top:0; right:0; width:400px; max-width:95vw; height:100vh; background:var(--lodge-panel); border-left:1px solid var(--lodge-border); z-index:101; display:flex; flex-direction:column; transform:translateX(100%); transition:transform 0.25s ease; }
.sessions-drawer.open { transform:translateX(0); }
.sessions-drawer-header { display:flex; align-items:center; justify-content:space-between; padding:16px 18px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.sessions-drawer-title { font-family:'IM Fell English',serif; font-size:14px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-amber); }
.sessions-close-btn { background:none; border:none; color:var(--lodge-muted); font-size:16px; cursor:pointer; padding:4px 8px; line-height:1; }
.sessions-close-btn:hover { color:var(--lodge-cream); }
/* #344: cards in a grid rather than one dense scan-list column — auto-fill
   settles to 2 columns at this drawer width, 1 on narrow viewports. */
.sessions-drawer-body { flex:1; overflow-y:auto; padding:12px; display:grid; grid-template-columns:repeat(auto-fill, minmax(160px, 1fr)); gap:10px; align-content:start; }
.sessions-empty { grid-column:1 / -1; font-family:'IM Fell English',serif; font-style:italic; color:var(--lodge-muted); font-size:14px; text-align:center; padding:32px 16px; }
.session-item { grid-column:span 1; background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:3px; padding:10px 12px; cursor:default; transition:border-color 0.15s; display:flex; flex-direction:column; gap:6px; }
.session-item:hover { border-color:var(--lodge-amber-dim); }
.session-card-top { display:flex; align-items:center; gap:8px; }
.avatar-stack { display:flex; align-items:center; flex-shrink:0; }
.avatar-stack-img, .avatar-stack-more { width:26px; height:26px; border-radius:50%; margin-left:-9px; border:1.5px solid var(--lodge-surface); box-shadow:0 0 0 1px var(--lodge-border); background:var(--lodge-panel); flex-shrink:0; }
.avatar-stack-img { object-fit:cover; }
.avatar-stack-img:first-child, .avatar-stack-more:first-child { margin-left:0; }
.avatar-stack-more { display:flex; align-items:center; justify-content:center; font-family:'IM Fell English',serif; font-size:10px; color:var(--lodge-muted); }
.session-item-date { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:1.5px; color:var(--lodge-amber); display:flex; flex-direction:column; gap:2px; min-width:0; }
.session-item-rounds { font-size:10px; color:var(--lodge-muted); letter-spacing:1px; }
.session-item-badges { display:flex; flex-wrap:wrap; gap:4px; }
.session-item-badges:empty { display:none; }
.session-item-entry { font-family:'Crimson Pro',serif; font-size:13px; color:var(--lodge-cream); line-height:1.4; font-style:italic; display:-webkit-box; -webkit-line-clamp:1; -webkit-box-orient:vertical; overflow:hidden; }
.session-item-actions { display:flex; gap:6px; align-items:center; }
.session-load-btn { background:transparent; border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); font-family:'IM Fell English',serif; font-size:12px; padding:5px 12px; border-radius:2px; cursor:pointer; letter-spacing:1px; flex:1; min-width:0; transition:all 0.15s; }
.session-load-btn:hover { background:rgba(200,146,42,0.12); border-color:var(--lodge-amber); }
.session-more-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-size:14px; padding:5px 9px; border-radius:2px; cursor:pointer; line-height:1; flex-shrink:0; transition:all 0.15s; }
.session-more-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-muted); }
.session-item.actions-open .session-more-btn { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); }
.session-item-more-actions { display:none; grid-template-columns:1fr 1fr; gap:6px; padding-top:8px; margin-top:2px; border-top:1px solid var(--lodge-border); }
.session-item.actions-open .session-item-more-actions { display:grid; }
.session-item-more-actions button { width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.session-witness-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; transition:all 0.15s; }
.session-witness-btn:hover { border-color:var(--lodge-ash); color:var(--lodge-muted); background:rgba(154,138,116,0.08); }
.session-delete-btn { background:transparent; border:1px solid #3a1a1a; color:#7a4040; font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; transition:all 0.15s; }
.session-delete-btn:hover { border-color:#7a3030; color:#c07070; background:rgba(120,40,40,0.1); }
/* Thread styles */
.thread-header { grid-column:1 / -1; padding:10px 14px 6px; border-bottom:1px solid var(--lodge-border); display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.thread-header-name { font-size:16px; color:var(--lodge-amber); letter-spacing:0.5px; }
.thread-header-count { font-family:'IM Fell English',serif; font-size:11px; color:var(--lodge-ash); letter-spacing:1px; }
.thread-clear-btn { background:none; border:none; color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; cursor:pointer; margin-left:auto; letter-spacing:1px; }
.thread-clear-btn:hover { color:var(--lodge-muted); }
.session-thread-badge { font-family:'IM Fell English',serif; font-size:10px; letter-spacing:1px; background:rgba(122,84,24,0.2); border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); padding:1px 6px; border-radius:2px; cursor:pointer; margin-left:4px; }
.session-thread-badge:hover { background:rgba(200,146,42,0.2); }
.session-branch-badge { font-family:'IM Fell English',serif; font-size:10px; letter-spacing:1px; background:rgba(90,90,90,0.2); border:1px solid var(--lodge-border); color:var(--lodge-muted); padding:1px 6px; border-radius:2px; margin-left:4px; }
.session-thread-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; }
.session-thread-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-muted); }
.session-reconvene-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; transition:all 0.15s; }
.session-reconvene-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); background:rgba(200,146,42,0.05); }
.thread-picker { margin-top:8px; display:flex; flex-direction:column; gap:5px; padding:10px; background:var(--lodge-panel); border:1px solid var(--lodge-amber-dim); border-radius:2px; }
.thread-picker-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:2px; }
.thread-picker-close { background:none; border:none; color:var(--lodge-ash); font-size:12px; cursor:pointer; padding:0 2px; line-height:1; }
.thread-picker-close:hover { color:var(--lodge-cream); }
.thread-pick-label { font-family:'IM Fell English',serif; font-size:10px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-ash); }
.thread-new-row { display:flex; gap:6px; align-items:center; }
.thread-pick-btn { background:none; border:1px solid var(--lodge-border); color:var(--lodge-muted); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:2px; cursor:pointer; text-align:left; letter-spacing:1px; }
.thread-pick-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-cream); }
.thread-pick-clear { color:#7a4040; border-color:#3a1a1a; }
.thread-pick-clear:hover { color:#c07070; border-color:#7a3030; }

.sessions-search-row { padding:8px 12px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.sessions-search-input { width:100%; background:var(--lodge-surface); border:1px solid var(--lodge-border); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:14px; padding:6px 10px; border-radius:2px; }
.sessions-search-input:focus { outline:none; border-color:var(--lodge-amber-dim); }
.sessions-search-input::placeholder { color:var(--lodge-ash); font-style:italic; }
.session-tags-row { display:flex; flex-wrap:wrap; gap:5px; align-items:center; }
.session-tag { font-family:'IM Fell English',serif; font-size:10px; letter-spacing:1px; background:rgba(200,146,42,0.12); border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); padding:2px 7px; border-radius:2px; cursor:pointer; user-select:none; display:inline-flex; align-items:center; gap:4px; }
.session-tag:hover { background:rgba(200,146,42,0.22); }
.tag-remove { font-size:11px; line-height:1; opacity:0.5; cursor:pointer; }
.tag-remove:hover { opacity:1; }
.session-tag-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; }
.session-tag-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-muted); }
.tag-input { background:var(--lodge-surface); border:1px solid var(--lodge-amber-dim); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:12px; padding:2px 6px; border-radius:2px; width:80px; }

/* ─── Comparative mode ─────────────────────────────────────────────────── */
.compare-bar { display:none; align-items:center; gap:10px; padding:8px 12px; background:rgba(200,146,42,0.08); border-bottom:1px solid var(--lodge-amber-dim); flex-shrink:0; }
.compare-bar-hint { font-family:'IM Fell English',serif; font-style:italic; font-size:12px; color:var(--lodge-amber); flex:1; }
.compare-bar-go { font-size:12px; padding:5px 14px; }
.compare-bar-cancel { background:none; border:none; color:var(--lodge-ash); cursor:pointer; font-size:14px; line-height:1; padding:2px 6px; }
.compare-bar-cancel:hover { color:var(--lodge-cream); }
.session-compare-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; }
.session-compare-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-muted); }
.session-compare-btn.active { border-color:var(--lodge-amber); color:var(--lodge-amber); background:rgba(200,146,42,0.1); }
.session-publish-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; transition:all 0.15s; }
.session-publish-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); background:rgba(200,146,42,0.05); }
.session-publish-btn.is-published { border-color:var(--lodge-amber); color:var(--lodge-amber); }
.session-published-badge { font-family:'IM Fell English',serif; font-size:10px; letter-spacing:1px; background:rgba(200,146,42,0.15); border:1px solid var(--lodge-amber); color:var(--lodge-amber); padding:1px 6px; border-radius:2px; margin-left:4px; text-decoration:none; }
.session-published-badge:hover { background:rgba(200,146,42,0.28); }
.session-publish-hint { font-family:'Crimson Pro',serif; font-style:italic; font-size:10px; color:var(--lodge-ash); line-height:1.4; }
/* #178: reuses .session-publish-btn's look — only shown once a session is published */
.session-curate-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; transition:all 0.15s; }
.session-curate-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-amber); background:rgba(200,146,42,0.05); }
.compare-overlay { position:fixed; inset:0; background:var(--lodge-bg); z-index:200; display:flex; flex-direction:column; }
.compare-header { display:flex; align-items:center; justify-content:space-between; padding:14px 20px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.compare-title { font-family:'IM Fell English',serif; font-size:14px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-amber); }
.compare-panels { display:flex; flex:1; overflow:hidden; gap:1px; background:var(--lodge-border); }
.compare-panel { flex:1; overflow-y:auto; background:var(--lodge-bg); display:flex; flex-direction:column; }
.compare-panel-header { padding:16px 20px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.compare-panel-date { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:2px; color:var(--lodge-amber); margin-bottom:4px; }
.compare-panel-members { font-family:'IM Fell English',serif; font-size:12px; color:var(--lodge-muted); margin-bottom:6px; }
.compare-panel-source { font-family:'Crimson Pro',serif; font-style:italic; font-size:14px; color:var(--lodge-cream); line-height:1.5; }
.compare-panel-transcript { padding:16px 20px; flex:1; }

/* ─── Dossier drawer (slides from right, below sessions drawer) ────────── */
.dossier-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:100; }
.dossier-overlay.open { display:block; }
.dossier-drawer { position:fixed; top:0; right:0; width:360px; max-width:96vw; height:100vh; background:var(--lodge-panel); border-left:1px solid var(--lodge-border); z-index:101; display:flex; flex-direction:column; transform:translateX(100%); transition:transform 0.25s ease; overflow:hidden; }
.dossier-drawer.open { transform:translateX(0); }
.dossier-body { flex:1; overflow-y:auto; padding:12px; display:flex; flex-direction:column; gap:12px; }
.dossier-entry { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:12px 14px; transition:border-color 0.2s; }
.dossier-entry.highlighted { border-color:var(--lodge-amber); background:rgba(200,146,42,0.06); }
.dossier-header { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.dossier-portrait { width:48px; height:48px; border-radius:50%; object-fit:cover; border:1px solid var(--lodge-border); flex-shrink:0; }
.dossier-name { font-size:18px; color:var(--lodge-amber); letter-spacing:1px; }
.dossier-section-label { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-muted); margin-bottom:4px; }
.dossier-text { font-family:'Crimson Pro',serif; font-size:15px; line-height:1.6; color:var(--lodge-muted); }
.dossier-toggle { background:none; border:none; color:var(--lodge-muted); font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; cursor:pointer; margin-top:8px; padding:0; text-transform:uppercase; }
.dossier-toggle:hover { color:var(--lodge-muted); }
.dossier-voice { display:none; margin-top:10px; }
.dossier-voice.open { display:block; }

/* ─── Export destination picker (#345) ─────────────────────────────────── */
/* Preserve's menu used to list every destination as a full-width button,
   plus a separate drawer with every destination's config fields shown at
   once. Now the menu holds a row of small destination icons and one focused
   panel below them for whichever destination is selected (export.js's
   selectDestination toggles [hidden] on the rest). .settings-field and
   .ulysses-group-input are the same field styling the old drawer used --
   kept as-is, just relocated into the per-destination panels below. */
.export-picker { min-width:280px; gap:10px; padding:10px; }
.export-icon-row { display:flex; flex-wrap:wrap; gap:6px; }
.export-icon { background:transparent; border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); font-family:'IM Fell English',serif; font-size:12px; padding:6px 9px; border-radius:2px; cursor:pointer; letter-spacing:0.5px; transition:all 0.2s; white-space:nowrap; }
.export-icon:hover { background:rgba(200,146,42,0.1); border-color:var(--lodge-amber); }
.export-icon:disabled { opacity:0.4; cursor:not-allowed; }
.export-icon.active { background:rgba(200,146,42,0.18); border-color:var(--lodge-amber); }
.export-icon.export-dayone { border-color:#5a8a5a; color:#90c890; }
.export-icon.export-dayone:hover, .export-icon.export-dayone.active { background:rgba(90,138,90,0.15); }
.export-icon.export-txt { border-color:#6a7a8a; color:#a0b8c8; }
.export-icon.export-txt:hover, .export-icon.export-txt.active { background:rgba(100,130,150,0.15); }
.export-icon.export-ulysses { border-color:#7a6a9a; color:#b8a8d8; }
.export-icon.export-ulysses:hover, .export-icon.export-ulysses.active { background:rgba(120,100,160,0.15); }
.export-icon.export-obsidian { border-color:#5a7a5a; color:#90c890; }
.export-icon.export-obsidian:hover, .export-icon.export-obsidian.active { background:rgba(80,130,80,0.15); }
.export-dest-config { display:flex; flex-direction:column; gap:10px; }
.export-dest-hint { font-family:'IM Fell English',serif; font-style:italic; font-size:12px; color:var(--lodge-muted); margin:0; padding:2px; }
.citation-verify-row { font-family:'IM Fell English',serif; font-style:italic; font-size:12px; color:var(--lodge-muted); }
.citation-verify-row[hidden] { display:none; }
.citation-verify-link { font:inherit; font-style:normal; background:transparent; border:none; padding:0; margin-left:4px; color:var(--lodge-amber); cursor:pointer; text-decoration:underline; text-underline-offset:2px; }
.citation-verify-link:hover { color:var(--lodge-amber-dim); }
.export-dest-panel { display:flex; flex-direction:column; gap:10px; padding-top:8px; border-top:1px solid var(--lodge-border); }
.export-dest-panel[hidden] { display:none; }
.export-dest-desc { font-family:'Crimson Pro',serif; font-size:13px; font-style:italic; color:var(--lodge-muted); margin:0; }
.settings-field { display:flex; flex-direction:column; gap:6px; }
.settings-field > span:first-child { font-family:'IM Fell English',serif; font-size:12px; font-style:italic; letter-spacing:0.5px; color:var(--lodge-muted); }
.settings-field .ulysses-group-input { width:100%; font-size:14px; padding:8px 10px; }

/* ─── Metrics drawer ───────────────────────────────────────────────────── */

/* Metrics drawer (#191) — reuses .sessions-drawer-header/.sessions-close-btn
   chrome; only the overlay/drawer shell and body content are new. */
.metrics-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.55); z-index:100; }
.metrics-overlay.open { display:block; }
.metrics-drawer { position:fixed; top:0; right:0; width:380px; max-width:96vw; height:100vh; background:var(--lodge-panel); border-left:1px solid var(--lodge-border); z-index:101; display:flex; flex-direction:column; transform:translateX(100%); transition:transform 0.25s ease; }
.metrics-drawer.open { transform:translateX(0); }
.metrics-body { flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:10px; }
.metrics-summary { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.metrics-stat { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:10px 12px; display:flex; flex-direction:column; gap:2px; }
.metrics-stat-value { font-family:'IM Fell English',serif; font-size:20px; color:var(--lodge-amber); line-height:1.1; }
.metrics-stat-label { font-family:'Crimson Pro',serif; font-size:11px; color:var(--lodge-muted); letter-spacing:0.5px; }
.metrics-note { font-family:'Crimson Pro',serif; font-style:italic; font-size:12px; color:#c07070; }
.metrics-table { width:100%; border-collapse:collapse; font-family:'Crimson Pro',serif; font-size:12px; }
.metrics-table th { text-align:left; color:var(--lodge-ash); font-weight:normal; letter-spacing:0.5px; padding:4px 6px; border-bottom:1px solid var(--lodge-border); }
.metrics-table td { padding:4px 6px; color:var(--lodge-cream); border-bottom:1px solid var(--lodge-border); }
.metrics-table td:first-child { color:var(--lodge-muted); }
.metrics-row-silent td { color:var(--lodge-ash); font-style:italic; }
.metrics-silent-tag { font-style:italic; font-size:10px; letter-spacing:0.5px; color:#c07070; }
.metrics-reasoning { background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:10px 12px; }
.metrics-reasoning-tag { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:1px; color:var(--lodge-amber); margin-bottom:4px; }
.session-metrics-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:4px 6px; border-radius:2px; cursor:pointer; letter-spacing:0; text-align:center; }
.session-metrics-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-muted); }

/* ─── Publish curation modal (#178) ────────────────────────────────────── */
.publish-curate-row { display:flex; align-items:flex-start; gap:10px; padding:8px 0; border-bottom:1px solid var(--lodge-border); font-family:'Crimson Pro',serif; font-size:14px; color:var(--lodge-cream); cursor:pointer; }
.publish-curate-row:last-child { border-bottom:none; }
.publish-curate-check { margin-top:3px; flex-shrink:0; accent-color:var(--lodge-amber); }

/* ─── Add member modal ─────────────────────────────────────────────────── */
.add-member-btn { border-style:dashed; border-color:var(--lodge-ash); color:var(--lodge-muted); font-size:12px; padding:5px 14px; }
.add-member-btn:hover { border-color:var(--lodge-amber-dim); color:var(--lodge-cream); }
.modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.55); z-index:100; }
.modal-overlay.open { display:block; }
.modal-drawer { position:fixed; top:0; right:0; width:420px; max-width:96vw; height:100vh; background:var(--lodge-panel); border-left:1px solid var(--lodge-border); z-index:101; display:flex; flex-direction:column; transform:translateX(100%); transition:transform 0.25s ease; overflow-y:auto; }
.modal-drawer.open { transform:translateX(0); }
.modal-header { display:flex; align-items:center; justify-content:space-between; padding:16px 18px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.modal-title { font-family:'IM Fell English',serif; font-size:14px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-amber); }
.modal-body { padding:18px; display:flex; flex-direction:column; }

/* ─── Stage & record panes (#184) ──────────────────────────────────────── */

/* ── #184: the stage + the record ─────────────────────────────────────────────
   Two permanent, bounded panes stacked vertically — never one swapped for the
   other (the old toggleLive() DOM re-parenting is gone). The stage plays a
   live convene as it streams, or a past session paced beat-by-beat (#90); the
   record is the same conversation rendered continuously in its own scrolling
   window, so a long session never grows the page. Heights are viewport-
   relative with floors/caps rather than exactly equal — see
   docs/archive/DESIGN-184-STAGE-DEFAULT.md for why "similar" beats "identical" here.

   Revision: only one pane is ever VISIBLE at a time (.stage-only vs
   .collapsed, toggled by witness.js) — showing the same streaming text in
   both was unreadable, not "linked." See docs/archive/DESIGN-184-STAGE-DEFAULT.md's
   Revision section and witness.js's collapseStage()/reopenStage().

   #358: the third state -- neither class present, i.e. the page at rest
   before any convene -- used to mean "both panes visible, roughly halved"
   (54vh/44vh below), which is exactly the layout this issue exists to fix:
   a small room sharing space with an empty record. witness.js never reads
   or branches on .stage-only/.collapsed (grepped: only ever set/removed),
   so redefining what "neither class" looks like is safe -- nothing treats
   it as a meaningful third state to preserve. The room is the resting
   default now: big stage-pane, hidden record-pane, same shape as
   .stage-only but sized for "the empty room, at rest" rather than "a live
   performance," which gets the taller/more-committed 75vh below. Loading a
   past meeting (sessions.js restoreSession) explicitly calls collapseStage()
   so its transcript actually surfaces instead of sitting hidden behind a
   resting room with no visible way back to it. */
.stage-record { display:flex; flex-direction:column; background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; overflow:hidden; }

.stage-pane { display:flex; flex-direction:column; height:64vh; min-height:420px; max-height:760px; border-bottom:1px solid var(--lodge-border); background:var(--lodge-bg); }
.stage-record.collapsed .stage-pane { display:none; }
.stage-record.stage-only .stage-pane { height:75vh; max-height:820px; }

/* Shown only when the stage is exited/collapsed — reopens it without
   restarting a live convene or stopping the record's growth (#184: "exiting
   mid-convene does not stop the convene"). Reuses the existing ◎ Watch
   vocabulary rather than inventing a new control. */
.stage-collapsed-bar { display:none; width:100%; background:transparent; border:none; border-bottom:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase; padding:10px; cursor:pointer; text-align:center; transition:all 0.15s; }
.stage-collapsed-bar:hover { color:var(--lodge-muted); background:rgba(154,138,116,0.06); }
.stage-record.collapsed .stage-collapsed-bar { display:block; }

/* .stage-only is .collapsed's mirror image: the record stays hidden (not
   just shorter) while the stage is showing, so the same streaming text is
   never visible in both places at once. See witness.js's revision comment
   atop collapseStage()/reopenStage(). Hidden by default now too (#358) —
   see the note atop .stage-pane above. */
.record-pane { display:none; flex-direction:column; height:44vh; min-height:220px; max-height:480px; }
.stage-record.collapsed .record-pane { display:flex; height:75vh; max-height:820px; }
/* .record-pane carries .transcript-panel for the shared panel background/
   border/padding rule above — reset padding here since the toolbar and
   scroll region below supply their own. */
.transcript-panel.record-pane { padding:0; }

.record-toolbar { display:flex; align-items:center; justify-content:space-between; padding:10px 16px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.record-label { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-ash); }
/* Stick-to-bottom scroll (#184): hidden while the record auto-follows new
   speech; shown the moment the user scrolls up, so re-attaching is a
   deliberate click rather than losing their place on the next line. */
.record-live-pill { display:none; background:rgba(200,146,42,0.12); border:1px solid var(--lodge-amber-dim); color:var(--lodge-amber); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:12px; cursor:pointer; letter-spacing:1px; }
.record-live-pill:hover { background:rgba(200,146,42,0.2); }
.record-live-pill.visible { display:inline-block; }

.record-scroll { flex:1 1 auto; overflow-y:auto; min-height:0; padding:16px; }

/* #358 — a narrow viewport is also a *tall* one (375x812 etc.), and a plain
   vh-based height here turns the canvas portrait (verified live: 375x422,
   an 0.9:1 aspect) rather than the letterboxed wide-short shape the camera
   in scene.js was actually framed for -- HEARTH_ANGLE and the seat ring both
   assume the horizontal FOV a wide aspect gives you, and a portrait canvas
   under-frames the room (mostly ceiling/floor, the hearth pushed to the
   edge or out of frame). min(vh, vw*ratio) caps the height by width too, so
   the canvas stays wide-short on any screen shape instead of just shrinking
   proportionally. */
@media (max-width: 768px) {
  .stage-pane { height:min(52vh, 58vw); min-height:240px; max-height:none; }
  .stage-record.collapsed .record-pane { height:62vh; min-height:180px; max-height:none; }
  .stage-record.stage-only .stage-pane { height:min(65vh, 66vw); }
}

/* ─── Witness mode — room, stage playback & keyframes ──────────────────── */

.witness-controls { display:flex; align-items:center; gap:12px; padding:10px 16px; border-bottom:1px solid var(--lodge-border); flex-shrink:0; }
.witness-label { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase; color:var(--lodge-ash); }
.witness-hint { font-family:'IM Fell English',serif; font-size:12px; color:var(--lodge-border); font-style:italic; flex:1; text-align:center; }
.witness-exit-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:2px; cursor:pointer; letter-spacing:1px; }
.witness-exit-btn:hover { border-color:var(--lodge-ash); color:var(--lodge-muted); }
.witness-speed-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:2px; cursor:pointer; letter-spacing:1px; min-width:34px; }
.witness-speed-btn:hover { border-color:var(--lodge-ash); color:var(--lodge-muted); }
/* #506 */
.witness-recap-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:2px; cursor:pointer; letter-spacing:1px; }
.witness-recap-btn:hover { border-color:var(--lodge-ash); color:var(--lodge-muted); }
/* #29 */
.witness-voice-btn { background:transparent; border:1px solid var(--lodge-border); color:var(--lodge-ash); font-family:'IM Fell English',serif; font-size:11px; padding:3px 10px; border-radius:2px; cursor:pointer; letter-spacing:1px; }
.witness-voice-btn:hover { border-color:var(--lodge-ash); color:var(--lodge-muted); }
.witness-voice-btn.voice-on { border-color:var(--lodge-fire); color:var(--lodge-fire); }
.witness-progress { height:2px; background:var(--lodge-amber); width:0%; transition:width 0.4s ease; flex-shrink:0; }
.witness-stage { flex:1 1 auto; min-height:0; overflow-y:auto; padding:24px 32px 20px; cursor:pointer; display:flex; flex-direction:column; gap:0; scroll-behavior:smooth; }
/* The room (#257): same slot as .witness-stage, mutually exclusive with it --
   whichever is active is the only stage there is (the old #202 Text/Room
   toggle is retired). .room-active is added once, by witness.js's
   enableRoom(), the moment the 3D scene actually initializes (app.js's
   initSceneLayer); .witness-stage's bubble rendering is what's left showing
   when it never does. */
.witness-room { display:none; position:relative; flex:1 1 auto; min-height:0; background:var(--lodge-bg); cursor:pointer; }
.witness-room canvas { width:100%; height:100%; display:block; outline:none; }
.stage-pane.room-active .witness-stage { display:none; }
.stage-pane.room-active .witness-room { display:flex; }

/* Dialogue composited into the room (#257): a DOM speech card per seated
   member, positioned in witness.js's repositionRoomCards() from
   LodgeScene.getSeatScreenPosition's screen-space projection of their
   portrait billboard (Vector3.Project layered over the WebGL canvas -- the
   standard "world-space UI" pattern). room-speech-layer covers the canvas
   exactly and stays click-through (pointer-events:none) except where a card
   actually is, so clicking the room still advances replay. */
.room-speech-layer { position:absolute; inset:0; pointer-events:none; }
/* #291: a longer beat (especially with an italic action note attached) can
   grow taller than the room itself -- the card grows upward from its seat
   anchor (translateY(-100%) below) with no cap, and repositionRoomCards'
   top-overflow correction only nudges its position, it doesn't bound its
   height. Past a point the card simply exceeds .stage-record's overflow:hidden
   box and its earliest lines are clipped off-screen with no way to read them.
   max-height + overflow-y:auto turns that into an internal scroll instead of
   silent clipping; the 100% basis resolves against room-speech-layer's own
   height (inset:0 over witness-room, which has a definite height from its
   fixed-height flex ancestor .stage-pane), so this scales with the room
   itself rather than a hardcoded pixel guess. Width bumped from 240px per
   the issue's other question (#291) -- wider wrapping means fewer lines for
   the same beat, so most turns never need to hit the scroll cap at all. */
.room-speech-card {
  position:absolute; transform:translate(-50%, -100%); margin-top:-14px;
  max-width:300px; max-height:min(320px, calc(100% - 40px)); overflow-y:auto; overscroll-behavior:contain;
  background:rgba(14,11,8,0.92); border:1px solid var(--lodge-border);
  border-radius:3px; padding:10px 12px; pointer-events:auto;
  transition:opacity 0.5s ease; opacity:1;
}
.room-speech-card.room-card-fading { opacity:0; }
/* #287 fix: the header is the card's first child, inside the same
   overflow:auto region as the entries below it -- scrolling to the newest
   entry (scrollCardToLatest in witness.js) was pushing it out of view
   entirely once a stack grew past one screenful, leaving a card of text
   with no name attached (reported live). Sticky pins it to the scroll
   container's top edge regardless of how far the entries beneath scroll. */
.room-speech-card .speaker-name {
  font-size:13px; margin-bottom:3px;
  position:sticky; top:0; z-index:1;
  background:rgba(14,11,8,0.92); padding-bottom:4px;
}
.room-speech-card .speech-text { font-family:'Crimson Pro',serif; font-size:14px; line-height:1.6; color:var(--lodge-cream); }
.room-speech-card .witness-annotation { font-size:12px; }
/* #287: a member's card is a short-lived stack, not a single overwritten
   beat -- each new turn appends a .room-card-entry instead of replacing the
   card's content, so the last few beats stay visible and, once they outgrow
   max-height above, scrollable -- the same overflow:auto that #291 gave a
   single overlong beat now doubles as the stack's scrollback. Older entries
   are dimmed so they read as backscroll behind the live one, which always
   stays scrolled into view (scrollCardToLatest in witness.js). The whole
   stack still fades together on inactivity (room-card-fading above): this
   is short-lived scrollback for the current burst of speech, not a
   standing history rail. */
.room-card-entries { display:flex; flex-direction:column; gap:10px; }
.room-card-entry:not(:last-child) { opacity:0.55; }
.room-card-entry + .room-card-entry { padding-top:10px; border-top:1px solid var(--lodge-border); }
.room-card-entry-typing .speech-text::after { content:'▍'; opacity:0.6; animation:witnessCursorBlink 1s step-end infinite; }

/* #457 — splinter/aside visual grammar. A splinter beat gets a plain-text
   "aside" tag (speechBodyHtml, both room cards and the stage-fallback
   bubbles below) plus this dimmed/dashed treatment on its own container --
   text alone carries the distinction, color/border is reinforcement, not
   the only signal. Deliberately no room-wide dimming or camera change: the
   two participants' own styling plus the connector line below is the whole
   grammar for a first pass (see room-thread-layer's comment for why not
   portrait rotation). */
.room-card-entry.card-entry-aside { opacity:0.85; }
.room-card-entry.card-entry-aside .speech-text { font-style:italic; color:var(--lodge-muted); }
/* #579 — a confessional is one member thinking at length, apart from the
   room: the "confessional" tag (speechBodyHtml) carries the meaning, and a
   quiet double rule at the left edge sets it off as a different kind of
   text from the room's exchange. Deliberately not the aside's dimmed
   italic — this is the long form being read, not an overheard murmur — and
   no accent color, since nothing here is clickable. */
.room-card-entry.card-entry-confessional { border-left:3px double var(--lodge-border); padding-left:10px; }
.thread-tag {
  font-family:'IM Fell English',serif; font-size:10px; letter-spacing:1.5px;
  text-transform:uppercase; color:var(--lodge-ash); opacity:0.75; margin-bottom:3px;
}
/* room-thread-layer sits beneath room-speech-layer (painted first in DOM
   order) so its connector line never blocks a card's own click target --
   pointer-events:none on the whole layer means it wouldn't anyway, but the
   ordering also keeps the line visually behind the cards it joins. One
   <line> per active splinter (witness.js's updateThreadConnectors), x1/y1/
   x2/y2 set from the same getSeatScreenPosition projection the cards
   anchor to. */
.room-thread-layer { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; overflow:visible; }
.room-thread-line { stroke:var(--lodge-amber-dim); stroke-width:1; stroke-dasharray:3 5; opacity:0.55; }

/* Round headers, lulls, and unattributed action lines aren't anchored to any
   one member's seat -- they read into a small fixed strip at the top of the
   room instead of a card. Not scrollable (unlike the stage): a bounded
   strip that clips older entries is a deliberate rough edge (#257), not a
   history the room is meant to hold. */
.room-events { position:absolute; top:12px; left:50%; transform:translateX(-50%); max-height:130px; overflow:hidden; display:flex; flex-direction:column; align-items:center; gap:6px; pointer-events:none; }
.room-events > * { pointer-events:auto; }
.room-events .witness-round-header,
.room-events .transcript-lull { width:300px; }
.room-events .action-line { color:var(--lodge-muted); font-style:italic; font-size:13px; }

/* #34: the document-as-object reading panel. Opened by scene.js's book-click
   handler (via the onDocumentInspect callback app.js registers with
   LodgeScene.init) at the same moment the camera eases in on the book mesh
   -- this is the "zoom into a passage" affordance for a first cut: the full
   document, readable and scrollable, not per-passage highlighting synced to
   citations (deliberately deferred, see scene.js's own #34 comment). Sized
   and positioned like room-speech-card above (a floating parchment sheet
   over the room, not a full-bleed modal) so it reads as an object being
   examined rather than a page navigation. */
.document-inspect-panel {
  position:absolute; top:50%; left:50%; transform:translate(-50%, -50%);
  width:min(480px, calc(100% - 48px)); max-height:calc(100% - 56px);
  overflow-y:auto; overscroll-behavior:contain;
  background:var(--lodge-parchment); border:1px solid var(--lodge-border);
  border-radius:3px; padding:16px 20px 20px; box-shadow:0 12px 32px rgba(0,0,0,0.5);
}
.document-inspect-close {
  position:sticky; top:0; float:right; margin:-4px -8px 4px 8px;
  background:none; border:none; cursor:pointer;
  font-family:'IM Fell English',serif; font-size:12px; letter-spacing:2px; text-transform:uppercase;
  color:var(--lodge-border);
}
.document-inspect-close:hover { color:var(--lodge-fire); }
.document-inspect-text {
  clear:both; font-family:'Crimson Pro',serif; font-size:16px; line-height:1.7;
  color:var(--lodge-bg); white-space:pre-wrap;
}
/* #34 follow-up: the passage a live citation (#355) matched against this
   document, for the duration scene.js's citeFromBeat pulse holds it. Warm
   fire-toned background rather than a plain yellow highlight, consistent
   with the room's own palette. */
.document-citation-mark {
  background:var(--lodge-fire); color:var(--lodge-parchment);
  border-radius:2px; padding:0 2px;
}
.witness-stage .transcript-entry { max-width:70%; }
.witness-stage .speaker-name { font-size:22px; }
.witness-stage .speech-text { font-size:17px; }
.witness-stage .action-line { opacity:0; animation:witnessfade-dim 0.5s ease forwards; }
@keyframes witnessfade-dim { from{opacity:0;transform:translateY(8px)} to{opacity:0.8;transform:translateY(0)} }
/* #257: pre-existing gap found while verifying the room's event strip --
   .witness-round-header/.transcript-lull below reference this animation but
   it was never defined, so both (and any buttons appended into a live lull,
   e.g. Continue/Let it end) rendered stuck at opacity:0 in the text stage
   too, not just here. Fixing the keyframe rather than the (correct)
   animation references. */
@keyframes witnessfade { from{opacity:0} to{opacity:1} }
.witness-stage .transcript-entry { opacity:0; animation:witnessslide 0.5s ease forwards; }
.witness-round-header { display:flex; align-items:center; gap:12px; opacity:0; animation:witnessfade 0.6s ease forwards; }
.witness-rule { flex:1; height:1px; background:var(--lodge-border); }
.witness-round-label { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:3px; text-transform:uppercase; color:var(--lodge-ash); white-space:nowrap; }
/* #184: live rounds mirror into the stage using the same .transcript-round-header/
   .round-rule markup the record uses, via witness.js's renderWitnessBlock — a
   second, lighter render, not a DOM move (see the comment atop witness.js). */
.witness-stage .transcript-round-header { opacity:0; animation:witnessfade 0.6s ease forwards; }
.witness-stage .round-rule { background:var(--lodge-border); }
.witness-stage .round-rule-label { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:3px; text-transform:uppercase; color:var(--lodge-ash); white-space:nowrap; }
/* #245: the stage's copy of the lull. Same markup as the record's, on the
   stage's own scale, and it fades in like every other performed beat. This is
   the copy the user actually acts on during a live meeting — the record is
   hidden behind .stage-only while the room is speaking. */
.witness-stage .transcript-lull { opacity:0; animation:witnessfade 0.6s ease forwards; margin:26px 0 22px; }
.witness-stage .lull-note { font-size:14px; color:var(--lodge-ash); }
.witness-stage .transcript-typing .speaker-name { opacity:0.9; }
.witness-stage .transcript-typing .typing-text { font-family:'Crimson Pro',serif; font-size:17px; line-height:1.8; color:var(--lodge-cream); }
.witness-stage .transcript-typing .typing-text::after { content:'▍'; opacity:0.6; animation:witnessCursorBlink 1s step-end infinite; }
@keyframes witnessCursorBlink { 50% { opacity:0; } }
.witness-stage:empty::before { content:'The room is quiet. Convene to begin.'; display:block; text-align:center; margin-top:60px; font-family:'IM Fell English',serif; font-style:italic; font-size:14px; color:var(--lodge-muted); }
.witness-speaker { font-size:22px; color:var(--lodge-amber); letter-spacing:1px; display:flex; align-items:baseline; gap:8px; opacity:0; animation:witnessslide 0.5s ease forwards; }
.witness-speech { font-family:'Crimson Pro',serif; font-size:17px; line-height:1.8; color:var(--lodge-cream); max-width:680px; opacity:0; animation:witnessslide 0.5s ease 0.15s forwards; }
.witness-annotation { font-family:'Crimson Pro',serif; font-size:14px; font-style:italic; color:var(--lodge-ash); margin-top:4px; padding-left:16px; border-left:2px solid var(--lodge-border); opacity:0; animation:witnessslide 0.5s ease 0.3s forwards; }
/* Ghost: same element, class swap — use transition not animation so it visibly dims in place */
.witness-end { font-family:'IM Fell English',serif; font-size:14px; font-style:italic; color:var(--lodge-ash); text-align:center; letter-spacing:1px; opacity:0; animation:witnessslide 0.5s ease forwards; }
@keyframes witnessslide {
  from { opacity:0; transform:translateY(8px); }
  to   { opacity:1; transform:translateY(0); }
}
@keyframes witnessface {
  from { opacity:0; } to { opacity:1; }
}

/* ─── Lodge page (#84 — member page + knowledge graph) ─────────────────── */

.lodge-page-root { min-height:100vh; display:flex; flex-direction:column; }
.lodge-page-header { display:flex; align-items:center; gap:20px; padding:18px 24px; border-bottom:1px solid var(--lodge-border); background:linear-gradient(180deg,#0a0704 0%,var(--lodge-panel) 100%); }
.lodge-page-back { font-family:'IM Fell English',serif; font-size:13px; color:var(--lodge-muted); text-decoration:none; letter-spacing:0.5px; white-space:nowrap; }
.lodge-page-back:hover { color:var(--lodge-amber); }
.lodge-page-title-block { flex:1; }
.lodge-page-title { font-size:22px; }
.lodge-page-stats { font-family:'Crimson Pro',serif; font-size:12px; color:var(--lodge-ash); white-space:nowrap; }

.lodge-page-graph-wrap { padding:16px 24px 0; }
.graph-toolbar { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:10px; }
.graph-search-input { max-width:280px; flex:none; }
/* #296 — one legend, not two: node shapes (the type-filter checkboxes) and
   edge-origin colors used to live in unrelated places (toolbar vs. a
   floating box over the canvas) with no visual signal they were both keys
   to the same graph. Grouped into a single row with a divider between the
   two kinds of key. */
.graph-legend { display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.graph-legend-divider { width:1px; align-self:stretch; min-height:18px; background:var(--lodge-border); }
.graph-type-toggles { display:flex; gap:14px; flex-wrap:wrap; }
.graph-type-toggle { font-family:'Crimson Pro',serif; font-size:14px; color:var(--lodge-muted); display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none; padding:4px 2px; }
.graph-type-toggle input { accent-color:var(--lodge-amber); width:16px; height:16px; }
/* #296 — glyphs colored to match each type's actual on-canvas fill (was a
   flat --lodge-muted for all three), so the checkbox you're reading is
   visibly the same color as the shape it filters, not just a generic bullet. */
.graph-legend-glyph { font-size:15px; line-height:1; }
.graph-legend-glyph-member { color:var(--lodge-graph-member-fill); }
.graph-legend-glyph-text { color:var(--lodge-graph-text-fill); }
.graph-legend-glyph-theme { color:var(--lodge-graph-theme-fill); }
.graph-edge-legend { display:flex; gap:10px; font-family:'Crimson Pro',serif; font-size:14px; color:var(--lodge-muted); flex-wrap:wrap; }
.graph-edge-legend-item { display:flex; align-items:center; gap:5px; white-space:nowrap; }
.graph-edge-legend-swatch { display:inline-block; width:14px; height:2px; }
.graph-edge-legend-historical { background:var(--lodge-fire); }
.graph-edge-legend-session { background:var(--lodge-muted); }
.graph-edge-legend-library { background:var(--lodge-graph-edge-library); }
.graph-reset-btn { margin-left:auto; }

.graph-svg-container { position:relative; width:100%; height:640px; background:var(--lodge-panel); border:1px solid var(--lodge-border); border-radius:2px; overflow:hidden; touch-action:none; }
#graph-svg { width:100%; height:100%; cursor:grab; }
#graph-svg:active { cursor:grabbing; }
.graph-zoom-hint { position:absolute; left:8px; bottom:8px; z-index:4; font-family:'IM Fell English',serif; font-style:italic; font-size:11px; color:var(--lodge-muted); background:rgba(23,18,13,0.8); padding:3px 8px; border-radius:2px; pointer-events:none; }
.graph-empty-hint { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-family:'IM Fell English',serif; font-style:italic; color:var(--lodge-muted); pointer-events:none; }
.graph-tooltip { position:absolute; z-index:5; background:var(--lodge-panel); border:1px solid var(--lodge-amber-dim); color:var(--lodge-cream); font-family:'Crimson Pro',serif; font-size:12px; line-height:1.5; padding:6px 10px; border-radius:2px; max-width:280px; pointer-events:none; box-shadow:0 4px 12px rgba(0,0,0,0.4); }
/* #296 — states what the dim/highlight split is showing in words, not just
   color, since "which node is the center and what's it connected to" was
   reported ambiguous even with the highlight in place. */
.graph-focus-caption { position:absolute; left:8px; top:8px; z-index:4; font-family:'Crimson Pro',serif; font-size:13px; color:var(--lodge-cream); background:rgba(23,18,13,0.85); border:1px solid var(--lodge-amber-dim); padding:4px 10px; border-radius:2px; pointer-events:none; }
.graph-focus-caption strong { color:var(--lodge-gold); }

/* #296 — baseline opacity lowered (was 0.7/0.8/0.85 across the board) so the
   default view reads as a soft mesh instead of a solid haze once you're past
   a couple hundred edges; historical edges (rare — hand-curated, 15 on the
   current roster) stay the most prominent since they're the highest-signal
   relationships, library edges (the bulk — mostly text↔theme "touches") stay
   the quietest since they're structural. Hover/select dimming (.dim) is
   unchanged. */
.graph-edge { stroke:var(--lodge-graph-edge-library); opacity:0.5; transition:opacity 0.15s; }
.graph-edge-historical { stroke:var(--lodge-fire); opacity:0.9; }
.graph-edge-session { stroke:var(--lodge-muted); opacity:0.6; }
.graph-edge-library { stroke:var(--lodge-graph-edge-library); opacity:0.45; }
.graph-edge.dim { opacity:0.06; }
/* #296 — an edge directly touching the focus node (not just a link between
   two of its neighbors) reads as thicker/brighter than the rest of the
   un-dimmed highlight set, so "what's connected to the thing I picked"
   doesn't require comparing it against everything else that merely survived
   dimming. */
.graph-edge.focus-touch { opacity:1; stroke-width:2.5px !important; }

.graph-node { cursor:pointer; }
.graph-node:focus-visible .graph-node-shape,
.lodge-roster-card:focus-visible,
.lodge-chip:focus-visible,
.lodge-text-item:focus-visible { outline:2px solid var(--lodge-amber); outline-offset:2px; }
.graph-node-shape { fill:var(--lodge-surface); stroke-width:1.5; transition:fill 0.15s, stroke 0.15s, transform 0.15s; transform-box:fill-box; transform-origin:center; }
.graph-node-member .graph-node-shape { fill:var(--lodge-graph-member-fill); stroke:var(--lodge-amber); }
.graph-node-text .graph-node-shape { fill:var(--lodge-graph-text-fill); stroke:var(--lodge-parchment); }
.graph-node-theme .graph-node-shape { fill:var(--lodge-graph-theme-fill); stroke:#9a86c0; }
/* #296 — three-tier hierarchy replacing a two-tier one (focus vs.
   everything-not-dimmed, which put a directly-connected neighbor and an
   unrelated node three hops away in the same visual bucket). .connected
   (a neighbor of the current focus) gets a brighter ring, no fill/size
   change. .node-focus (the focus itself — set on click OR hover, see
   lodge.js) gets both a size increase and a fill/stroke swap to colors
   that don't otherwise appear on the canvas (parchment/gold), since the
   previous amber-on-orange selected state was too close to the ordinary
   member fill to read as "this one" at a glance; .selected (click-only,
   independent of hover) keeps that same treatment so a clicked node still
   pops after the cursor moves away. */
.graph-node.connected .graph-node-shape { stroke:var(--lodge-parchment); stroke-width:2.5px; }
.graph-node.node-focus .graph-node-shape,
.graph-node.selected .graph-node-shape { fill:var(--lodge-gold); stroke:var(--lodge-parchment); stroke-width:2.5px; filter:drop-shadow(0 0 8px rgba(232,184,75,0.9)); transform:scale(1.35); }
.graph-node.dim { opacity:0.15; }
.graph-node-label { font-family:'Crimson Pro',serif; font-size:13px; fill:var(--lodge-muted); pointer-events:none; user-select:none; }
.graph-node-member .graph-node-label { font-size:14px; fill:var(--lodge-cream); font-weight:600; }
.graph-node.connected .graph-node-label { fill:var(--lodge-parchment); font-weight:600; }
.graph-node.node-focus .graph-node-label,
.graph-node.selected .graph-node-label { fill:var(--lodge-gold); font-weight:700; }

.lodge-page-body { flex:1; display:flex; gap:0; min-height:0; padding:16px 24px 24px; gap:20px; }
.lodge-page-roster { width:280px; flex-shrink:0; background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:14px; display:flex; flex-direction:column; gap:10px; max-height:calc(100vh - 260px); }
.lodge-roster-filter { width:100%; }
.lodge-roster-grid { overflow-y:auto; display:flex; flex-direction:column; gap:4px; }
.lodge-roster-card { display:flex; align-items:center; gap:8px; padding:6px 8px; border-radius:2px; cursor:pointer; border:1px solid transparent; transition:background 0.15s, border-color 0.15s, box-shadow 0.15s; }
.lodge-roster-card:hover { background:rgba(200,146,42,0.08); }
/* #240 — reflects the graph's hoveredId onto the matching roster card (see
   syncRosterHighlight in lodge.js); a lighter echo of .selected so the two
   panels visibly track each other on hover, not just on click. */
.lodge-roster-card.hovered { background:rgba(200,146,42,0.1); border-color:var(--lodge-amber-dim); }
.lodge-roster-card.selected { background:rgba(200,146,42,0.2); border-color:var(--lodge-amber); box-shadow:0 0 8px rgba(200,146,42,0.35); }
.lodge-roster-portrait { width:28px; height:28px; border-radius:50%; object-fit:cover; border:1px solid var(--lodge-border); flex-shrink:0; }
.lodge-roster-glyph { color:var(--lodge-amber); font-size:13px; width:16px; text-align:center; flex-shrink:0; }
.lodge-roster-name { font-family:'Crimson Pro',serif; font-size:14px; color:var(--lodge-cream); }

.lodge-page-detail { flex:1; min-width:0; background:var(--lodge-surface); border:1px solid var(--lodge-border); border-radius:2px; padding:20px; overflow-y:auto; max-height:calc(100vh - 260px); }
.lodge-detail-empty { font-family:'IM Fell English',serif; font-style:italic; color:var(--lodge-muted); text-align:center; margin-top:40px; }
.lodge-detail-header { display:flex; align-items:center; gap:14px; margin-bottom:14px; }
.lodge-detail-portrait { width:64px; height:64px; border-radius:50%; object-fit:cover; border:1px solid var(--lodge-border); flex-shrink:0; }
.lodge-detail-archive-image { border-radius:2px; }
.lodge-detail-name { font-size:24px; color:var(--lodge-amber); letter-spacing:1px; }
.lodge-detail-kind { font-family:'IM Fell English',serif; font-size:12px; letter-spacing:1px; text-transform:uppercase; color:var(--lodge-muted); margin-top:2px; }
.lodge-detail-section { margin-top:18px; }
.lodge-citation { font-style:italic; }
.lodge-source-link { display:inline-block; margin-top:6px; font-family:'Crimson Pro',serif; font-size:13px; color:var(--lodge-amber); text-decoration:none; }
.lodge-source-link:hover { text-decoration:underline; }
.lodge-excerpt { margin-top:6px; }

.lodge-chip-row { display:flex; flex-wrap:wrap; gap:6px; margin-top:4px; }
.lodge-chip { font-family:'Crimson Pro',serif; font-size:12px; padding:3px 10px; border-radius:12px; cursor:pointer; border:1px solid var(--lodge-border); transition:border-color 0.15s, color 0.15s; }
.lodge-chip-member { color:var(--lodge-amber); border-color:var(--lodge-amber-dim); }
.lodge-chip-member:hover { border-color:var(--lodge-amber); }
.lodge-chip-theme { color:#b0a0d8; border-color:#4a3f66; }
.lodge-chip-theme:hover { border-color:#9a86c0; }

.lodge-relationship-list { display:flex; flex-direction:column; gap:10px; margin-top:6px; }
.lodge-relationship { padding:8px 10px; background:var(--lodge-panel); border-left:2px solid var(--lodge-fire); border-radius:0 2px 2px 0; }
.lodge-relationship-type { font-family:'IM Fell English',serif; font-size:11px; letter-spacing:1px; text-transform:uppercase; color:var(--lodge-ash); }

.lodge-text-list { display:flex; flex-direction:column; gap:6px; margin-top:6px; }
.lodge-text-item { padding:8px 10px; background:var(--lodge-panel); border-radius:2px; cursor:pointer; transition:background 0.15s; }
.lodge-text-item:hover { background:rgba(200,146,42,0.08); }
.lodge-text-item-title { font-family:'Crimson Pro',serif; font-size:14px; color:var(--lodge-cream); }
.lodge-text-item-meta { font-family:'IM Fell English',serif; font-size:11px; font-style:italic; color:var(--lodge-ash); margin-top:2px; }

@media (max-width: 800px) {
  .lodge-page-body { flex-direction:column; }
  .lodge-page-roster { width:100%; max-height:220px; }
  .lodge-page-detail { max-height:none; }
}

/* #235 — mobile: the graph previously kept a fixed 900x520 layout scaled
   down 1:1 into whatever width the phone had, so node radii, spacing, and
   label text that read fine at desktop width became cramped and tiny at
   ~340-390px wide. Give the graph much more vertical room (it's the one
   dimension a phone has to spare) instead of shrinking everything into a
   letterbox, and stack/enlarge the toolbar for touch. */
@media (max-width: 640px) {
  .lodge-page-header { flex-wrap:wrap; gap:8px 16px; padding:14px 16px; }
  .lodge-page-title { font-size:19px; }
  .lodge-page-stats { width:100%; order:3; white-space:normal; }

  .lodge-page-graph-wrap { padding:12px 12px 0; }
  .graph-toolbar { gap:10px; }
  .graph-search-input { max-width:none; flex:1 1 100%; order:1; }
  .graph-legend { order:2; gap:10px 16px; }
  .graph-type-toggles { gap:16px; }
  .graph-reset-btn { order:3; margin-left:0; }

  .graph-svg-container { height:min(78vh, 620px); min-height:420px; }

  /* #296 — same crowded-narrow-width reasoning as the rest of this query;
     the merged legend's labels don't fit in one row below ~400px, and a
     vertical divider mid-wrap reads as a stray mark rather than a
     separator, so both drop and the edge key falls back to color-only. */
  .graph-legend-divider { display:none; }
  .graph-edge-legend-label { display:none; }
  .graph-edge-legend { gap:8px; }

  .lodge-page-body { padding:12px 12px 16px; }
}
