:root {
  --ui-scale:  1.25;      /* overall interface scale (see `html { zoom }` below) */
  --bg:        #0c0a09;
  --bg-2:      #14100d;
  --panel:     #1a1512;
  --panel-2:   #221b16;
  --ink:       #e9dfd2;
  --ink-dim:   #a2937f;
  --ink-faint: #6f6152;
  --ember:     #ff7a2f;
  --ember-dim: #b5541d;
  --vael:      #c0344d;   /* sorcery / crimson */
  --aurex:     #3f8fd0;   /* technology / blue  */
  --seam:      #b8923f;   /* borderland / brass */
  --line:      #2c231c;
  --font: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
}

* { box-sizing: border-box; }
/* Overall UI scale (same mechanism as browser zoom — reflows layout, scales
   modals + tooltips). Tune `--ui-scale` above. NOTE: `zoom` scales rendered size
   but `100vh` is still measured against the UNSCALED viewport, so any full-height
   container must divide by --ui-scale (see #app) or it overflows the screen. */
html { zoom: var(--ui-scale); height: calc(100vh / var(--ui-scale)); margin: 0; }
body { height: 100%; margin: 0; }
body {
  background:
    radial-gradient(1200px 600px at 85% -10%, rgba(255,122,47,0.08), transparent 60%),
    var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
}

/* themed scrollbars (kills the default white bar) */
* { scrollbar-width: auto; scrollbar-color: var(--panel-2) transparent; }
::-webkit-scrollbar { width: 30px; height: 30px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--panel-2); border: 6px solid var(--bg);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover { background: var(--ember-dim); }
::-webkit-scrollbar-corner { background: transparent; }

/* height divided by the UI scale: `zoom` renders it ×--ui-scale, so this lands
   at exactly one screen and the input bar stays pinned at the visible bottom */
#app { display: flex; flex-direction: column; height: calc(100vh / var(--ui-scale)); overflow: hidden; }
main { overflow: hidden; }   /* the log + HUD scroll internally; the page itself never scrolls */

/* ---- top bar ---- */
#topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 10px 16px;
  background: linear-gradient(var(--panel), var(--bg-2));
  border-bottom: 1px solid var(--line);
}
.brand {
  font-family: var(--mono); font-weight: 700; letter-spacing: 4px;
  color: var(--ember); text-shadow: 0 0 18px rgba(255,122,47,0.35);
}
.room-name { color: var(--ink-dim); font-style: italic; }
.spacer { flex: 1; }
.mood-chip {
  font-family: var(--mono); font-size: 11px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px;
}
.controls { display: flex; align-items: center; gap: 8px; }
.icon-btn, .text-btn {
  background: var(--panel-2); color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 6px;
  padding: 5px 10px; cursor: pointer; font-family: var(--mono); font-size: 12px;
}
.icon-btn:hover, .text-btn:hover { color: var(--ember); border-color: var(--ember-dim); }
.icon-btn.off { color: var(--ink-faint); text-decoration: line-through; }
/* GM eye reveal toggle */
.reveal-btn { font-size: 15px; line-height: 1; padding: 4px 8px; filter: grayscale(1); opacity: .55; transition: .14s; }
.reveal-btn:hover { opacity: 1; filter: none; }
.reveal-btn.on { opacity: 1; filter: none; background: var(--ember-dim); border-color: var(--ember);
  box-shadow: 0 0 10px rgba(255,122,47,.45); }
/* GM eye debug: NPC disposition swings surfaced in the log */
.msg.debug-disp { font: 12px/1.5 ui-monospace, "Cascadia Code", Menlo, monospace;
  letter-spacing: .02em; color: var(--ink-dim, #9a8f82); background: rgba(255,122,47,.06);
  border-left: 2px solid var(--ember, #ff7a2f); border-radius: 3px;
  padding: 3px 9px; margin: 3px 0; opacity: .92; }
.msg.debug-disp .dd-eye { opacity: .8; }
.msg.debug-disp b { color: var(--ink, #cdbfae); font-weight: 600; }
.msg.debug-disp .dd-nums { opacity: .85; }
.msg.debug-disp .dd-delta { font-weight: 700; }
.msg.debug-disp.up .dd-delta { color: #6fcf7f; }
.msg.debug-disp.down .dd-delta { color: #e0685a; }
/* click-and-drag to scroll */
body.drag-scrolling, body.drag-scrolling * { cursor: grabbing !important; user-select: none !important; }
body.drag-scrolling #log { scroll-behavior: auto; }   /* instant while dragging (not smooth) */

/* ---- main split ---- */
main { flex: 1; display: flex; min-height: 0; position: relative; }

/* ---- map: a bounded box floating top-left over the background, fading at its edges. The player
   sits at the anchor point inside it (set in the camera). Control column floats over its top-left. ---- */
#map-overlay { position: absolute; top: 6px; left: 6px; z-index: 20; width: min(40vw, 620px); height: min(58vh, 520px); pointer-events: none; overflow: hidden; }
#map-overlay > * { pointer-events: auto; }   /* map ignores clicks in its faded margins, buttons still work */
#map-overlay .minimap { width: 100%; height: 100%; margin: 0; }
#map-overlay .map-svg.small { width: 100%; height: 100%; max-height: none; }
/* map controls: expand button top-left, a little vertical gap, then the vertical floor stack.
   Absolutely positioned so it floats OVER the map and never resizes/moves the map box. */
.map-ctl-col { position: absolute; left: 8px; top: 8px; z-index: 3; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.map-ctl-btn, .floor-box {
  display: flex; align-items: center; justify-content: center;
  min-width: 32px; height: 25px; padding: 0 8px;
  background: rgba(18,15,12,.74); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink-dim); font-family: var(--mono); font-size: 11.5px; letter-spacing: .02em; line-height: 1;
  cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.map-ctl-btn:hover, .floor-box:hover { color: var(--ember); border-color: var(--ember-dim); background: rgba(30,22,16,.88); }
.map-ctl-col .map-expand { font-size: 14px; margin-bottom: 9px; }   /* a touch of vertical padding above the floor stack */
.floor-stack { display: flex; flex-direction: column; gap: 4px; }
.floor-stack.hidden { display: none; }
.floor-stack-row { flex-direction: row; }                          /* the expanded-map modal lays floors out in a row */
.floor-box.active { color: var(--ember); border-color: var(--ember); background: rgba(255,122,47,.14); }

/* ---- chat pane ---- */
/* pad the pane left by the HUD's width (320px) so the log / beat box / chat bar centre on the
   whole WINDOW, not on the pane (which is offset now that the left rail is gone) */
#chat-pane { flex: 1; display: flex; flex-direction: column; min-width: 0; padding-left: 320px; }
#log {
  flex: 1; overflow-y: auto; padding: 22px 26px;
  scroll-behavior: smooth;
}
#log .msg { margin: 0 auto 18px; max-width: 68ch; }   /* column centered in the window, text left-aligned */
#log-ruler { width: min(68ch, 100%); height: 0; margin: 0 auto; pointer-events: none; }   /* invisible: marks the message column left for the map bound */
#log .dm { color: var(--ink); }
#log .dm p { margin: 0 0 10px; }
#log .you {
  color: var(--ember); font-family: var(--mono); font-size: 14px;
  border-left: 2px solid var(--ember-dim); padding-left: 12px;
}
#log .you::before { content: "› "; color: var(--ember-dim); }
#log .sys { color: var(--ink-faint); font-style: italic; font-size: 14px; }
#log .err { color: var(--vael); font-family: var(--mono); font-size: 13px; }
#log .thinking { color: var(--ink-faint); font-style: italic; }

#input-form {   /* no border — sits over the bg; ~30% longer than the beat box (min(64%,640px)), centred */
  display: flex; gap: 10px; padding: 14px 18px;
  width: min(83%, 832px); margin: 0 auto;
  background: transparent;
}
#cmd {
  flex: 1; background: var(--panel); border: 1px solid var(--line);
  color: var(--ink); border-radius: 8px; padding: 12px 14px;
  font-family: var(--font); font-size: 16px;
}
#cmd:focus { outline: none; border-color: var(--ember-dim); box-shadow: 0 0 0 2px rgba(255,122,47,0.12); }

/* attributes floated LEFT of the portrait, flush against the HUD's left border (320px in) */
#attrs.attrs { position: absolute; top: 18px; right: 320px; width: 88px; z-index: 15; gap: 6px; }
#attrs .attrs-head { display: none; }              /* just the stat boxes float here; STR aligns with the portrait top */
#attrs .attr-grid { grid-template-columns: 1fr; }  /* one vertical column */
#attrs .attrs-body { gap: 6px; }
/* right edge tucks behind the HUD: flat corners + no right border, so each box reads as
   emerging from behind the panel rather than sitting beside it */
#attrs .attr { border-right: none; border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* The narration column is centered and grows with the window, so below ~1710px it runs
   UNDER these floating stat boxes. The stats aren't needed at a glance — hide them on a
   narrow viewport rather than cover the prose. (A character sheet will surface them on
   demand later.) Measured: overlap starts at 1710px, so 1760 leaves a real gap. */
@media (max-width: 1760px) { #attrs.attrs { display: none; } }

/* ---- backpack (bottom-left): the inventory's new home ---- */
#backpack {
  position: absolute; bottom: 16px; left: 16px; z-index: 25;
  width: 52px; height: 52px; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--line);
  font-size: 26px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: border-color .15s, background .15s, transform .12s;
}
#backpack:hover { border-color: var(--ember-dim); background: var(--bg-2); }
#backpack.pulse { animation: bpPulse .5s ease; }        /* nudge when an item lands (later stage) */
@keyframes bpPulse { 50% { transform: scale(1.18); border-color: var(--ember); } }
#backpack-panel {
  position: absolute; bottom: 78px; left: 16px; z-index: 25;
  width: 300px; max-height: 60vh; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; box-shadow: 0 14px 40px rgba(0,0,0,.5);
}
#backpack-panel.hidden { display: none; }
/* ---- acquire flourish: a taken item flashes above the pack, then flies into it ----
   The card is planted in the empty strip between the map and the backpack, then flown
   to the pack's LIVE rect (measured at fire time, so it follows the icon if it moves).
   Card and pack are siblings in <main>, both outside the log, so nothing reflows. */
.acquire-fx { position: absolute; inset: 0; z-index: 24; pointer-events: none; overflow: hidden; }
/* The card is ONE bordered panel: it opens as a square on the art, the border then
   EXTENDS to the right to reveal the name, holds, and contracts back to the bare square
   before flying into the pack. Width is animated (not scaleX) so the border slides open
   without distorting the art or the text. `overflow:hidden` clips the name while narrow. */
.acq-card {
  position: absolute; left: 20px; bottom: 104px;
  display: flex; flex-direction: row; align-items: center; gap: 13px;   /* name sits RIGHT of the art */
  box-sizing: border-box; padding: 8px; overflow: hidden; white-space: nowrap;
  background: var(--panel); border: 1px solid var(--seam); border-radius: 14px;   /* same border as the tooltips */
  box-shadow: 0 12px 30px rgba(0,0,0,.6);        /* rarity shows in the NAME, not the frame */
  opacity: 0; will-change: transform, opacity, width;
}
.acq-card .art-slot {
  width: 88px; height: 88px; flex: 0 0 88px; border-radius: 10px; background: var(--bg-2);
}
.acq-name {
  font-family: var(--mono); font-size: 15.5px; line-height: 1.22; font-weight: 600;
  max-width: 220px; overflow: hidden; text-overflow: ellipsis;   /* a long name clips, never reflows */
  color: var(--rar, var(--ink)); text-shadow: 0 2px 10px rgba(0,0,0,.9);
  opacity: 0;                                  /* fades in as the border opens */
}
#send-btn {
  background: var(--ember-dim); color: #1a0f06; border: none; font-weight: 700;
  border-radius: 8px; padding: 0 20px; cursor: pointer; font-family: var(--mono);
}
#send-btn:hover { background: var(--ember); }
#send-btn:disabled { opacity: .5; cursor: default; }

/* ---- HUD ---- */
#hud {
  width: 320px; flex-shrink: 0; overflow-y: auto;
  background: linear-gradient(var(--bg-2), var(--bg));
  border-left: 1px solid var(--line); padding: 18px 16px 40px;
}
.portrait { margin: 0 0 14px; }
.portrait .art-slot { aspect-ratio: 1 / 1; width: 100%; }
figcaption { text-align: center; color: var(--ink-dim); font-style: italic; margin-top: 8px; }

.art-slot {
  position: relative; background: var(--panel);
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.art-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* empty-slot silhouette: a faded, blurred black ghost of what goes here */
.art-slot.sil img.slot-sil { object-fit: contain; opacity: .32; filter: blur(1.3px); }
.art-slot[data-empty]::after {
  content: attr(data-empty);
  color: var(--ink-faint); font-family: var(--mono); font-size: 10px;
  text-transform: uppercase; letter-spacing: 1px; text-align: center; padding: 4px;
}
.art-slot.pending::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255,122,47,0.12) 50%, transparent 70%);
  background-size: 220% 100%; animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer { to { background-position: -220% 0; } }

.bars { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.bar { }
.bar .bar-label {
  display: flex; justify-content: space-between; font-family: var(--mono);
  font-size: 11px; color: var(--ink-dim); margin-bottom: 3px;
}
.bar .bar-track { height: 9px; background: var(--panel); border-radius: 999px; overflow: hidden; border: 1px solid var(--line); }
.bar .bar-fill { height: 100%; border-radius: 999px; transition: width .35s ease; }
.bar-fill.hp   { background: linear-gradient(90deg, var(--vael), #e05a4c); }
.bar-fill.mana { background: linear-gradient(90deg, #5b6fd0, var(--aurex)); }

.factions { display: flex; gap: 6px; margin-bottom: 18px; }
.factions .fac {
  flex: 1; text-align: center; border: 1px solid var(--line);
  border-radius: 8px; padding: 6px 4px; background: var(--panel);
}
.factions .fac .fac-name { font-family: var(--mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.factions .fac .fac-val { font-family: var(--mono); font-size: 15px; margin-top: 2px; }
.fac.aurex .fac-val { color: var(--aurex); }
.fac.vael  .fac-val { color: var(--vael); }
.fac.seam  .fac-val { color: var(--seam); }

.hud-h {
  font-family: var(--mono); font-size: 11px; letter-spacing: 2px;
  text-transform: uppercase; color: var(--ink-faint);
  border-bottom: 1px solid var(--line); padding-bottom: 6px; margin: 8px 0 12px;
}

.equip-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 6px; }
.equip-slot { }
.equip-slot .art-slot { aspect-ratio: 1 / 1; }
.equip-slot.filled .art-slot { border-color: var(--ember-dim); }
.equip-slot .slot-name {
  font-family: var(--mono); font-size: 9px; color: var(--ink-faint);
  text-align: center; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.equip-slot.filled .slot-name { color: var(--rar, var(--ink-dim)); }

.inv-row { display: flex; flex-wrap: wrap; gap: 6px; }
.inv-chip {
  display: flex; align-items: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 10px 3px 4px; font-size: 12px; color: var(--ink-dim);
}
.inv-chip img { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; }
.inv-chip .dot { width: 18px; height: 18px; border-radius: 50%; background: var(--panel-2); border: 1px solid var(--line); }
.inv-empty { color: var(--ink-faint); font-style: italic; font-size: 13px; }

/* thinking dots */
.dots::after { content: "…"; animation: dots 1.2s steps(4, end) infinite; }
@keyframes dots { 0%{content:""} 25%{content:"·"} 50%{content:"··"} 75%{content:"···"} 100%{content:"···"} }

/* ---- codex modal ---- */
.modal { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; }
.modal.hidden { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(6,4,3,0.72); backdrop-filter: blur(3px); }
.modal-card {
  position: relative; width: min(920px, 92vw); max-height: 86vh; display: flex; flex-direction: column;
  background: linear-gradient(var(--panel), var(--bg-2));
  border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 30px 80px rgba(0,0,0,.6);
  overflow: hidden;
}
/* top-anchor the codex card near the visible top — the overlay's inset:0 takes the
   TALLER layout viewport, so centering pushes the card off the bottom. fitDetail caps
   the card height to the viewport so it always fits from the top down. */
#codex-modal { align-items: flex-start; }
#codex-modal .modal-card { margin-top: 24px; }
/* --- UI motion (fades / slides / pops; honours reduced-motion) --- */
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes riseIn { from { opacity: 0; transform: translateY(14px) scale(.985) } to { opacity: 1; transform: none } }
@keyframes slideInL { from { opacity: 0; transform: translateX(-16px) } to { opacity: 1; transform: none } }
@keyframes popIn { from { opacity: 0; transform: scale(.88) } to { opacity: 1; transform: none } }
@media (prefers-reduced-motion: no-preference) {
  .modal-backdrop { animation: fadeIn .18s ease; }
  .modal-card { animation: riseIn .24s cubic-bezier(.2,.85,.25,1); }
  .cx-detail { animation: riseIn .3s cubic-bezier(.2,.85,.25,1); }
  .cx-info > * { animation: slideInL .34s ease backwards; }
  .cx-info > *:nth-child(2) { animation-delay: .04s } .cx-info > *:nth-child(3) { animation-delay: .08s }
  .cx-info > *:nth-child(4) { animation-delay: .12s } .cx-info > *:nth-child(5) { animation-delay: .16s }
  .cx-info > *:nth-child(n+6) { animation-delay: .2s }
  .cx-chip { animation: popIn .3s ease backwards; }
  .ci-card, .loc-card { animation: fadeIn .3s ease backwards; }
}
.modal-head { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.modal-head h2 { margin: 0; font-family: var(--mono); letter-spacing: 3px; color: var(--ember); font-size: 16px; }

/* art-prompt editor: sits ABOVE the item modal (which stays open behind it) */
#artprompt-modal { z-index: 70; }
.artprompt-card { width: min(680px, 92vw); }
.artprompt-body { padding: 16px 18px 4px; }
.artprompt-text {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 132px; margin-top: 10px;
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 11px 13px; font-family: var(--mono); font-size: 12px; line-height: 1.55;
}
.artprompt-text:focus { outline: none; border-color: var(--ember-dim); box-shadow: 0 0 0 2px rgba(255,122,47,.12); }
.codex-count { font-family: var(--mono); font-size: 12px; color: var(--ink-faint); }
.codex-body { overflow-y: auto; min-height: 0; padding: 0 18px 18px; }
.codex-body.hidden { display: none; }
.codex-empty { margin-top: 28px; }
.codex-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
/* codex main tabs (Characters | Items) */
.codex-tabs { display: flex; gap: 4px; padding: 8px 18px 0; border-bottom: 1px solid var(--line); }
.codex-tab { background: none; border: none; border-bottom: 2px solid transparent; color: var(--ink-dim);
  font-family: var(--font); font-size: 15px; padding: 8px 14px; cursor: pointer; margin-bottom: -1px; }
.codex-tab:hover { color: var(--ink); }
.codex-tab.active { color: var(--ember); border-bottom-color: var(--ember); }
/* sub-tab pill bar (faction / item category) — sticky at the top of the scroll body */
.sub-tabs { position: sticky; top: 0; z-index: 3; display: flex; flex-wrap: wrap; gap: 6px;
  padding: 14px 0 12px; margin-bottom: 4px; background: var(--panel); }
.sub-tab { display: inline-flex; align-items: center; gap: 6px; background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 999px; color: var(--ink-dim); font-family: var(--font); font-size: 13px; padding: 5px 13px; cursor: pointer; }
.sub-tab:hover { color: var(--ink); border-color: var(--ember-dim); }
.sub-tab.active { background: var(--ember-dim); border-color: var(--ember); color: #fff; }
.sub-tab.vael.active { background: var(--vael); border-color: var(--vael); }
.sub-tab.aurex.active { background: var(--aurex); border-color: var(--aurex); }
.sub-tab span { font-size: 11px; font-family: var(--mono); opacity: .75; }
/* Characters tab: faction segment tabs -> portrait strip -> big scene detail */
.cx-facs { position: sticky; top: 0; z-index: 3; display: flex; background: var(--panel); border-bottom: 1px solid var(--line); }
.cx-fac { flex: 1; min-width: 0; background: none; border: none; border-bottom: 2px solid transparent; color: var(--ink-dim);
  font-family: var(--font); font-size: 15px; padding: 13px 8px; cursor: pointer;
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cx-fac + .cx-fac { border-left: 1px solid var(--line); }
.cx-fac span { font-family: var(--mono); font-size: 12px; color: var(--ink-faint); }
.cx-fac:hover { color: var(--ink); }
.cx-fac.active { color: var(--ink); border-bottom-color: var(--ember); }
.cx-fac.vael.active { color: var(--vael); border-bottom-color: var(--vael); }
.cx-fac.aurex.active { color: var(--aurex); border-bottom-color: var(--aurex); }
.cx-fac.seam.active { color: var(--ember); border-bottom-color: var(--ember); }
.cx-strip { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; padding: 14px 0; }
.cx-chip { flex: 0 0 auto; width: 60px; height: 60px; border-radius: 10px; border: 2px solid var(--line);
  background: var(--bg-2); cursor: pointer; padding: 0; overflow: hidden; opacity: .65; transition: .12s; }
.cx-chip .art-slot { width: 100%; height: 100%; border-radius: 0; }
.cx-chip:hover { opacity: 1; border-color: var(--ember-dim); transform: translateY(-2px); }
.cx-chip.selected { opacity: 1; border-color: var(--ember); }
.cx-chip.vael.selected { border-color: var(--vael); }
.cx-chip.aurex.selected { border-color: var(--aurex); }
.cx-chip.seam.selected { border-color: var(--ember); }
.cx-chip.dead { filter: grayscale(.6); }
#cx-detail-wrap { position: relative; }
.cx-detail { position: relative; height: 460px; border-radius: 12px; overflow: hidden; border: 1px solid var(--line); background: var(--bg); }
/* crossfade between characters: incoming panel is static, outgoing fades out over it */
.cx-detail.cx-still, .cx-detail.cx-still .cx-info > * { animation: none; }
.cx-detail.cx-fadeout { position: absolute; inset: 0; z-index: 2; transition: opacity .32s ease; }
.cx-detail.cx-fadeout.cx-gone { opacity: 0; }
.cx-scene { position: absolute; inset: 0; background-size: cover; background-position: right center; }
.cx-scrim { position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(8,6,5,.97) 0%, rgba(8,6,5,.9) 26%, rgba(8,6,5,.42) 52%, rgba(8,6,5,0) 72%); }
.cx-info { position: absolute; inset: 0; width: min(60%, 500px); padding: 26px 30px; overflow-y: auto; scrollbar-width: none; }
.cx-info::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* "scroll for more" cue: a faint pulsing double-chevron over a soft glow, living in the
   empty (left) column so it never sits on the character; up variant = scroll-up */
.cx-cue { position: absolute; left: 0; width: min(60%, 500px); height: 78px; pointer-events: none; opacity: 0;
  transition: opacity .35s ease; z-index: 3;
  background: url(/assets/ui/scrollmask.png) center / 100% 100% no-repeat; mix-blend-mode: screen; }
.cx-cue.down { bottom: 0; }
.cx-cue.up { top: 0; transform: scaleY(-1); }   /* flip the mask: glow + chevron point up */
.cx-cue.show { opacity: 1; animation: cuePulse 2.2s ease-in-out infinite; }
@keyframes cuePulse { 0%, 100% { opacity: .1; } 50% { opacity: .34; } }
@media (prefers-reduced-motion: reduce) { .cx-cue.show { animation: none; opacity: .28; } }
.cx-dfac { font-family: var(--mono); font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--ink-faint); }
.cx-dfac.vael { color: var(--vael); } .cx-dfac.aurex { color: var(--aurex); }
.cx-dname { font-size: 27px; line-height: 1.15; color: var(--ink); margin: 3px 0 6px; }
.cx-dname.codex-name-epithet { font-style: italic; font-size: 22px; color: var(--ink-dim); }
.cx-drole { color: var(--ink-dim); font-style: italic; margin-bottom: 12px; }
.cx-drole.codex-unnamed { color: var(--ink-faint); }
.cx-dfacts { margin-top: 12px; }
.cx-dfacts li { font-size: 14px; line-height: 1.5; margin-bottom: 7px; }
.cx-nofact { color: var(--ink-faint); font-style: italic; }
@media (max-width: 640px) {
  .cx-info { width: 100%; }
  .cx-scrim { background: linear-gradient(0deg, rgba(8,6,5,.97) 30%, rgba(8,6,5,.45) 100%); }
}
/* codex Items tab: grouped gallery of LARGER cards + hover re-roll */
.codex-items { display: block; }
.ci-group { margin-bottom: 22px; }
.ci-cat { display: flex; align-items: baseline; gap: 8px; font-size: 13px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-dim); border-bottom: 1px solid var(--line); padding-bottom: 5px; margin-bottom: 12px; }
.ci-cat span { font-size: 11px; color: var(--ink-faint); font-family: var(--mono); }
.ci-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 14px; }
.ci-card { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; padding: 10px; }
.ci-thumb { width: 100%; aspect-ratio: 1 / 1; border-radius: 10px; cursor: pointer; margin-bottom: 8px; }
.ci-thumb .art-slot { width: 100%; height: 100%; border-radius: 10px; }
.ci-name { color: var(--rar, var(--ink)); font-size: 14px; line-height: 1.2; cursor: pointer; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ci-sub { font-size: 11px; color: var(--ink-faint); margin: 2px 0 5px; }
.ci-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 3px 8px; }
.ci-stat { font-size: 11px; font-family: var(--mono); color: var(--ink-dim); white-space: nowrap; }
.ci-stat.dmg { color: #e06a4a; } .ci-stat.def { color: #6aa9e0; } .ci-stat.fx { color: var(--ember); }
.ci-stat.val { color: #d4af5a; } .ci-stat.quest { color: var(--vael); }
.ci-reroll { position: absolute; top: 7px; right: 7px; width: 26px; height: 26px; border-radius: 7px; background: rgba(12,10,9,.85);
  border: 1px solid var(--line); color: var(--ink-dim); cursor: pointer; font-size: 14px; line-height: 1; opacity: 0; transition: .12s; z-index: 2; }
.ci-card:hover .ci-reroll { opacity: 1; }
.ci-reroll:hover { color: var(--ember); border-color: var(--ember-dim); }
/* codex Locations tab: zone cards, side-tinted left edge */
.loc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.loc-card { background: var(--bg-2); border: 1px solid var(--line); border-left: 3px solid var(--line); border-radius: 10px; padding: 13px 16px; }
.loc-card.vael { border-left-color: var(--vael); }
.loc-card.aurex { border-left-color: var(--aurex); }
.loc-card.seam { border-left-color: var(--ember); }
.loc-name { font-size: 15px; color: var(--ink); margin-bottom: 6px; display: flex; align-items: center; gap: 8px; }
.loc-badge { font-family: var(--mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
.loc-badge.vis { color: var(--ember); border-color: var(--ember-dim); }
.loc-desc { color: var(--ink-dim); font-size: 13px; line-height: 1.55; }
.codex-empty { grid-column: 1 / -1; color: var(--ink-faint); font-style: italic; text-align: center; padding: 40px; }

.codex-card { background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; padding: 12px; }
.codex-card.dead { opacity: .7; }
.codex-card-top { display: flex; gap: 12px; margin-bottom: 8px; }
.codex-card-top .art-slot { width: 64px; height: 64px; flex-shrink: 0; border-radius: 10px; }
/* codex portrait is a clickable expander (bigger view + re-roll) */
.codex-portrait { position: relative; flex-shrink: 0; padding: 0; margin: 0; border: none; background: none; cursor: pointer; border-radius: 10px; }
.codex-portrait::after { content: "⛶"; position: absolute; right: 3px; bottom: 3px; font-size: 10px; line-height: 1; color: var(--ink); background: rgba(0,0,0,.6); border-radius: 4px; padding: 2px 3px; opacity: 0; transition: opacity .15s; }
.codex-portrait:hover::after { opacity: 1; }
.codex-portrait:hover .art-slot { box-shadow: 0 0 0 2px var(--ember-dim); }

/* expanded codex-character portrait (with re-roll) */
.npc-card { width: min(560px, 92vw); }
.npc-body { padding: 18px; display: flex; flex-direction: column; align-items: center; gap: 14px; }
/* the codex expand shows the 4:3 scene render (character in a background) */
.npc-body .art-slot { width: 100%; max-width: 512px; aspect-ratio: 4 / 3; border-radius: 12px; }
.npc-meta { width: 100%; text-align: center; }
.npc-name { font-size: 18px; color: var(--ink); }
.npc-name.codex-name-epithet { font-style: italic; color: var(--ink-dim); }
.npc-meta .codex-fac { margin-top: 4px; }
.npc-meta .item-actions { margin-top: 16px; display: flex; justify-content: center; }
.codex-name { font-size: 16px; color: var(--ink); }
/* an as-yet-unnamed figure is headed by its descriptor, shown as an italic epithet */
.codex-name.codex-name-epithet { font-style: italic; color: var(--ink-dim); }
.codex-role.codex-unnamed { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); font-style: normal; }
.codex-name .dead-tag { color: var(--vael); font-family: var(--mono); font-size: 10px; margin-left: 6px; }
.codex-fac { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; margin-top: 2px; }
.codex-fac.aurex { color: var(--aurex); }
.codex-fac.vael { color: var(--vael); }
.codex-fac.seam { color: var(--seam); }
.codex-role { font-size: 13px; color: var(--ink-dim); font-style: italic; margin: 6px 0 6px; }
.codex-ties { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); margin-bottom: 8px; line-height: 1.7; }
.codex-ties span { border: 1px solid var(--line); border-radius: 999px; padding: 1px 7px; margin-right: 4px; white-space: nowrap; }
.codex-facts { list-style: none; margin: 0; padding: 0; }
.codex-facts li { font-size: 13px; color: var(--ink); padding: 5px 0 5px 16px; position: relative; border-top: 1px solid var(--line); }
.codex-facts li::before { content: "◆"; color: var(--ember-dim); position: absolute; left: 0; font-size: 9px; top: 8px; }
.codex-locked { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); margin-top: 8px; }

/* ---- left inventory rail ---- */
#left-rail {
  width: 216px; flex-shrink: 0; overflow-y: auto;
  background: linear-gradient(var(--bg-2), var(--bg));
  border-right: 1px solid var(--line); padding: 18px 14px 40px;
}
/* what's in the pack: an ICON GRID — art only, no names. The name and stats live in the
   hover tooltip (the shop's, reused); clicking a cell opens the item modal. Rarity tints
   the cell's border, so the grid reads at a glance without any text. */
.inv-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.inv-cell {
  position: relative; aspect-ratio: 1 / 1; cursor: pointer;
  border-radius: 10px; transition: transform .12s, box-shadow .15s;
}
.inv-cell .art-slot {
  width: 100%; height: 100%; border-radius: 10px;
  border-color: color-mix(in srgb, var(--rar, var(--line)) 55%, var(--line));
}
.inv-cell:hover { transform: translateY(-2px); }
.inv-cell:hover .art-slot {
  border-color: var(--rar, var(--ember-dim));
  box-shadow: 0 0 16px -3px var(--rar, var(--ember));
}
.inv-empty { color: var(--ink-faint); font-style: italic; font-size: 13px; padding: 6px; grid-column: 1 / -1; }

/* legacy list styles — the HUD no longer uses them, kept for the loadout editor's carried list */
.inv-list { display: flex; flex-direction: column; gap: 8px; }
.inv-item {
  display: flex; align-items: center; gap: 10px; padding: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  cursor: pointer; transition: border-color .15s, background .15s;
}
.inv-item:hover { border-color: var(--ember-dim); background: var(--panel-2); }
.inv-item .art-slot { width: 42px; height: 42px; flex-shrink: 0; border-radius: 8px; }
.inv-item .inv-name { font-size: 13px; color: var(--rar, var(--ink-dim)); line-height: 1.25; }

/* available actions — click drafts the command into the input */
.act-list { display: flex; flex-wrap: wrap; gap: 6px; }
.act-btn { background: var(--panel); border: 1px solid var(--line); color: var(--ink-dim); border-radius: 8px; padding: 5px 10px; font-size: 12px; cursor: pointer; text-align: left; font-family: var(--font); }
.act-btn:hover { border-color: var(--ember-dim); color: var(--ember); }
.act-note { font-size: 10px; color: var(--ink-faint); font-style: italic; margin: 10px 2px 0; }

/* Quick commands: a POP-UP menu (not the old always-visible row, which overflowed
   the width). The trigger is pinned FLUSH ALONG THE BOTTOM, right side — in the gutter
   between the chat and the gear on wide screens, over the text bar on narrow ones.
   Clicking it pops a VERTICAL menu upward that stays open until the trigger is clicked
   again (or Esc). Absolute so it never pushes the input. Fades out with the VN box. */
.actions-wrap { position: absolute; right: 18px; bottom: 14px; z-index: 25; transition: opacity .22s ease; }
.qa-trigger { display: inline-flex; align-items: center; gap: 7px; background: var(--panel);
  border: 1px solid var(--line); color: var(--ink-dim); border-radius: 8px; padding: 6px 12px;
  cursor: pointer; font-family: var(--mono); font-size: 12px; letter-spacing: .04em;
  transition: color .15s, border-color .15s; }
.qa-trigger:hover, .qa-trigger[aria-expanded="true"] { color: var(--ember); border-color: var(--ember-dim); }
.qa-caret { font-size: 10px; transition: transform .18s ease; }
.qa-trigger[aria-expanded="true"] .qa-caret { transform: rotate(180deg); }
/* the pop-up: opens UPWARD from the trigger, right-aligned, a vertical stack */
.qa-menu { position: absolute; right: 16px; bottom: calc(100% + 6px); z-index: 30;
  display: flex; flex-direction: column; align-items: stretch; gap: 5px;
  min-width: 176px; max-width: 264px; max-height: 52vh; overflow-y: auto; padding: 7px;
  background: rgba(20, 16, 13, .94); border: 1px solid var(--line); border-radius: 11px;
  box-shadow: 0 14px 40px rgba(0, 0, 0, .5); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transform: translateY(6px) scale(.98); transform-origin: bottom right;
  pointer-events: none; transition: opacity .16s ease, transform .16s ease; }
.qa-menu.open { opacity: 1; transform: none; pointer-events: auto; }
.qa-menu .act-btn { width: 100%; }
.qa-menu .act-note { margin: 4px 6px; }
#vn-stage.showing ~ .actions-wrap { opacity: 0; pointer-events: none; }
/* when the gutter beside the input is too narrow, JS adds .qa-lift so the trigger sits
   flush ON TOP of the text bar instead of overlapping it. Measured (not a px breakpoint)
   because html{zoom} makes viewport breakpoints unreliable. */
.actions-wrap.qa-lift { bottom: 78px; }

/* ---- minimap (left rail) + expanded map modal ---- */
.map-head { display: flex; align-items: center; justify-content: space-between; }
.map-zone { font-family: var(--mono); font-size: 10px; letter-spacing: .04em; color: var(--ember-dim);
  text-transform: none; font-weight: 400; margin-left: 4px; }
.minimap { margin: 4px 0 16px;
  /* soft dissolve at the 4 borders so rooms leaving the camera window fade out (viewBox-independent,
     so it stays put while the map slides/zooms). Tune the stops by eye. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 9%, #000 88%, transparent), linear-gradient(to bottom, transparent, #000 13%, #000 87%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 9%, #000 88%, transparent), linear-gradient(to bottom, transparent, #000 13%, #000 87%, transparent);
  mask-composite: intersect;
}
.map-empty { color: var(--ink-faint); font-style: italic; font-size: 12px; padding: 8px 2px; }
.map-svg { display: block; width: 100%; height: auto; }
.map-svg.small { max-height: 30vh; }
.map-svg.big { max-height: 72vh; }
/* minimap slide: the current-room highlight cross-fades as you move (solid-fill polys only),
   at the SAME slow pace as the camera walk (--mm-slide, set from MM_SLIDE_MS) */
.map-svg.small .iso-rim, .map-svg.small .iso-inwall, .map-svg.small .iso-right,
.map-svg.small .iso-left, .map-svg.small .iso-jamb { transition: fill var(--mm-slide, .5s) ease; }
/* corridors linking room centres — wide, and faded at both ends (stroke = a per-edge along-line gradient) */
.map-edge { stroke: none; opacity: .6; }   /* corridor = flat iso strip (polygon); fill is set inline so the fade/pulse win */
/* the corridor between the room you left and the one you entered pulses ember for the whole walk
   (colour comes from the swapped-in ember gradient; the keyframe just breathes its opacity) */
@keyframes mmEdgePulse { 0%, 100% { opacity: .35; } 50% { opacity: .95; } }
.map-edge.pulse { animation: mmEdgePulse 1.3s ease-in-out infinite; }   /* JS clears .pulse when the walk ends */
.map-edge.passage { opacity: .4; }   /* in/out passages read fainter */
/* ── faked-3D room trays: recessed floor + raised rim walls (gaps at exits),
      a hole for a down-exit, a staircase for an up-exit ── */
.map-node { cursor: pointer; }
.map-node polygon { stroke: none; stroke-linejoin: round; transition: fill .15s; }  /* NO per-face strokes (no diagonal construction lines) */
.map-node .iso-right { fill: #2a1e13; }   /* outer side (SE) — wall + foundation, ONE colour, lit side */
.map-node .iso-left  { fill: #201711; }   /* outer side (SW) — wall + foundation, ONE colour, shadow side */
.map-node .iso-rim   { fill: #382c1d; }   /* raised wall tops, lit (lightest) */
.map-node .iso-floor  { fill: url(#fg); }  /* recessed floor, dark + faint warm glow */
.map-node .iso-inwall { fill: #2a1e13; }   /* recess inner wall — SAME as the outer walls, so the dark floor stands out */
.map-node .iso-jamb   { fill: #3a2c1c; }   /* doorway jamb — the wall's end cross-section, lit */
.map-node .iso-holebot { fill: #050302; }     /* pit bottom (down exit), near-black */
/* pit walls: each face gets its own slanted gradient (built per-hole in holeSvg), so the fade runs down the wall */
.map-node .iso-holeglow { opacity: .4; animation: holepulse 3.4s ease-in-out infinite; }  /* subtle "there's a hole here" cue rising from the pit; gently pulses */
@keyframes holepulse { 0%, 100% { opacity: .28; } 50% { opacity: .5; } }
/* stair tread tops reuse .iso-rim so they share the wall-top colour + room-state recolour */
.map-node .iso-stair-r { fill: #2a1d10; }  /* stair riser (front face), dark */
.map-node .iso-stair-s { fill: #17100a; }  /* stair side profile, darkest */
/* room STATE is carried by the wall-TOP colour (rim), not an extra outline/highlight */
.map-node.unvisited { opacity: .72; }                                               /* seen, not entered — dim + slightly see-through (no outline) */
.map-node.unvisited .iso-rim, .map-node.unvisited .iso-inwall { fill: #241a12; }
.map-node.unvisited .iso-floor { opacity: .5; }
.map-node.has-note:not(.current) .iso-rim { fill: #4e3f26; }   /* something happened here — wall tops just a touch brighter/warmer than normal (#382c1d) */
.map-node.current .iso-rim   { fill: #ff7a2f; }   /* current room = orange, recoloured throughout */
.map-node.current .iso-inwall { fill: #7a3a15; }
.map-node.current .iso-floor { fill: url(#fgc); }
.map-node.current .iso-right { fill: #7a3a15; }
.map-node.current .iso-left  { fill: #542813; }
.map-node.current .iso-jamb  { fill: #8a531f; }
.map-label { fill: var(--ink-dim); font-family: var(--font); font-size: 12px; text-anchor: middle; dominant-baseline: middle; pointer-events: none; }
.map-label.current { fill: var(--ink); font-weight: 600; }
/* the floors you're NOT on go transparent, so the active level reads clearly */
.map-node.ghost { opacity: .24; pointer-events: none; }
.map-node.ghost.current { opacity: .4; }
.map-edge.ghost { opacity: .18; }
.map-tip { position: fixed; z-index: 60; max-width: 230px; background: var(--panel); border: 1px solid var(--line); border-radius: 9px; padding: 8px 11px; box-shadow: 0 14px 40px rgba(0,0,0,.5); pointer-events: none; }
.map-tip.hidden { display: none; }
.map-tip-name { color: var(--ink); font-weight: 600; font-size: 13px; margin-bottom: 5px; }
.map-tip-lvl { font-family: var(--mono); font-size: 10.5px; letter-spacing: .04em; color: var(--ember); margin: -2px 0 6px; }
.map-tip-occ { display: flex; flex-wrap: wrap; gap: 3px 5px; margin: 0 0 6px; }
.map-tip-occ span { font-size: 11px; color: var(--ember); background: rgba(255,122,47,.14); border: 1px solid var(--ember-dim); border-radius: 5px; padding: 1px 6px; }
.map-tip-ev { color: var(--ink-dim); font-size: 11.5px; line-height: 1.5; }
.map-tip-none { color: var(--ink-faint); font-style: italic; font-size: 11px; }
.map-modal-card { width: min(780px, 92vw); }
.map-modal-body { padding: 18px; overflow: auto; display: flex; justify-content: center; }

/* ---- equipment: strictly equal squares, clickable when filled ---- */
.equip-slot { min-width: 0; }
.equip-slot.filled { cursor: pointer; }
.equip-slot .art-slot { width: 100%; aspect-ratio: 1 / 1; height: auto; }
.art-slot[data-empty]::after { white-space: nowrap; }
/* transparent art reads cleanly against a subtle inset */
.art-slot { background: radial-gradient(circle at 50% 38%, #1d1813, #0b0908); }

/* enchant glows — drop-shadow hugs the transparent cutout's silhouette, tinted
   by allegiance (crimson=sorcery, blue=tech, amber=Seam hybrid) */
.art-slot img.glow-vael  { animation: glow-v 2.8s ease-in-out infinite; }
.art-slot img.glow-aurex { animation: glow-a 2.8s ease-in-out infinite; }
.art-slot img.glow-seam  { animation: glow-s 3.2s ease-in-out infinite; }
@keyframes glow-v { 0%,100%{filter:drop-shadow(0 0 2px rgba(192,52,77,.7))} 50%{filter:drop-shadow(0 0 5px rgba(192,52,77,.95)) drop-shadow(0 0 12px rgba(192,52,77,.5))} }
@keyframes glow-a { 0%,100%{filter:drop-shadow(0 0 2px rgba(63,143,208,.7))} 50%{filter:drop-shadow(0 0 5px rgba(63,143,208,.95)) drop-shadow(0 0 12px rgba(63,143,208,.5))} }
@keyframes glow-s { 0%,100%{filter:drop-shadow(0 0 2px rgba(184,146,63,.65))} 50%{filter:drop-shadow(0 0 4px rgba(184,146,63,.9)) drop-shadow(0 0 10px rgba(184,146,63,.45))} }
/* enchanted gear pulses harder/faster than an innate relic glow */
.art-slot img.ench { animation-duration: 1.7s; }

/* ---- cost + settings ---- */
.cost { font-family: var(--mono); font-size: 12px; color: var(--seam); text-decoration: none; cursor: pointer; }
.cost:hover { color: var(--ember); text-decoration: underline; }
.settings-wrap { position: relative; }
.settings-pop {
  position: absolute; right: 0; top: 34px; z-index: 40; width: 232px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px; box-shadow: 0 20px 50px rgba(0,0,0,.5);
  display: flex; flex-direction: column; gap: 10px;
}
.settings-pop.hidden { display: none; }
.settings-pop label { display: flex; flex-direction: column; gap: 4px; font-family: var(--mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.settings-pop select { background: var(--bg-2); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; padding: 6px; font-family: var(--font); font-size: 14px; }
.settings-note { font-size: 11px; color: var(--ink-faint); font-style: italic; margin: 0; text-transform: none; letter-spacing: 0; }

/* ---- word-by-word fade for new narration ---- */
.w { display: inline-block; opacity: 0; animation: fadeword .26s ease forwards; }
@keyframes fadeword { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* ---- VN stage: a text box prints the CURRENT beat large; each beat then drops
       into the log as you advance ---- */
/* the stage exists only in VN mode; it always occupies space so the card
   appearing doesn't shove the log up (space reserved via the card min-height) */
#vn-stage.vn-stage { display: none; }
body.vn-on #vn-stage.vn-stage {
  display: flex; justify-content: center; gap: 16px; align-items: flex-end; cursor: pointer;
  padding: 10px 22px 16px;                     /* lifts the card off the input bar + side padding */
  background: transparent;
}
#vn-stage:not(.showing) .vn-box { visibility: hidden; }   /* idle: reserved but invisible */
/* Milestone C/D: the talking portrait lives INSIDE .vn-box but is absolutely
   positioned off its LEFT edge — out of the layout flow entirely, so the box is
   always dead-centered whether or not anyone is speaking. (Was: a flex sibling
   whose reserved width shoved the centered box right on speaker turns.) */
.vn-portraits {
  position: absolute; right: 100%; bottom: 0; margin-right: 18px;
  width: min(30%, 210px);   /* % of the BOX, so it scales down with it */
  pointer-events: none;
}
@media (max-width: 980px) { .vn-portraits { display: none; } }  /* no room to hang left */
.vn-portraits.dim .vn-portrait { filter: brightness(.5) saturate(.75) drop-shadow(0 6px 18px rgba(0,0,0,.55)); }
.vn-portrait {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 6px 18px rgba(0,0,0,.55));
  opacity: 0; transform: translateY(10px) scale(.985);
  transition: opacity .38s ease, transform .38s ease, filter .3s ease;
}
.vn-portrait.in { opacity: 1; transform: none; }
.vn-box {                                      /* a floating card (tune width / min-height) */
  position: relative;                          /* anchor for the hanging portrait column */
  display: flex; flex-direction: column;
  width: min(64%, 640px); min-width: 0; min-height: 130px;
  background: linear-gradient(var(--panel-2), var(--panel));
  border: 1px solid var(--line); border-radius: 12px;
  padding: 14px 18px;
  box-shadow: 0 8px 24px rgba(0,0,0,.42);
}
.vn-name { font-family: var(--mono); font-size: 14px; letter-spacing: 1px; color: var(--ink); margin-bottom: 7px; }
.vn-name.hidden { display: none; }
.vn-name.vael  { color: var(--vael); text-shadow: 0 0 14px rgba(192,52,77,.35); }
.vn-name.aurex { color: var(--aurex); text-shadow: 0 0 14px rgba(63,143,208,.35); }
.vn-name.seam  { color: var(--seam); text-shadow: 0 0 14px rgba(184,146,63,.35); }
.vn-name.you   { color: var(--ember); }
.vn-text { color: var(--ink); line-height: 1.5; min-height: 1.5em; font-size: 1.2rem; }
.vn-text.whisper { font-style: italic; color: var(--ink-dim); }
.vn-text .wd { white-space: nowrap; }         /* a word never breaks mid-word at a line wrap */
.vn-text .ch { display: inline-block; opacity: 0; animation: fadeword .24s ease forwards; }
.vn-text.done .ch { animation: none; opacity: 1; transform: none; }
.vn-controls { display: flex; align-items: center; justify-content: flex-end; gap: 12px; margin-top: auto; padding-top: 10px; height: 18px; }
.vn-advance { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); animation: vnpulse 1.4s ease-in-out infinite; }
.vn-advance.hidden { visibility: hidden; }
@keyframes vnpulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
.vn-skip { background: transparent; border: 1px solid var(--line); color: var(--ink-faint); border-radius: 6px; padding: 2px 9px; font-family: var(--mono); font-size: 10px; cursor: pointer; }
.vn-skip:hover { color: var(--ember); border-color: var(--ember-dim); }
#vn-stage.shake { animation: vnshake .45s cubic-bezier(.36,.07,.19,.97); }
@keyframes vnshake {
  10%,90% { transform: translateX(-1px); } 20%,80% { transform: translateX(2px); }
  30%,50%,70% { transform: translateX(-4px); } 40%,60% { transform: translateX(4px); }
}

/* damage / heal number that pops in the box on the beat where a blow lands
   (a placeholder slot for the future d20 dice roll) */
.vn-event { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
.vn-event:empty { display: none; }
.vn-dmg {
  font-family: var(--mono); font-weight: 700; font-size: 1.35rem; line-height: 1;
  padding: 3px 12px; border-radius: 8px; border: 1px solid var(--line);
  animation: dmgpop .38s cubic-bezier(.2,1.5,.4,1);
}
.vn-dmg.to-player { color: var(--vael); border-color: #5a2630; background: rgba(192,52,77,.12); }
.vn-dmg.to-npc   { color: var(--ember); border-color: var(--ember-dim); background: rgba(255,122,47,.10); }
.vn-dmg.heal     { color: #6bbf6b; border-color: #3c5c3c; background: rgba(107,191,107,.12); }
@keyframes dmgpop { from { opacity: 0; transform: scale(.4) translateY(8px); } to { opacity: 1; transform: none; } }

/* each beat, as it lands in the log transcript on advance */
.vn-beat .beat-name { font-family: var(--mono); font-size: 13px; margin-right: 8px; color: var(--ink-dim); }
.vn-beat .beat-body { color: var(--ink); }
.vn-beat.whisper .beat-body { font-style: italic; color: var(--ink-dim); }
.beat-name.vael { color: var(--vael); } .beat-name.aurex { color: var(--aurex); }
.beat-name.seam { color: var(--seam); } .beat-name.you { color: var(--ember); }
.vn-beat.land { animation: beatland .3s ease; }
@keyframes beatland { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* the damage/heal number recorded inline with a beat in the transcript */
.beat-dmg { font-family: var(--mono); font-size: 12px; font-weight: 700; margin-left: 4px; }
.beat-dmg.to-player { color: var(--vael); } .beat-dmg.to-npc { color: var(--ember); } .beat-dmg.heal { color: #6bbf6b; }

/* ---- HUD attributes panel (level + the six ability scores + proficiencies) ---- */
.attrs { display: flex; flex-direction: column; gap: 8px; }
.attrs:empty { display: none; }
.attrs-head { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.attrs-head .hud-h { margin: 0; }
.attrs-head .attr-lvl { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ember); }
.attr-caret { color: var(--ink-faint); font-size: 11px; width: 10px; text-align: center; }
.attrs-body { display: flex; flex-direction: column; gap: 7px; }
.attrs-body.hidden { display: none; }
.attr-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.attr { display: flex; align-items: baseline; gap: 4px; padding: 4px 7px; border-radius: 6px;
  background: var(--panel); border: 1px solid var(--line); }
.attr-ab { font-family: var(--mono); font-size: 10px; letter-spacing: .05em; color: var(--ink-faint); }
.attr-sc { font-family: var(--mono); font-size: 14px; color: var(--ink); margin-left: auto; }
.attr-md { font-family: var(--mono); font-size: 11px; min-width: 18px; text-align: right; }
.attr-md.pos { color: #8fd17a; } .attr-md.neg { color: var(--vael); } .attr-md.zero { color: var(--ink-faint); }
.attr-prof, .attr-boon { font-size: 12px; color: var(--ink-dim); line-height: 1.5; }
.attr-k { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint); margin-right: 5px; }
.attr-boon span[title] { color: #8fd17a; font-family: var(--mono); font-size: 11px; }

/* ---- d20 roll chips (shared by the VN roll slot + the log tags) ---- */
.ev-roll { font-family: var(--mono); color: var(--ink-faint); border: 1px solid var(--line); border-radius: 7px; padding: 2px 8px; white-space: nowrap; cursor: help; border-bottom-style: dotted; }
.ev-roll.crit { color: var(--ember); border-color: var(--ember-dim); }
.ev-roll.fumble { color: var(--vael); border-color: #5a2630; }
.ev-crit { font-family: var(--mono); font-weight: 700; color: var(--ember); letter-spacing: 1px; }
.ev-dmg { font-family: var(--mono); font-weight: 700; }
.ev-dmg.to-player { color: var(--vael); } .ev-dmg.to-npc { color: var(--ember); }
.ev-dmg.heal { color: #6bbf6b; } .ev-dmg.miss { color: var(--ink-faint); letter-spacing: 1px; }
/* larger inside the VN box's roll slot */
.vn-event .ev-roll { font-size: 1rem; padding: 3px 10px; }
.vn-event .ev-crit { font-size: 1.05rem; }
.vn-event .ev-dmg { font-size: 1.35rem; line-height: 1; padding: 3px 12px; border-radius: 8px; border: 1px solid var(--line); animation: dmgpop .38s cubic-bezier(.2,1.5,.4,1); }
.vn-event .ev-dmg.to-player { border-color: #5a2630; background: rgba(192,52,77,.12); }
.vn-event .ev-dmg.to-npc { border-color: var(--ember-dim); background: rgba(255,122,47,.10); }
.vn-event .ev-dmg.heal { border-color: #3c5c3c; background: rgba(107,191,107,.12); }
.vn-event .ev-dmg.miss { background: transparent; }
/* small inline in the log transcript */
.vn-beat .ev-roll { font-size: 10px; padding: 1px 5px; }
.vn-beat .ev-dmg, .vn-beat .ev-crit { font-size: 11px; margin-left: 3px; }

/* ---- d20 roll-chip hover tooltip (the die + the full math) ---- */
.roll-tip {
  position: fixed; z-index: 200; width: 216px; pointer-events: none;
  padding: 12px 13px; border-radius: 8px; border: 1px solid var(--seam);
  background:
    repeating-linear-gradient(45deg, rgba(184,146,63,.05) 0 1px, transparent 1px 7px),
    linear-gradient(155deg, var(--panel), var(--bg-2));
  box-shadow: 0 16px 44px rgba(0,0,0,.62), inset 0 0 0 1px rgba(0,0,0,.45);
  font-family: var(--font); animation: rtPop .12s ease;
}
.roll-tip.hidden { display: none; }
@keyframes rtPop { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }
.rt-head { display: flex; align-items: center; gap: 11px; margin-bottom: 9px; }
.rt-hi { min-width: 0; }
.rt-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.rt-need { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); margin-top: 2px; }
.rt-need b { color: var(--ink-dim); }
/* the die */
.d20-svg { width: 42px; height: 42px; flex: none; }
.d20-body { fill: rgba(255,122,47,.06); stroke: var(--ember-dim); stroke-width: 3; stroke-linejoin: round; }
.d20-face { fill: rgba(255,122,47,.10); stroke: none; }
.d20-edge { stroke: var(--ember-dim); stroke-width: 1.5; opacity: .5; }
.d20-num  { fill: var(--ember); font-family: var(--mono); font-weight: 700; font-size: 32px; text-anchor: middle; }
.d20-svg.crit .d20-body { stroke: var(--ember); }
.d20-svg.crit .d20-face { fill: rgba(255,122,47,.22); }
.d20-svg.crit .d20-num  { fill: #ffd27a; }
.d20-svg.fumble .d20-body, .d20-svg.fumble .d20-edge { stroke: var(--vael); }
.d20-svg.fumble .d20-face { fill: rgba(192,52,77,.16); }
.d20-svg.fumble .d20-num  { fill: var(--vael); }
/* the math table */
.rt-math { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 6px 0; margin-bottom: 8px; }
.rt-row { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 12px; line-height: 1.7; }
.rt-row .rt-lbl { color: var(--ink-dim); } .rt-row .rt-val { color: var(--ink); }
.rt-row.base .rt-lbl, .rt-row.base .rt-val { color: var(--ink-faint); }
.rt-row.total { margin-top: 3px; border-top: 1px dashed var(--line); padding-top: 4px; }
.rt-row.total .rt-lbl, .rt-row.total .rt-val { color: var(--ember); font-weight: 700; }
.rt-foot { display: flex; align-items: center; justify-content: space-between; }
.rt-vs { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); }
.rt-out { font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .06em; padding: 2px 8px; border-radius: 5px; }
.rt-out.ok   { color: #8fd17a; background: rgba(107,191,107,.12); }
.rt-out.no   { color: var(--ink-faint); background: rgba(120,120,120,.1); }
.rt-out.crit { color: #ffd27a; background: rgba(255,122,47,.16); }

/* ---- combat tracker (HUD) ---- */
.combat-panel { border: 1px solid #5a2630; border-radius: 10px; padding: 10px 12px; margin: 12px 0; background: rgba(192,52,77,.07); }
.combat-panel.hidden { display: none; }
.combat-head { font-family: var(--mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--ember); }
.combat-you { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); margin: 3px 0 6px; }
/* Each foe is a FACE + its bars — you should see what you're fighting, not just a name. */
.combat-foe { margin-top: 8px; display: flex; gap: 8px; align-items: center; }
.combat-foe-body { flex: 1; min-width: 0; }   /* min-width:0 so a long name can ellipsize */
.combat-foe-face {
  flex: 0 0 auto; width: 42px; height: 42px; border-radius: 8px; object-fit: cover;
  object-position: top center;                /* busts are chest-up — keep the head, not the chest */
  border: 1px solid var(--line); background: radial-gradient(circle at 50% 38%, #1d1813, #0b0908);
  transition: filter .3s ease, opacity .3s ease; }
.combat-foe-face.empty { display: block; }    /* no art yet — an empty frame, never a broken row */
/* the killing blow: the face goes grey and sinks back, matching the row's .down state */
.combat-foe.down .combat-foe-face { filter: grayscale(1) brightness(.5); opacity: .5; }
.combat-foe-top { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
.combat-foe-name { font-size: 13px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combat-foe-ac { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); flex-shrink: 0; }
.combat-foe-bar { height: 5px; border-radius: 3px; background: var(--panel-2); overflow: hidden; margin: 3px 0; }
.combat-foe-fill { height: 100%; background: var(--vael); transition: width .3s ease; }
.combat-foe-hp { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); }
.combat-empty { font-size: 12px; color: var(--ink-faint); font-style: italic; }

/* ---- "Present" NPC roster — floats top-right OVER the chat log (kept out of
   the HUD so it never pushes the gear grid down). Compact translucent card. ---- */
#chat-pane { position: relative; }        /* anchor for the floating roster */
.present {
  position: absolute; top: 12px; right: 108px; z-index: 6;   /* clear the stats column (88px wide, flush to the HUD) so the roster isn't hidden under it */
  max-width: 208px; padding: 7px 9px 8px;
  background: rgba(20, 16, 13, .82); border: 1px solid var(--line);
  border-radius: 12px; backdrop-filter: blur(5px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, .42);
}
.present.hidden { display: none; }
.present-lbl {
  font-family: var(--mono); font-size: 9px; letter-spacing: 2px;
  text-transform: uppercase; color: var(--ink-faint);
  text-align: right; margin: 0 2px 6px;
}
.present-row { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.present-npc {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  width: 56px; padding: 0; margin: 0; background: none; border: none;
  cursor: pointer; font: inherit;
}
.pr-portrait {
  position: relative; width: 56px; height: 56px; border-radius: 9px;
  overflow: hidden; box-shadow: 0 0 0 1px var(--line);
  transition: box-shadow .15s ease, transform .15s ease;
}
.pr-portrait .art-slot { width: 100%; height: 100%; border: none; border-radius: 9px; }
.present-npc.fac-vael  .pr-portrait { box-shadow: 0 0 0 1px var(--vael); }
.present-npc.fac-aurex .pr-portrait { box-shadow: 0 0 0 1px var(--aurex); }
.present-npc.fac-seam  .pr-portrait { box-shadow: 0 0 0 1px var(--seam); }
.present-npc:hover .pr-portrait { transform: translateY(-1px); box-shadow: 0 0 0 2px var(--ember-dim), 0 6px 16px rgba(0,0,0,.4); }
.pr-name {
  font-size: 9px; line-height: 1.15; text-align: center; max-width: 56px;
  color: var(--ink-dim); overflow: hidden; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.present-npc:hover .pr-name { color: var(--ink); }
.pr-name.vael { color: var(--vael); } .pr-name.aurex { color: var(--aurex); } .pr-name.seam { color: var(--seam); }
.pr-badge {
  position: absolute; top: 2px; right: 2px; width: 16px; height: 16px;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; border-radius: 50%; background: rgba(0, 0, 0, .72);
  border: 1px solid var(--line);
}
.pr-badge.hostile  { color: var(--vael); border-color: var(--vael); }
.pr-badge.merchant { color: var(--seam); border-color: var(--seam); }

/* entity highlights — blue items, green people, orange places (toggle via settings) */
.ent { font-weight: 600; }
.ent-item   { color: var(--aurex); }
.ent-person { color: #6bbf6b; }
.ent-loc    { color: var(--ember); }
.ent-item[data-item] { cursor: pointer; }
.ent-item[data-item]:hover { text-decoration: underline; }
body.no-ent .ent { color: inherit; font-weight: inherit; }

/* settings: VN controls */
.settings-sep { height: 1px; background: var(--line); margin: 2px 0; }
.settings-check { flex-direction: row !important; align-items: center; gap: 8px !important; text-transform: none !important; letter-spacing: 0 !important; font-size: 12px !important; color: var(--ink-dim) !important; cursor: pointer; }
.settings-check input { accent-color: var(--ember); }

/* audio menu: a volume slider + mute button per channel (music / effects / typing) */
.snd-pop { width: 250px; gap: 12px; }
.snd-row { display: flex; align-items: center; gap: 10px; }
/* fixed width (fits the widest glyph — the keyboard) so all three rows line up */
.snd-mute { flex-shrink: 0; width: 48px; padding: 5px 0; text-align: center; font-size: 15px; line-height: 1.1; }
.snd-mute.off { opacity: .4; }   /* clearly-muted (plus the .icon-btn.off strike/dim) */
.snd-body { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.snd-label { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.snd-vol { width: 100%; accent-color: var(--ember); }

/* ---- new game modal: narrow + centered ---- */
.newgame-card { width: min(460px, 92vw); }
.newgame-body { padding: 22px 26px; display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.newgame-body p { margin: 0; color: var(--ink); font-size: 16px; line-height: 1.5; }
.newgame-body .settings-check { display: inline-flex; justify-content: center; font-size: 15px !important; gap: 10px !important; }
.newgame-body .settings-check input { width: 17px; height: 17px; }
.newgame-body .settings-note { font-size: 14px; color: var(--ink-faint); line-height: 1.5; }
.settings-pop input[type=range] { accent-color: var(--ember); width: 100%; }

/* ---- character creation (new game) ---- */
.cc-card { width: min(760px, 94vw); }
.cc-body { flex-direction: row; align-items: flex-start; text-align: left; gap: 20px;
  max-height: min(80vh, 780px); overflow-y: auto; }
.cc-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 13px; }
/* right-hand ability-score panel */
.cc-stats { flex: none; width: 216px; display: flex; flex-direction: column; gap: 10px;
  padding: 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2);
  position: sticky; top: 0; }
.cc-stats-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.cc-reroll { background: var(--panel); color: var(--ember); border: 1px solid var(--ember-dim);
  border-radius: 999px; font-family: var(--mono); font-size: 11px; letter-spacing: .04em;
  padding: 4px 10px; cursor: pointer; white-space: nowrap; }
.cc-reroll:hover { background: var(--ember-dim); color: #fff; border-color: var(--ember); }
.cc-reroll:active { transform: scale(.95); }
.cc-abils { display: flex; flex-direction: column; gap: 4px; }
.cc-abil { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 8px;
  padding: 5px 9px; border-radius: 7px; background: var(--panel); }
.cc-abil .cc-ab-name { font-size: 13px; color: var(--ink-dim); }
.cc-abil .cc-ab-score { font-family: var(--mono); font-size: 15px; color: var(--ink); min-width: 20px; text-align: right; }
.cc-abil .cc-ab-mod { font-family: var(--mono); font-size: 12px; min-width: 30px; text-align: right;
  padding: 1px 6px; border-radius: 5px; }
.cc-ab-mod.pos { color: #8fd17a; } .cc-ab-mod.neg { color: var(--vael); } .cc-ab-mod.zero { color: var(--ink-faint); }
.cc-abil.rolling { animation: ccRoll .28s ease; }
@keyframes ccRoll { 0% { opacity: .25; transform: translateY(-3px) } 100% { opacity: 1; transform: none } }
.cc-hint { margin: 0 !important; font-size: 11.5px !important; color: var(--ink-faint) !important;
  line-height: 1.4; text-align: left !important; font-style: italic; }
.cc-prof { font-size: 12px; color: var(--ink-dim); line-height: 1.5; border-top: 1px solid var(--line); padding-top: 9px; }
.cc-prof b { color: var(--ember); font-weight: 600; }
/* "what's in your pocket?" starter-trinket picker */
/* Five trinkets, ONE row, art only — read by hovering (the tooltip carries the name +
   effect). Replaces five stacked text cards that ate most of the creation screen.
   Fixed 5 columns rather than auto-fit: the set is exactly config.STARTER_TRINKETS, and
   a wrapped 6th row would defeat the point of the change. */
.cc-pocket { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.cc-pk {
  aspect-ratio: 1; padding: 5px; cursor: pointer; transition: .12s;
  background: radial-gradient(circle at 50% 38%, #1d1813, #0b0908);
  border: 1px solid var(--line); border-radius: 9px;
  display: flex; align-items: center; justify-content: center; }
.cc-pk img { width: 100%; height: 100%; object-fit: contain; display: block;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.5)); }
.cc-pk:hover { border-color: var(--ember-dim); transform: translateY(-1px); }
.cc-pk:focus-visible { outline: none; border-color: var(--ember-dim); }
.cc-pk.active { border-color: var(--ember); background: rgba(255,122,47,.07);
  box-shadow: inset 0 0 0 1px var(--ember-dim); }
/* names the SELECTED trinket — the tiles are pictures, so without this you'd have to
   hover your own choice to recall what you took */
.cc-pocket-name { display: flex; flex-direction: column; gap: 1px; min-height: 2.6em;
  margin-top: 2px; }
.cc-pocket-name > span:first-child { font-size: 14px; font-weight: 600; color: var(--rar, var(--ink)); }
.cc-pk-note { font-size: 12px; color: var(--ink-dim); line-height: 1.4; }
@media (max-width: 640px) {
  .cc-body { flex-direction: column; }
  .cc-stats { width: auto; align-self: stretch; position: static; }
}
.cc-lead { text-align: center; color: var(--ember) !important; font-style: italic; font-size: 17px !important; margin-bottom: 2px !important; }
.cc-field { display: flex; flex-direction: column; gap: 5px; }
/* Origin is a <select> now (a closed archetype list). The CC panel had no select
   styling, so without this it renders as a raw white OS dropdown in the middle of the
   dark card. Matches the settings popover's select. */
.cc-field select {
  background: var(--bg-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 9px 10px; font-family: var(--font); font-size: 14px;
  cursor: pointer; }
.cc-field select:focus { outline: none; border-color: var(--ember-dim); }
.cc-field select option { background: var(--bg-2); color: var(--ink); }
.cc-label { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-dim); }
.cc-sub { text-transform: none; letter-spacing: 0; color: var(--ink-faint); font-style: italic; }
.cc-body input[type=text], .cc-body textarea {
  background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 7px;
  padding: 9px 11px; font-family: var(--font); font-size: 15px; width: 100%; box-sizing: border-box; resize: vertical; }
.cc-body input[type=text]::placeholder, .cc-body textarea::placeholder { color: var(--ink-faint); font-style: italic; }
.cc-body input[type=text]:focus, .cc-body textarea:focus { outline: none; border-color: var(--ember-dim); }
.cc-seg { display: flex; gap: 7px; }
.cc-seg button {
  flex: 1; padding: 8px 6px; background: var(--bg); color: var(--ink-dim); cursor: pointer;
  border: 1px solid var(--line); border-radius: 7px; font-family: var(--font); font-size: 14px; transition: .12s; }
.cc-seg button:hover { color: var(--ink); border-color: var(--ember-dim); }
.cc-seg button.active { background: var(--ember-dim); border-color: var(--ember); color: #fff; }
.cc-seg button:disabled { opacity: .4; cursor: not-allowed; }
.cc-panel { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.cc-panel.hidden { display: none; }
.cc-preset-img {
  width: 132px; height: 132px; object-fit: cover; border-radius: 9px;
  border: 1px solid var(--line); background: var(--bg-2); }
.cc-note { margin: 0 !important; font-size: 12.5px !important; color: var(--ink-faint) !important; line-height: 1.45; text-align: center; }
.cc-warn { color: var(--vael) !important; opacity: .85; }

/* ---- character creation: upload your own portrait ---- */
/* The art-OFF path to a face that's yours (the public droplet has no GPU). */
.cc-upload-row { display: flex; gap: 14px; align-items: flex-start; width: 100%; }
.cc-upload-preview {
  flex: 0 0 auto; width: 132px; height: 132px; border-radius: 9px;
  border: 1px dashed var(--line); background: var(--bg-2) center/cover no-repeat;
  display: flex; align-items: center; justify-content: center; }
.cc-upload-preview.has-img { border-style: solid; border-color: var(--ember-dim); }
.cc-upload-preview:not(.has-img)::after {
  content: attr(data-empty); font-size: 11.5px; color: var(--ink-faint);
  text-align: center; padding: 0 10px; line-height: 1.4; }
.cc-upload-side { flex: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 7px; }
.cc-upload-side .cc-note { text-align: left; }

/* There is NO global `.hidden` rule in this stylesheet — the convention is an
   explicit scoped one per element (.modal.hidden, .cc-panel.hidden, …). So a new
   element carrying class="hidden" is NOT hidden until it gets a rule here. The
   Remove button shipped visible-with-no-picture for exactly this reason.
   `.gate-err.hidden` was missing too: it only *looked* fine because the element is
   empty until an error lands, and the invite gate reloads the page on success. */
#cc-file-clear.hidden,
#cc-mode-custom.hidden,
.gate-err.hidden { display: none; }

/* ---- no renderer on this box (WARDLINE_ART=0) ---- */
/* Anything whose ONLY outcome is a render is removed, not left to fail silently.
   The JS guards the click paths too (openArtPrompt / rerollPortrait / rerollItemArt
   all early-return on !ART_ON) — this just stops them LOOKING interactive, because a
   button that does nothing when clicked reads as a bug. */
body.no-art .ci-reroll,
body.no-art #cc-mode-custom { display: none !important; }
body.no-art #portrait { cursor: default; }
body.no-art #portrait:hover { border-color: var(--line); }   /* kill the hover tell */

/* ---- codex: alignment slider + quests ---- */
.codex-align { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.codex-align .al-end { font-family: var(--mono); font-size: 8px; letter-spacing: .5px; text-transform: uppercase; color: var(--ink-faint); white-space: nowrap; }
.codex-align .al-end.vael { color: var(--vael); }
.codex-align .al-end.aurex { color: var(--aurex); }
.al-track { position: relative; flex: 1; height: 4px; border-radius: 999px; background: linear-gradient(90deg, var(--vael), #40342c, var(--aurex)); }
.al-mark { position: absolute; top: 50%; width: 10px; height: 10px; border-radius: 50%; background: var(--ink); border: 2px solid var(--bg); transform: translate(-50%, -50%); }
.codex-quests { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; }
.codex-quest { font-size: 12px; color: var(--ink-dim); display: flex; align-items: center; gap: 6px; }
.q-badge { font-family: var(--mono); font-size: 9px; text-transform: uppercase; padding: 1px 6px; border-radius: 999px; border: 1px solid var(--line); }
.q-active .q-badge { color: var(--ember); border-color: var(--ember-dim); }
.q-done .q-badge { color: #6bbf6b; border-color: #3c5c3c; }
.q-failed .q-badge { color: var(--vael); border-color: #5a2630; }

/* ---- item inspector ---- */
.item-card { width: min(520px, 92vw); }
.item-body { padding: 18px; display: flex; gap: 16px; }
.item-body .art-slot { width: 160px; height: 160px; flex-shrink: 0; border-radius: 12px; }
.item-meta { flex: 1; min-width: 0; }
.item-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 10px; }
.item-tags span { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: var(--ink-dim); border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; }
.item-desc { font-size: 14px; color: var(--ink); font-style: italic; margin-bottom: 14px; }
.item-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.item-reroll { background: var(--panel-2); color: var(--ink-dim); border: 1px solid var(--line); border-radius: 8px; padding: 8px 14px; cursor: pointer; font-family: var(--mono); font-size: 12px; }
.item-reroll:hover { color: var(--ember); border-color: var(--ember-dim); }
.item-reroll:disabled { opacity: .5; cursor: default; }
/* menu-driven equip/unequip — the primary action, so give it the ember accent */
.item-equip { background: var(--ember-dim); color: #1a0f06; border: none; border-radius: 8px; padding: 8px 16px; cursor: pointer; font-family: var(--mono); font-weight: 700; font-size: 12px; }
.item-equip:hover { background: var(--ember); }
.item-equip:disabled { opacity: .5; cursor: default; }

/* ---- loadout editor ---- */
.loadout-open { width: 100%; margin-top: 12px; background: var(--panel); color: var(--ink-dim); border: 1px solid var(--line); border-radius: 8px; padding: 9px; cursor: pointer; font-family: var(--mono); font-size: 12px; letter-spacing: 1px; }
.loadout-open:hover { color: var(--ember); border-color: var(--ember-dim); }
.loadout-card { width: min(760px, 94vw); }
.loadout-body { padding: 16px 18px; display: flex; flex-direction: column; gap: 14px; }
/* the whole gear area is one drop zone — drop anywhere and it finds the slot */
.loadout-slots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; border: 1px dashed transparent; border-radius: 12px; padding: 4px; transition: border-color .15s, background .15s; }
.loadout-slots.droppable { border-color: var(--ember-dim); }
.loadout-slots.over { border-color: var(--ember); background: rgba(255,122,47,.06); }
.lo-slot { border: 1px solid var(--line); border-radius: 10px; padding: 6px; background: var(--bg-2); display: flex; flex-direction: column; gap: 5px; min-height: 96px; }
.lo-slot-label { font-family: var(--mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.lo-slot.changed { border-color: var(--seam); box-shadow: inset 0 0 0 1px var(--seam); }
.lo-empty { flex: 1; border-radius: 8px; background: radial-gradient(circle at 50% 40%, #1a1611, #0b0908); display: flex; align-items: center; justify-content: center; }
.lo-empty::after { content: attr(data-empty); font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: 1px; color: #4a4038; }
.lo-tile { display: flex; flex-direction: column; align-items: center; gap: 3px; cursor: grab; user-select: none; }
.lo-tile:active { cursor: grabbing; }
.lo-tile.dragging { opacity: .4; }
.lo-tile .art-slot { width: 100%; aspect-ratio: 1/1; height: auto; border-radius: 8px; }
.lo-tile-name { font-size: 11px; color: var(--ink-dim); text-align: center; line-height: 1.15; max-height: 2.4em; overflow: hidden; }
.loadout-pool-wrap { border-top: 1px solid var(--line); padding-top: 12px; }
.loadout-pool-head { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 8px; }
.loadout-pool { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; min-height: 84px; border: 1px dashed var(--line); border-radius: 10px; padding: 8px; transition: border-color .15s; }
.loadout-pool.over { border-color: var(--ember); background: rgba(255,122,47,.06); }
.lo-pool-empty { grid-column: 1/-1; color: var(--ink-faint); font-style: italic; font-size: 12px; align-self: center; text-align: center; }
.loadout-foot { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-top: 1px solid var(--line); }
.loadout-status { font-size: 12px; color: var(--ink-dim); }

/* ---- coin + merchant trade bar + shop ---- */
.coin { font-family: var(--mono); font-size: 12px; color: var(--seam); }
.merchant-bar { display: flex; gap: 8px; padding: 10px 18px 0; flex-wrap: wrap; }
.merchant-bar:empty { display: none; padding: 0; }
.trade-btn { background: var(--panel-2); color: var(--seam); border: 1px solid var(--seam); border-radius: 999px; padding: 5px 14px; cursor: pointer; font-family: var(--mono); font-size: 12px; }
.trade-btn:hover { background: var(--seam); color: #1a1206; }

/* compact list — one thin row per item; hover for the full stat-compare tooltip */
.shop-body { overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 3px; }
.shop-empty { text-align: center; color: var(--ink-faint); font-style: italic; padding: 22px; }
/* merchant hero banner: 4:3 scene, character on the RIGHT, name/info over the LEFT */
.shop-banner { position: relative; width: 100%; aspect-ratio: 5 / 2; max-height: 300px; overflow: hidden;
  border: 1px solid var(--line); border-radius: 10px; margin-bottom: 6px; background: var(--panel); }
.shop-banner-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: right 28%; display: block; }
.shop-banner-img.pending { background: linear-gradient(120deg, var(--panel), var(--bg-2)); animation: shimmer 1.4s ease-in-out infinite; }
.shop-banner-scrim { position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(6,4,3,.92) 0%, rgba(6,4,3,.62) 32%, rgba(6,4,3,0) 60%); }
.shop-banner-info { position: absolute; left: 18px; bottom: 14px; right: 42%; }
.shop-banner-name { font-family: var(--mono); font-size: 22px; letter-spacing: 2px; color: var(--ink); text-shadow: 0 2px 12px rgba(0,0,0,.85); }
.shop-banner-tag { font-family: var(--mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--ember); margin-top: 5px; }
.shop-section { font-family: var(--mono); font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--ink-faint); margin: 12px 2px 3px; }
.shop-section:first-child { margin-top: 0; }
.shop-row { display: flex; align-items: center; gap: 10px; padding: 5px 8px; border: 1px solid transparent; border-radius: 8px; }
.shop-row:hover { background: var(--bg-2); border-color: var(--line); }
.shop-thumb { width: 34px; height: 34px; flex-shrink: 0; }
.shop-thumb .art-slot { width: 34px; height: 34px; border-radius: 7px; margin: 0; }
.shop-row-main { flex: 1; min-width: 0; }
.shop-name { font-size: 14px; color: var(--rar, var(--ink)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shop-sub { font-family: var(--mono); font-size: 9px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 1px; }
.shop-price { font-family: var(--mono); font-size: 12px; color: var(--seam); flex-shrink: 0; }
.shop-price.free { color: #6bbf6b; }
.buy-btn { background: var(--ember-dim); color: #1a0f06; border: none; border-radius: 6px; padding: 5px 12px; cursor: pointer; font-family: var(--mono); font-size: 12px; font-weight: 700; flex-shrink: 0; }
.buy-btn:hover { background: var(--ember); }
.buy-btn:disabled { opacity: .45; cursor: default; }
.buy-btn.sell { background: var(--panel-2); color: var(--seam); border: 1px solid var(--line); }
.buy-btn.sell:hover { background: var(--bg-2); border-color: var(--seam); }

/* ---- shop item tooltip (Diablo-style stat compare: border + pattern BG) ---- */
.shop-tip {
  position: fixed; z-index: 200; max-width: 262px; pointer-events: none;
  padding: 11px 13px; border-radius: 6px; border: 1px solid var(--seam);
  background:
    repeating-linear-gradient(45deg, rgba(184,146,63,.05) 0 1px, transparent 1px 7px),
    linear-gradient(155deg, var(--panel), var(--bg-2));
  box-shadow: 0 16px 44px rgba(0,0,0,.62), inset 0 0 0 1px rgba(0,0,0,.45);
}
.shop-tip.hidden { display: none; }
.shop-tip-name { font-size: 15px; font-weight: 600; color: var(--rar, var(--ink)); }

/* ---- item rarity (Diablo-style name colours; set --rar, elements read it) ---- */
.rar-common    { --rar: #b9ab97; }
.rar-uncommon  { --rar: #6ea86e; }
.rar-rare      { --rar: #d2a54a; }
.rar-legendary { --rar: #ff7a2f; }
.rar-relic     { --rar: #b57edb; }
#item-title { color: var(--rar, var(--ember)); }
/* trinket/neck EFFECT blurb */
.shop-tip-fx { font-size: 11.5px; color: var(--ink-dim); line-height: 1.5; margin: 7px 0 2px; border-top: 1px solid var(--line); padding-top: 7px; }
.shop-tip-fx .fx-name, .item-fx .fx-name { color: #d2a54a; font-family: var(--mono); font-weight: 700; }
.item-fx { font-size: 13px; color: var(--ink-dim); line-height: 1.55; margin: 8px 0; padding: 8px 11px;
           border-left: 2px solid #d2a54a; background: rgba(210,165,74,.06); border-radius: 4px; }
.item-fx.boon { border-left-color: #6bbf6b; background: rgba(107,191,107,.07); }
.item-fx.boon .fx-name { color: #8fd17a; }
.shop-tip-type { font-family: var(--mono); font-size: 9px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--ink-faint); margin-top: 1px; }
.shop-tip-stats { margin: 8px 0 6px; border-top: 1px solid var(--line); padding-top: 7px; }
.tip-stat { font-family: var(--mono); font-size: 12px; color: var(--ink-dim); display: flex; align-items: baseline; gap: 6px; line-height: 1.75; }
.tip-stat > span { text-transform: uppercase; font-size: 10px; color: var(--ink-faint); width: 28px; }
.tip-stat > b { color: var(--ink); }
.tip-delta.up { color: #6bbf6b; } .tip-delta.down { color: var(--vael); }
.shop-tip-cmp { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); font-style: italic; }
.tip-gain { font-family: var(--mono); font-size: 11px; color: #6bbf6b; margin-top: 5px; }
.tip-lose { font-family: var(--mono); font-size: 11px; color: var(--vael); margin-top: 3px; }
.tip-none { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); font-style: italic; margin-top: 5px; }
.shop-tip-desc { font-size: 11.5px; color: var(--ink-dim); font-style: italic; line-height: 1.5; margin-top: 8px; border-top: 1px solid var(--line); padding-top: 7px; }

@media (max-width: 900px) {
  main { flex-direction: column; }
  #left-rail { width: auto; border-right: none; border-bottom: 1px solid var(--line); max-height: 24vh; }
  #hud { width: auto; border-left: none; border-top: 1px solid var(--line); max-height: 42vh; }
}

/* ---- invite gate (public servers) ---- */
.gate-card { max-width: 440px; }
.gate-card .newgame-body p { color: var(--ink-dim); line-height: 1.55; }
#gate-code {
  width: 100%; box-sizing: border-box; margin-top: 10px;
  background: var(--bg-deep, #14110d); color: var(--ink, #e8dfd0);
  border: 1px solid var(--line); border-radius: 6px;
  padding: 10px 12px; font-size: 16px; letter-spacing: .04em;
  font-family: inherit;
}
#gate-code:focus { outline: none; border-color: var(--ember, #ee6b2d); }
.gate-err { color: #d3506a; font-size: 13px; margin: 8px 0 0; }

/* a foe dropped mid-reveal: their tracker row dims on the killing beat */
.combat-foe.down { opacity: .45; filter: saturate(.5); }
/* stacked floors: an above floor slides up and fades further out of the way */
.map-node .mm-floor.mm-above, .mm-floor.mm-above { opacity: .5; }
/* below floors read MORE clearly than above (their own opacity knob) */
.mm-floor.mm-below .map-node.ghost { opacity: .60; }
.mm-floor.mm-below .map-edge.ghost { opacity: .60; }
