/* Ghelmyon Web — dark terminal theme */
:root {
  --bg: #1a1a2e;
  --bg2: #16213e;
  --bg3: #0d1525;
  --fg: #d4d4d4;
  --fg-dim: #888;
  /* BU86 #2: was a fixed #2b2b36 (contrast ~1.2:1 against --bg, i.e. nearly
     invisible), which is what made scrolled-back / room-faded text unreadable.
     Derived from --fg-dim so it recedes relative to normal text while staying
     legible (contrast ~3.3-4:1 against --bg on every skin below, since the
     formula reads --fg-dim/--bg per theme instead of a hardcoded hex). */
  --fg-faded: color-mix(in srgb, var(--fg-dim) 80%, var(--bg));
  --accent: #e94560;
  --accent2: #0f3460;
  --narrator: #7ec8e3;
  --input-bg: #0f0f1a;
  --border: #333;
  --green: #4ade80;
  --yellow: #facc15;
  --cyan: #22d3ee;
  --sidebar-width: 200px;
  --right-panel-width: 300px;
}

/* IT66 theme/skin engine: a skin overrides the :root tokens above, selected by
   data-theme on <html>. "midnight" is the default :root (no block needed). The
   token-override blocks for the other skins live in themes.css; themes.js owns
   the registry + flips the attribute; the <head> FOUC guard sets it before
   first paint. */

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

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: "Cascadia Code", "Fira Code", "JetBrains Mono", "Consolas", monospace;
  font-size: 14px;
  overflow: hidden;
}

/* Compact laptop screens: shrink the root font a touch so more transcript
   fits without scrolling. All game text is rem-based off this root, so it all
   scales together (the pixel viewport is canvas-drawn and unaffected). The
   font-size is the only thing that changes; layout is untouched. */
@media (max-height: 820px) {
  html, body { font-size: 13px; }
}
@media (max-height: 700px), (max-width: 1280px) {
  html, body { font-size: 12px; }
}

.hidden { display: none !important; }

/* Login */
#login-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
  overflow: hidden;
}
.login-box {
  background: var(--bg2);
  padding: 2rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  width: 320px;
  position: relative;
  z-index: 2;
}
.login-box h1 {
  text-align: center;
  color: var(--accent);
  margin-bottom: 1.5rem;
  font-size: 1.8rem;
}
.login-box input {
  display: block;
  width: 100%;
  padding: 0.6rem;
  margin-bottom: 0.8rem;
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--fg);
  font-family: inherit;
  font-size: 1rem;
}
.login-box button {
  width: 100%;
  padding: 0.6rem;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 4px;
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
}
.login-box button:hover { opacity: 0.85; }
.login-discord {
  display: inline-block;
  margin-top: 0.9rem;
  color: var(--gold-dim, #8a7e5a);
  text-decoration: none;
  font-size: 0.85rem;
  opacity: 0.8;
  transition: opacity 0.2s;
}
.login-discord:hover { opacity: 1; color: var(--gold, #c9963a); }
/* BU32: small music + SFX toggles on the login screen. Must override the
   full-width accent `.login-box button` styling above (two classes beat
   `.login-box button`), and mirror the footer/splash strike-through cue. */
.login-audio {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 0.9rem;
}
.login-box .login-audio-btn {
  width: auto;
  background: rgba(20, 16, 12, 0.5);
  color: var(--fg-dim);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0.25rem 0.6rem;
  opacity: 0.8;
  position: relative;
}
.login-box .login-audio-btn:hover {
  opacity: 1;
  color: var(--fg);
  background: rgba(20, 16, 12, 0.5);
}
.login-audio-btn.audio-off { opacity: 0.5; }
.login-audio-btn.audio-off::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 130%;
  height: 2px;
  background: var(--red, #e44);
  transform: translate(-50%, -50%) rotate(-45deg);
  border-radius: 2px;
  pointer-events: none;
}
.error { color: var(--accent); margin-top: 0.5rem; font-size: 0.85rem; }

/* Game layout — 3-panel */
/* Welcome lobby */
#welcome-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
  overflow: hidden;
}
/* --- Landing atmosphere: drifting aurora + ember canvas behind the menu --- */
.landing-aurora {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  filter: blur(70px);
  opacity: 0.55;
}
.landing-aurora::before,
.landing-aurora::after {
  content: "";
  position: absolute;
  border-radius: 50%;
}
.landing-aurora::before {
  width: 65vmax;
  height: 65vmax;
  left: 0;
  top: -10%;
  background: radial-gradient(
    circle,
    rgba(86, 120, 200, 0.4),
    rgba(86, 120, 200, 0) 70%
  );
  animation: auroraDrift1 30s ease-in-out infinite alternate;
}
.landing-aurora::after {
  width: 60vmax;
  height: 60vmax;
  right: 0;
  bottom: -10%;
  background: radial-gradient(
    circle,
    rgba(200, 86, 120, 0.26),
    rgba(200, 86, 120, 0) 70%
  );
  animation: auroraDrift2 38s ease-in-out infinite alternate;
}
@keyframes auroraDrift1 {
  from {
    transform: translate(-12%, -6%) scale(1);
  }
  to {
    transform: translate(16%, 12%) scale(1.25);
  }
}
@keyframes auroraDrift2 {
  from {
    transform: translate(10%, 6%) scale(1.1);
  }
  to {
    transform: translate(-14%, -10%) scale(0.95);
  }
}
#landing-embers,
#login-embers {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .landing-aurora::before,
  .landing-aurora::after {
    animation: none;
  }
}

/* ====================================================================
   Reduce-flashing accessibility toggle (epilepsy / photosensitivity safety).
   `html.reduce-flashing` is set pre-paint by the bootstrap in index.html and
   by reduce_flashing.js. It removes EVERY CSS keyframe animation so nothing can
   strobe / flash / rapid-pulse. Opacity & filter BASE states still render (e.g.
   the combat danger tint holds steady) — only the animating is killed. Canvas-
   drawn flashes (dice, viewport pulse/weapon-flash, combat_anim, scene_renderer,
   combat_morph enter-flash) ignore CSS and are guarded in JS via
   window.ReduceFlashing.isOn().
   ==================================================================== */
html.reduce-flashing *,
html.reduce-flashing *::before,
html.reduce-flashing *::after {
  animation: none !important;
}
.welcome-box {
  position: relative;
  z-index: 2;
  /* Torch-lit weathered stone: warm top glow + dark stone gradient + grain,
     carved into the dark with an iron border, soot pooling at the edges. */
  background-color: #1c1814;
  background-image:
    radial-gradient(
      120% 80% at 50% -12%,
      rgba(214, 132, 72, 0.16),
      rgba(214, 132, 72, 0) 55%
    ),
    linear-gradient(180deg, #241e18 0%, #15110e 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
  padding: 2.5rem;
  border-radius: 5px;
  border: 1px solid #0c0908;
  box-shadow:
    0 18px 50px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 rgba(214, 162, 112, 0.13),
    inset 0 0 70px rgba(0, 0, 0, 0.5);
  width: 380px;
  text-align: center;
}
.welcome-box h1 {
  color: #e0455e;
  margin-bottom: 0.25rem;
  font-size: 2.4rem;
  letter-spacing: 0.35rem;
  /* Carved into stone, faintly lit like an ember. */
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.65),
    0 2px 7px rgba(224, 69, 94, 0.28);
}
.welcome-tagline {
  color: var(--fg-dim);
  font-style: italic;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
.welcome-sub {
  color: var(--fg-dim);
  margin-bottom: 0.5rem;
  font-size: 0.95rem;
}
/* BG111 A3: returning-player character name hint on the landing screen */
.welcome-char-hint {
  color: var(--accent);
  font-size: 0.85rem;
  font-style: italic;
  margin-bottom: 1rem;
  opacity: 0.9;
}
.welcome-hint {
  color: var(--fg-dim);
  font-size: 0.85rem;
  margin-bottom: 1.5rem;
  opacity: 0.85;
}
.welcome-hint kbd {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.05rem 0.4rem;
  font-family: inherit;
  color: var(--accent);
}
.welcome-actions {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.welcome-btn {
  display: block;
  width: 100%;
  padding: 0.7rem;
  background: linear-gradient(180deg, #2b2319 0%, #1c1611 100%);
  border: 1px solid #0c0908;
  border-radius: 4px;
  color: #cdbfa8;
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  box-shadow:
    inset 0 1px 0 rgba(214, 162, 112, 0.1),
    0 2px 4px rgba(0, 0, 0, 0.45);
  transition: background 0.15s, box-shadow 0.15s, color 0.15s;
}
.welcome-btn:hover {
  background: linear-gradient(180deg, #36291c 0%, #251c14 100%);
  color: #f0e4cf;
  box-shadow:
    inset 0 1px 0 rgba(255, 190, 120, 0.18),
    0 0 14px rgba(214, 130, 70, 0.22);
}
.welcome-btn.primary {
  background: linear-gradient(180deg, #d6455e 0%, #a8364a 100%);
  color: #fff;
  border-color: #7a2030;
  font-weight: bold;
  font-size: 1.1rem;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 0 18px rgba(214, 69, 94, 0.3);
}
.welcome-btn.primary:hover {
  background: linear-gradient(180deg, #e85068 0%, #b83a50 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    0 0 26px rgba(232, 80, 104, 0.45);
}
.welcome-footer {
  margin-top: 1.5rem;
  color: var(--fg-dim);
  font-size: 0.8rem;
}

#game-screen { height: 100%; }
#layout {
  display: flex;
  height: 100%;
}

/* Sidebar (left) */
#sidebar {
  width: var(--sidebar-width);
  min-width: 140px;
  max-width: 400px;
  background: var(--bg2);
  border-right: 1px solid var(--border);
  padding: 0.5rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex-shrink: 0;
}
#location-name {
  font-weight: bold;
  color: var(--yellow);
  text-align: center;
  padding: 0.3rem 0;
  font-size: 0.9rem;
}
.portrait {
  width: 100%;
  border-radius: 4px;
  cursor: pointer;
  display: block;
}
.portrait[src=""], .portrait:not([src]) { display: none; }
.portrait.broken { display: none; }
.portrait-label {
  font-size: 0.75rem;
  color: var(--fg-dim);
  text-align: center;
  padding: 0.2rem 0;
}
.portrait-label.focused { color: var(--accent); font-weight: bold; }
.npc-entry {
  margin-bottom: 0.3rem;
  transition: margin 0.25s ease;
}
.npc-entry .portrait {
  border: 2px solid transparent;
  transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
  cursor: crosshair;
}
.npc-entry .portrait:hover {
  border-color: var(--fg-dim);
  box-shadow: 0 0 6px rgba(255, 255, 255, 0.15);
}
.npc-entry.focused {
  margin-bottom: 0.5rem;
}
.npc-entry.focused .portrait {
  border-color: var(--accent);
  box-shadow: 0 0 12px rgba(233, 69, 96, 0.4);
  transform: scale(1.15);
  transform-origin: top center;
}

/* Pixel art portrait rendering — crisp upscaling */
.portrait-pixel {
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

/* NPC action bar (Talk/Greet/Look) */
#npc-action-bar {
  display: flex;
  gap: 4px;
  padding: 4px 2px;
  justify-content: center;
  animation: npc-action-fade-in 0.15s ease-out;
}
@keyframes npc-action-fade-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.npc-action-btn {
  flex: 1;
  padding: 4px 6px;
  font-size: 0.7rem;
  font-family: inherit;
  background: var(--bg3);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s;
}
.npc-action-btn:hover {
  background: var(--accent2);
  border-color: var(--accent);
}

/* HP bar */
.hp-bar-wrap {
  width: 100%;
  height: 8px;
  background: var(--input-bg);
  border-radius: 4px;
  overflow: hidden;
  margin: 0.2rem 0;
}
.hp-bar-fill {
  height: 100%;
  border-radius: 4px;
  transition: width 0.3s ease, background 0.3s ease;
}
.hp-bar-fill.hp-high { background: var(--green); }
.hp-bar-fill.hp-mid { background: var(--yellow); }
.hp-bar-fill.hp-low { background: var(--accent); }
.hp-text {
  font-size: 0.7rem;
  color: var(--fg-dim);
  text-align: center;
}

/* Mana bar */
.mana-bar-wrap {
  width: 100%;
  height: 6px;
  background: var(--input-bg);
  border-radius: 3px;
  overflow: hidden;
  margin: 0.15rem 0;
}
.mana-bar-fill {
  height: 100%;
  border-radius: 3px;
  background: #6366f1;
  transition: width 0.3s ease;
}
.mana-text {
  font-size: 0.65rem;
  color: var(--fg-dim);
  text-align: center;
}

/* Hunger bar */
.hunger-bar-wrap {
  width: 100%;
  height: 6px;
  background: var(--input-bg);
  border-radius: 3px;
  overflow: hidden;
  margin: 0.15rem 0;
}
.hunger-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease, background 0.3s ease;
}
.hunger-bar-fill.hunger-high { background: var(--green); }
.hunger-bar-fill.hunger-mid { background: var(--yellow); }
.hunger-bar-fill.hunger-low { background: var(--accent); }
.hunger-text {
  font-size: 0.65rem;
  color: var(--fg-dim);
  text-align: center;
}

/* Thirst bar */
.thirst-bar-wrap {
  width: 100%;
  height: 6px;
  background: var(--input-bg);
  border-radius: 3px;
  overflow: hidden;
  margin: 0.15rem 0;
}
.thirst-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease, background 0.3s ease;
}
.thirst-bar-fill.thirst-high { background: #3b82f6; }
.thirst-bar-fill.thirst-mid { background: var(--yellow); }
.thirst-bar-fill.thirst-low { background: var(--accent); }
.thirst-text {
  font-size: 0.65rem;
  color: var(--fg-dim);
  text-align: center;
}

/* Sidebar info (gold + time) */
#sidebar-info {
  padding: 0.3rem 0;
  border-top: 1px solid var(--border);
  margin-top: 0.2rem;
}
.sidebar-stat {
  font-size: 0.7rem;
  color: var(--fg-dim);
  text-align: center;
  padding: 0.1rem 0;
}
.sidebar-stat .stat-icon {
  color: var(--yellow);
}
.sidebar-stat .stat-value-gold {
  color: var(--yellow);
  font-weight: bold;
}
.sidebar-stat .stat-value-time {
  color: var(--cyan);
}

/* Sidebar always-visible sections */
.sidebar-section {
  padding: 0.3rem 0.5rem;
  border-top: 1px solid var(--border);
  font-size: 0.7rem;
}
.sidebar-section-title {
  color: var(--accent);
  font-size: 0.65rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.2rem;
}
#sidebar-effects-list .effect-line {
  color: var(--fg-dim);
  padding: 0.05rem 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.effect-line .effect-positive { color: var(--green); }
.effect-line .effect-negative { color: var(--red); }

/* QW108: hover popup explaining an effect + how to remove it. */
.effect-line.has-tip {
  position: relative;
  overflow: visible;
  cursor: help;
}
.effect-line .effect-tip {
  display: none;
  position: absolute;
  left: 0;
  top: 100%;
  z-index: 60;
  width: max-content;
  max-width: 220px;
  margin-top: 2px;
  padding: 6px 8px;
  background: rgba(20, 16, 12, 0.97);
  border: 1px solid var(--border);
  border-radius: 5px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  white-space: normal;
  font-size: 0.68rem;
  line-height: 1.3;
  pointer-events: none;
}
.effect-line.has-tip:hover .effect-tip { display: block; }
.effect-tip .effect-tip-desc { display: block; color: var(--fg); }
.effect-tip .effect-tip-remove {
  display: block;
  margin-top: 4px;
  color: var(--accent);
  font-style: italic;
}

/* QW109: collapsible sidebar sections. */
.sidebar-section.collapsible .sidebar-section-title {
  cursor: pointer;
  user-select: none;
}
.sidebar-section.collapsible .sidebar-section-title::before {
  content: "\25BE"; /* ▾ expanded */
  display: inline-block;
  width: 0.9em;
  font-size: 0.6rem;
  opacity: 0.7;
  transition: transform 0.12s ease;
}
.sidebar-section.collapsible.collapsed .sidebar-section-title::before {
  transform: rotate(-90deg); /* ▸ collapsed */
}
.sidebar-section.collapsible .sidebar-section-title:hover { filter: brightness(1.25); }
/* Hide every child except the clickable title when collapsed.
   BU145: `!important` so the hide wins over ID-level display rules on section
   content (e.g. `#sidebar-stats-grid { display: grid }`, which out-specifies a
   plain class rule and otherwise left the Stats section visibly un-collapsible
   even though its header click already toggled `.collapsed`). Mirrors the
   codebase `.hidden { display: none !important }` forced-hide idiom, and keeps
   every titled sidebar section collapsing consistently. */
.sidebar-section.collapsed > *:not(.sidebar-section-title) { display: none !important; }

/* UI light-slice STEP 1 (ui_collapse.js): collapsible first-class panels
   (room / character / coin&day / here / map). A clickable bar is inserted as a
   sibling before each panel; .collapsed hides the adjacent panel. */
.ui-collapse-bar {
  cursor: pointer;
  font-size: 0.62rem;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 6px;
  margin-top: 2px;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 5px;
}
.ui-collapse-bar::before {
  content: "\25BE"; /* down caret */
  font-size: 0.85em;
  transition: transform 0.15s;
}
.ui-collapse-bar.collapsed::before { transform: rotate(-90deg); }
.ui-collapse-bar:hover { filter: brightness(1.4); }
.ui-collapse-bar.collapsed + * { display: none !important; }
#sidebar-party-list .party-member {
  display: flex;
  justify-content: space-between;
  color: var(--fg-dim);
  padding: 0.05rem 0;
}
.party-member .party-hp { color: var(--green); font-size: 0.65rem; }
#sidebar-quest-text {
  color: var(--fg-dim);
  line-height: 1.3;
}
#sidebar-quest-text .quest-title {
  color: var(--yellow);
  font-weight: bold;
}
#sidebar-quest-text .quest-hint {
  color: var(--fg-dim);
  font-style: italic;
}
#sidebar-quest-text .quest-pin-mark {
  color: var(--fg-dim);
  font-weight: normal;
}
#sidebar-quest-text .quest-active-badge {
  color: var(--cyan);
  cursor: pointer;
  text-decoration: underline;
}
.quest-pin {
  margin-left: 0.4rem;
  padding: 0 0.3rem;
  font-size: 0.65rem;
  color: var(--fg-dim);
  background: none;
  border: 1px solid var(--fg-dim);
  cursor: pointer;
}
.quest-pin.pinned { color: var(--yellow); border-color: var(--yellow); }
#sidebar-notifications-list {
  color: var(--fg-dim);
  max-height: 12rem;
  overflow-y: auto;
}
#sidebar-notifications-list .notif-group {
  margin-bottom: 0.3rem;
}
#sidebar-notifications-list .notif-group-header {
  color: var(--accent);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.1rem;
  cursor: pointer;
  user-select: none;
}
#sidebar-notifications-list .notif-group-header:hover {
  color: var(--yellow);
}
#sidebar-notifications-list .notif-row {
  padding: 0.05rem 0 0.05rem 0.4rem;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
#sidebar-notifications-list .notif-row:hover {
  color: var(--fg);
}
#sidebar-notifications-list .notif-more {
  padding: 0.05rem 0 0.1rem 0.4rem;
  font-style: italic;
  color: var(--fg-dim);
  cursor: pointer;
}
#sidebar-notifications-list .notif-more:hover {
  color: var(--yellow);
}
#sidebar-notifications-count {
  color: var(--fg-dim);
  font-weight: normal;
  text-transform: none;
  font-size: 0.6rem;
}
#sidebar-stats-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.1rem 0.4rem;
  color: var(--fg-dim);
}
.stat-cell {
  display: flex;
  justify-content: space-between;
}
.stat-cell .stat-label { color: var(--fg-dim); }
.stat-cell .stat-val { color: var(--fg); font-weight: bold; }

/* Settings bar. Bug #349 retired the green "online" dot + label that used to
   sit here (and the `pulse` keyframes that only it used): the fixed
   Cloud/Showcase badge covered the same top-left corner, and connect /
   disconnect already print in the log feed. The bar stays as the settings-gear
   row and as the mount anchor for the customize strip. */
#connection-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  font-size: 0.7rem;
  color: var(--fg-dim);
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
}

/* Resize handles */
.resize-handle {
  width: 5px;
  cursor: col-resize;
  background: var(--border);
  flex-shrink: 0;
  transition: background 0.15s;
}
.resize-handle:hover, .resize-handle.active {
  background: var(--accent);
}

/* Main area (center) */
#main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 200px;
}
#main-toolbar {
  display: flex;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

/* Diegetic-UI context strip (P0.5) — visible while a modal context
   is active. Color-coded per context. ARIA live region announces
   entry/exit to screen readers. */
#ui-context-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.3rem 0.75rem;
  border-bottom: 1px solid var(--border);
  background: #2a1f12;
  color: #f4eed8;
  font-family: monospace;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}
#ui-context-strip.hidden {
  display: none;
}
#ui-context-strip[data-ctx="scene"] {
  background: #2a1530;
  color: #f0d8e8;
}
#ui-context-strip[data-ctx="combat"] {
  background: #401818;
  color: #f8d8c8;
}
#ui-context-strip[data-ctx="dream"] {
  background: #14223a;
  color: #c8d8f0;
}
#ui-context-strip[data-ctx="zone"] {
  background: #1a2a14;
  color: #d8e8c8;
}
#ui-context-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#ui-context-leave {
  flex: 0 0 auto;
  padding: 0.2rem 0.7rem;
  background: rgba(255, 255, 255, 0.12);
  color: inherit;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 3px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.8rem;
}
#ui-context-leave:hover {
  background: rgba(255, 255, 255, 0.22);
}
#ui-context-leave:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 1px;
}

/* Breadcrumb scaffold (P0.5 part 4) — inert until Phase P1 ships a
   ContextStack with depth >= 2. Renders as a slim secondary strip
   below the context strip when populated. */
#ui-breadcrumb {
  padding: 0.2rem 0.75rem;
  border-bottom: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.25);
  color: #c8c0a8;
  font-family: monospace;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
}
#ui-breadcrumb.hidden {
  display: none;
}
.ui-breadcrumb-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  align-items: center;
}
.ui-breadcrumb-item {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.ui-breadcrumb-crumb {
  background: transparent;
  border: 0;
  padding: 0.05rem 0.25rem;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.25);
}
.ui-breadcrumb-crumb:hover {
  color: #f4eed8;
  text-decoration-color: currentColor;
}
.ui-breadcrumb-crumb:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 1px;
}
.ui-breadcrumb-sep {
  opacity: 0.6;
}
.ui-breadcrumb-item [aria-current="page"] {
  color: #f4eed8;
  font-weight: 600;
}

/* Modal close button (P0.5 part 3) — shared × affordance for the
   event modal, lightbox, and any future native <dialog> contexts.
   Two-ways-out rule: ESC + Leave/× button + (where applicable)
   backdrop click. */
.modal-close {
  position: absolute;
  top: 0.4rem;
  right: 0.5rem;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: rgba(0, 0, 0, 0.35);
  color: #f4eed8;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  z-index: 5;
}
.modal-close:hover {
  background: rgba(0, 0, 0, 0.6);
  border-color: rgba(255, 255, 255, 0.45);
}
.modal-close:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 2px;
}
#lightbox-close {
  top: 1rem;
  right: 1rem;
  width: 2.4rem;
  height: 2.4rem;
  font-size: 1.6rem;
}

/* Atlas tab (P1) — static SVG viewer with thumbnail rail.
   See work/PLAYBOOK_ATLAS_TAB.md. Decorate non-modal context per
   work/SPEC_DIEGETIC_UI.md. */
#tab-atlas {
  padding: 0.5rem;
  overflow-y: auto;
}
#atlas-viewer {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
#atlas-big-wrap {
  position: relative;
  background: #f4eed8;
  border: 2px solid #5a4a24;
  border-radius: 4px;
  cursor: zoom-in;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  overflow: hidden;
  aspect-ratio: 960 / 600;
}
#atlas-big-wrap:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 2px;
}
#atlas-big {
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;  /* let wrap catch all clicks for lightbox */
}
/* Painted atlas mode (GhelmyonMap.png as #atlas-big). The hand-painted map
   already shows every city, road, river and label, so suppress the vector pin
   dots and keep ONLY the pulsing "you are here" marker on the current city.
   Pins are display-only; the whole map opens the lightbox on click. */
.atlas-painted {
  background: #15100a;
}
.atlas-painted .atlas-pin:not(.atlas-pin-current) {
  display: none;
}
.atlas-painted #atlas-overlay .atlas-pin {
  pointer-events: none;
}
/* Atlas Phase 3 Slice A — stacked overlay <img>s between the base
   settlements layer (#atlas-big, z-index 0) and the Phase 2 SVG sibling
   (#atlas-overlay, z-index 2). Each overlay's display is toggled via
   the matching checkbox in #atlas-overlays. Per-layer blend mode +
   opacity follow the generator's intent: terrain biomes multiply to
   tint the parchment, elevation overlays with relief, hydrology paints
   rivers in true colour, roads bake at full opacity. */
.atlas-overlay-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}
.atlas-overlay-layer[data-layer="terrain"] {
  /* Terrain is now a full shaded-relief parchment map (regenerated 2026-06-23:
     hillshade + modelled mountains/hills/forest), so it presents as its own
     view on toggle rather than a faint multiply tint — mirrors Waterways. */
  opacity: 0.95;
}
.atlas-overlay-layer[data-layer="elevation"] {
  opacity: 0.3;
  /* multiply tints the relief bands without the contrast-flip that
     `overlay` produced, which shimmered the city dots underneath
     ("wiggle"). Real fix (dots rendered ON TOP of backdrops) is the
     atlas redesign — see work/PLAYBOOK_ATLAS_UPDATE.md. */
  mix-blend-mode: multiply;
}
.atlas-overlay-layer[data-layer="hydrology"] {
  opacity: 0.7;
}
.atlas-overlay-layer[data-layer="roads"] {
  opacity: 1.0;
}
/* Atlas Phase 2 overlay — SVG sibling to #atlas-big. Same viewBox as
   the generator (960×600) so pin coords from atlas_meta.json drop in
   without conversion. */
#atlas-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;  /* tooltips via <title>; clicks fall through */
  z-index: 2;
}
#atlas-overlay .atlas-pin {
  pointer-events: auto;  /* enable native <title> tooltip on hover */
}
.atlas-pin-dot {
  fill: #2a1f12;
  stroke: #f4eed8;
  stroke-width: 1.2;
}
.atlas-pin-hamlet .atlas-pin-dot {
  fill: #5a4a24;
  stroke-width: 1;
}
.atlas-pin-fog .atlas-pin-dot {
  fill: rgba(80, 70, 50, 0.55);
  stroke: rgba(244, 238, 216, 0.4);
}
.atlas-pin-visited .atlas-pin-dot {
  fill: #2a1f12;
}
.atlas-pin-current .atlas-pin-dot {
  fill: #d04030;
  stroke: #fff4d0;
  stroke-width: 1.6;
}
.atlas-pin-halo {
  fill: rgba(208, 64, 48, 0.35);
  stroke: rgba(208, 64, 48, 0.65);
  stroke-width: 1;
  transform-origin: center;
  transform-box: fill-box;
  animation: atlas-pulse 1.6s ease-out infinite;
}
@keyframes atlas-pulse {
  0%   { transform: scale(0.6); opacity: 0.9; }
  100% { transform: scale(2.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .atlas-pin-halo {
    animation: none;
    opacity: 0.5;
  }
}

/* Atlas Phase 3 — route trace overlay. ``.atlas-route`` is the
   polyline drawn through TOWN_MAP_COORDS for the route path; danger
   variants tint it from green (safe) through yellow (moderate) to
   red (perilous) so the player can read risk at a glance. Pins on
   the route get a subtle ring; the chosen "from" pin gets a stronger
   highlight while waiting for the "to" click. */
.atlas-route {
  fill: none;
  stroke: #f8d878;
  stroke-width: 4;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.85;
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.4));
}
.atlas-route-danger-1 { stroke: #6fcf6f; }
.atlas-route-danger-2 { stroke: #c8d870; }
.atlas-route-danger-3 { stroke: #f8d878; }
.atlas-route-danger-4 { stroke: #f08040; }
.atlas-route-danger-5 { stroke: #d04030; }
.atlas-pin-route-from .atlas-pin-dot {
  stroke: #f8d878;
  stroke-width: 2.5;
  r: 6.5;
}
.atlas-pin-route-stop .atlas-pin-dot {
  stroke: #fff4d0;
  stroke-width: 1.8;
}
/* QW23 / Atlas P3 Slice D — faction territory tint. Subtle outer
   stroke (not background fill) so the existing fog/visited/current/
   route layers stack cleanly on top. Cities-only — hamlets stay
   neutral by design. */
.atlas-pin-faction-friendly .atlas-pin-dot {
  filter: drop-shadow(0 0 4px rgba(110, 200, 110, 0.65));
}
.atlas-pin-faction-hostile .atlas-pin-dot {
  filter: drop-shadow(0 0 4px rgba(210, 80, 80, 0.65));
}
.atlas-pin-faction-neutral .atlas-pin-dot {
  /* No glow — explicit neutral class for drift-guard tests. */
}

/* Atlas P3 Slice C — per-city zoom mode "Back to world" affordance.
   Absolutely positioned over #atlas-big-wrap; hidden by default,
   shown when _enterZoom() loads a per-city SVG. ESC also exits. */
#atlas-zoom-back {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 10;
  padding: 0.35rem 0.8rem;
  font-family: inherit;
  font-size: 0.85rem;
  background: rgba(58, 42, 20, 0.92);
  color: #f4eed8;
  border: 1px solid #8a7a4e;
  border-radius: 4px;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#atlas-zoom-back:hover {
  background: rgba(58, 42, 20, 1);
  border-color: #f8d878;
}
#atlas-zoom-back:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 2px;
}
#atlas-zoom-back.hidden {
  display: none;
}
#atlas-caption {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.3rem 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
  font-size: 0.8rem;
}
#atlas-caption-title {
  font-weight: bold;
  color: var(--fg);
}
#atlas-caption-sub {
  color: var(--dim);
  font-size: 0.75rem;
  font-style: italic;
}
/* IT300 - click-to-travel confirm buttons. Injected into #atlas-caption
   by atlas.js's _renderTravelButtons() while a pin-click travel ask is
   pending; removed on confirm/cancel/re-click. */
.atlas-travel-confirm {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.3rem;
}
.atlas-travel-btn {
  padding: 0.3rem 0.9rem;
  font-family: inherit;
  font-size: 0.8rem;
  border-radius: 4px;
  cursor: pointer;
  border: 1px solid var(--border);
}
.atlas-travel-go {
  background: #3a6b3a;
  color: #f4eed8;
  border-color: #6fa86f;
  font-weight: bold;
}
.atlas-travel-go:hover {
  background: #468446;
  border-color: #8fd08f;
}
.atlas-travel-cancel {
  background: rgba(255, 255, 255, 0.06);
  color: var(--fg);
}
.atlas-travel-cancel:hover {
  background: rgba(255, 255, 255, 0.14);
}
.atlas-travel-btn:focus-visible {
  outline: 2px solid #f8d878;
  outline-offset: 2px;
}
/* Atlas Phase 3 Slice A — overlay-toggle checkbox cluster (replaces
   the old #atlas-thumbs tab rail). Compact pill-style checkboxes that
   wrap onto multiple lines on narrow viewports. */
#atlas-overlays {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0.4rem 0.5rem;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.04);
}
#atlas-overlays legend {
  padding: 0 0.4rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--dim);
}
.atlas-overlay-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.55rem;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  font-size: 0.78rem;
  user-select: none;
  transition: background 0.15s, border-color 0.15s;
}
.atlas-overlay-toggle:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: var(--fg);
}
.atlas-overlay-toggle:has(input:checked) {
  background: rgba(248, 216, 120, 0.18);
  border-color: #f8d878;
  color: var(--fg);
}
.atlas-overlay-toggle input[type="checkbox"] {
  margin: 0;
  cursor: pointer;
}
.atlas-overlay-toggle:focus-within {
  outline: 2px solid #f8d878;
  outline-offset: 1px;
}
@media (max-width: 700px) {
  #atlas-overlays {
    flex-wrap: wrap;
  }
  .atlas-overlay-toggle {
    flex: 1 1 auto;
    justify-content: center;
  }
}
#viewport-toggle-btn {
  font-size: 0.75rem;
  padding: 0.15rem 0.6rem;
  background: transparent;
  color: var(--dim);
  border: 1px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
}
#viewport-toggle-btn:hover { color: var(--fg); border-color: var(--fg); }
#viewport-toggle-btn.active { color: var(--cyan); border-color: var(--cyan); }
#output {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem 1rem;
  white-space: pre-wrap;
  word-wrap: break-word;
  line-height: 1.5;
}
#output .narrator { color: var(--narrator); }
/* Narrator thinking spinner — braille-dot animation in the narrator line
   while the LLM is generating but before the first token arrives.
   Rotated frame-by-frame from JS (setInterval); class applies colour,
   spacing, and a gentle pulse. */
#output .narrator-thinking {
  color: color-mix(in srgb, var(--narrator) 70%, transparent);
  margin-left: 0.25em;
  display: inline-block;
  animation: narrator-thinking-pulse 1.2s ease-in-out infinite;
  font-size: 1.05em;
  vertical-align: baseline;
}
@keyframes narrator-thinking-pulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1.0; }
}
#output .bracket { color: var(--green); }
#output .error-line { color: var(--accent); }
/* Reading focus: older text recedes HARD toward the background so the latest
   turn pops. Scrolling up flips to _unfadeAll() (everything bright) for reading
   history, so the bottom-state fade can go dark without hurting legibility.
   Dial the strength with --fg-faded (lighter = gentler fade). */
#output > .faded { color: var(--fg-faded); transition: color 0.6s ease; }
#output > .faded.narrator { color: color-mix(in srgb, var(--narrator) 30%, var(--fg-faded)); }
#output > .faded.bracket { color: color-mix(in srgb, var(--green) 28%, var(--fg-faded)); }
#output > .faded.error-line { color: color-mix(in srgb, var(--accent) 32%, var(--fg-faded)); }
/* T5: previous-room transcript stays muted after a room change (still
   scrollable). Persistent, unlike the turn-based .faded which toggles. Mirrors
   .faded's colour treatment so a line carrying both reads identically. */
#output > .room-faded { color: var(--fg-faded); transition: color 0.6s ease; }
#output > .room-faded.narrator { color: color-mix(in srgb, var(--narrator) 30%, var(--fg-faded)); }
#output > .room-faded.bracket { color: color-mix(in srgb, var(--green) 28%, var(--fg-faded)); }
#output > .room-faded.error-line { color: color-mix(in srgb, var(--accent) 32%, var(--fg-faded)); }
/* BU65: a styled child span (command chip, ANSI colour, "special" highlight)
   carries its OWN colour, which beats the parent .faded/.room-faded colour swap
   on specificity, so it stayed full-brightness inside a faded block and broke
   the dim illusion. Dim the whole styled subtree with opacity (colour-agnostic,
   so a chip recedes with the surrounding text while keeping a hint of its hue).
   Scoped to descendants of a faded line only; structured printouts are exempt at
   the JS layer (they never receive .faded), so this can't touch them. */
#output > .faded :is(span, b, strong, a, code, mark),
#output > .room-faded :is(span, b, strong, a, code, mark) {
  opacity: 0.5;
  transition: opacity 0.6s ease;
}
/* IT225: plain mode prioritises readability, so the aggressive reading-focus
   fade softens to a gentle dim (never recedes into the background). */
html.plain-mode #output > .faded,
html.plain-mode #output > .room-faded { color: var(--fg-dim); }
/* Plain mode keeps the styled-span dim gentle too (readability over illusion). */
html.plain-mode #output > .faded :is(span, b, strong, a, code, mark),
html.plain-mode #output > .room-faded :is(span, b, strong, a, code, mark) { opacity: 0.78; }
/* ANSI color classes (converted from terminal escape codes by
   game.repl.colors.ansi_to_html). The combat feed's visual hierarchy (IT417)
   rides on these: the browser inherits the exact same hit / miss / crit colour
   semantics as the terminal, so both renderers stay consistent. In combat,
   .ansi-bold.ansi-red = the damage number (loudest token) and crit tags,
   .ansi-dim = enemy prose + whiffs (receding / secondary). */
.ansi-bold { font-weight: bold; }
.ansi-dim { opacity: 0.6; }
.ansi-red { color: #ff5555; }
.ansi-green { color: #50fa7b; }
.ansi-yellow { color: #f1fa8c; }
.ansi-cyan { color: #8be9fd; }
/* BU1543: magenta (relationship banners, FUMBLE) and gray (crafting recipe
   list) had an ansi class from the converter but no rule here. */
.ansi-magenta { color: #ff79c6; }
.ansi-gray { color: #9aa0b4; }
.ansi-white { color: #f8f8f2; font-weight: bold; }
/* POLISH (2026-09-28): loot names. colors.loot() emits 1;38;5;214 (bold
   256-colour orange) and ansi_to_html maps that one code here. A soft glow,
   no animation (docs/COLOR_STANDARD.md). */
/* POLISH (2026-09-28): an NPC speaking TO the player. colors.npc_speech()
   emits 38;5;223 (warm cream); ambient and NPC-to-NPC lines stay dim. */
.ansi-speech { color: #ffd7af; }
.ansi-loot {
  color: #ffaf00;
  font-weight: bold;
  text-shadow: 0 0 6px rgba(255, 175, 0, 0.55);
}
/* ROLLFMT (2026-09-27): the [ROLL] badge. ansi_to_html maps the one ANSI code
   used for it (1;7;36, reverse cyan) to .ansi-roll, and app.js marks the line
   holding it with .roll-line, so a d100 roll never reads as narration. */
.ansi-roll {
  display: inline-block;
  background: #8be9fd;
  color: #10141a;
  font-weight: bold;
  border-radius: 3px;
  padding: 0 0.35em;
  letter-spacing: 0.04em;
}
#output > .roll-line {
  border-left: 3px solid #8be9fd;
  padding-left: 0.4em;
  background: rgba(139, 233, 253, 0.07);
}
#output .image-inline {
  max-width: 400px;
  max-height: 300px;
  border-radius: 4px;
  cursor: pointer;
  margin: 0.3rem 0;
  display: block;
}

#status-bar {
  padding: 0.3rem 1rem;
  color: var(--fg-dim);
  font-size: 0.85rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}
#status-bar.hidden {
  display: none;
}

#input-form {
  display: flex;
  align-items: center;
  padding: 0.4rem 1rem;
  border-top: 1px solid var(--border);
  background: var(--input-bg);
}
#prompt-label {
  color: var(--accent);
  margin-right: 0.4rem;
  white-space: nowrap;
}
#input-field {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--fg);
  font-family: inherit;
  font-size: 1rem;
  outline: none;
}

/* Macro button bar */
#macro-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 1rem;
  border-top: 1px solid var(--border);
  background: var(--input-bg);
  min-height: 28px;
  align-items: center;
}
#macro-bar:empty {
  display: none;
}
.macro-btn {
  background: #2a2a3e;
  color: var(--green);
  border: 1px solid #444;
  padding: 3px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.75rem;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s;
}
.macro-btn:hover {
  background: #3a3a4e;
  border-color: var(--green);
}
.macro-btn:active {
  background: #4a4a5e;
}
.macro-hint {
  color: var(--fg-dim);
  font-size: 0.7rem;
  font-style: italic;
}

/* Exit direction bar — clickable navigation buttons */
#exit-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 1rem;
  align-items: center;
  justify-content: flex-end;
  min-height: 0;
}
#exit-bar:empty {
  display: none;
  padding: 0;
}
#exit-bar .exit-label {
  color: var(--fg-dim);
  font-size: 0.7rem;
  margin-right: 2px;
  user-select: none;
}
.exit-btn {
  background: #2a2a3e;
  color: #cc9955;
  border: 1px solid #3a3a4e;
  padding: 2px 10px;
  border-radius: 12px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.72rem;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  line-height: 1.4;
}
.exit-btn:hover {
  background: #3a3a4e;
  border-color: #cc6600;
  color: #ffb300;
}
.exit-btn:active {
  background: #4a4a5e;
}
.exit-btn .exit-dir {
  color: #888;
  font-size: 0.65rem;
  margin-right: 3px;
}
/* Hub-overflow "+N more…" / "less…" toggle (UX-fix 2026-05-29) */
.exit-btn.exit-more {
  background: #23233a;
  color: #8899bb;
  border-style: dashed;
  font-style: italic;
}
.exit-btn.exit-more:hover {
  background: #33334e;
  color: #aabbdd;
  border-color: #6677aa;
}
/* Undiscovered destination — name masked to "?????" (spoiler-safe). Still
   clickable: clicking walks you there, which discovers it. */
.exit-btn.exit-undiscovered {
  color: #8a8a8a;
  border-style: dashed;
  font-style: italic;
}
/* Hide exits during combat and cinematic */
body.in-combat #exit-bar,
body.in-cinematic #exit-bar,
body.in-dream #exit-bar {
  display: none;
}

/* Dream tutorial: the real world map ("navigator") is not the player's yet, so
   hide it (like the exit bar) and show a dream placeholder in its place. */
#minimap-dream-note {
  display: none;
}
body.in-dream #minimap-svg,
body.in-dream #minimap-legend {
  display: none;
}
body.in-dream #minimap-dream-note {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 100%;
  min-height: 160px;
  padding: 1rem;
  text-align: center;
  color: var(--fg-dim);
}
body.in-dream #minimap-dream-note .dream-note-title {
  font-style: italic;
  color: color-mix(in srgb, var(--narrator, #a9b7ff) 55%, var(--fg-dim));
}
body.in-dream #minimap-dream-note .dream-note-sub {
  font-size: 0.8rem;
  opacity: 0.85;
}

/* Quick action bar */
#quick-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 1rem;
  align-items: center;
  background: var(--input-bg);
  border-top: 1px solid var(--border);
}
.quick-btn {
  background: #2a2a3e;
  color: #cc9955;
  border: 1px solid #3a3a4e;
  padding: 2px 10px;
  border-radius: 12px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.72rem;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  line-height: 1.4;
  height: 26px;
}
.quick-btn:hover {
  background: #3a3a4e;
  border-color: #cc6600;
  color: #ffb300;
}
.quick-btn:active {
  background: #4a4a5e;
}
/* Hide quick bar during combat and cinematic */
body.in-combat #quick-bar,
body.in-cinematic #quick-bar {
  display: none;
}

/* Room transition effects */
#output.room-transition {
  opacity: 0;
  transition: opacity 150ms ease-out;
}
#output.room-transition-in {
  opacity: 1;
  transition: opacity 150ms ease-in;
}
#location-name.room-transition {
  opacity: 0;
  transition: opacity 150ms ease-out;
}
#location-name.room-transition-in {
  opacity: 1;
  transition: opacity 150ms ease-in;
}
#location-bg-wrap.room-transition {
  opacity: 0;
  transition: opacity 150ms ease-out;
}
#location-bg-wrap.room-transition-in {
  opacity: 1;
  transition: opacity 150ms ease-in;
}

.macro-hint code {
  background: rgba(255, 255, 255, 0.06);
  padding: 1px 4px;
  border-radius: 3px;
  font-family: inherit;
  font-style: normal;
  color: var(--green);
}

/* Right panel */
#right-panel {
  width: var(--right-panel-width);
  min-width: 180px;
  max-width: 500px;
  background: var(--bg2);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  overflow: hidden;
}

/* Tabs */
#right-tabs {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.tab-row {
  display: flex;
}
.tab-row + .tab-row {
  border-top: 1px solid var(--border);
}
.tab-btn {
  flex: 1;
  padding: 0.3rem 0.2rem;
  background: transparent;
  color: var(--fg-dim);
  border: none;
  border-bottom: 2px solid transparent;
  font-family: inherit;
  font-size: 0.7rem;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.tab-btn:hover { color: var(--fg); }
.tab-btn.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab-content {
  display: none;
  flex: 1;
  /* min-height:0 lets this flex child shrink below its content height so the
     overflow-y scroll actually engages. Without it a tall tab (Equip with
     dropdowns open, Skills, Stats) grows past the panel and the bottom gets
     clipped by #right-panel's overflow:hidden instead of scrolling. */
  min-height: 0;
  overflow-y: auto;
  padding: 0.5rem;
}
.tab-content.active { display: flex; flex-direction: column; }

/* --- Command palette --- */
#cmd-palette {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 4px 0;
}
.cmd-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cmd-group-label {
  font-size: 0.75em;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-dim);
  padding: 2px 2px 2px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  cursor: pointer;
  user-select: none;
}
.cmd-group-label:hover {
  color: var(--fg);
}
.cmd-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}
.cmd-btn {
  background: var(--bg3);
  border: 1px solid #3a3a5a;
  border-radius: 4px;
  padding: 6px 4px;
  color: var(--fg);
  font-family: inherit;
  font-size: 0.82em;
  cursor: pointer;
  text-align: center;
  transition: background 0.12s, border-color 0.12s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmd-btn:hover {
  background: #2a3a5a;
  border-color: #5a6a8a;
  color: #fff;
}
.cmd-btn:active {
  background: #3a4a6a;
  transform: scale(0.97);
}
/* Dimmed/hint button — verb exists but isn't usable in this context.
   Used e.g. for the Sleep button when the player isn't at an inn.
   Stays in the grid so the player learns the verb exists; click
   surfaces the hint as a bracketed log line via sendCmd. */
.cmd-btn-disabled {
  opacity: 0.4;
  font-style: italic;
  cursor: help;
}
.cmd-btn-disabled:hover {
  background: var(--bg3);
  border-color: #3a3a5a;
  color: var(--fg);
  opacity: 0.6;
}
.cmd-btn-disabled:active {
  transform: none;
}

/* Minimap */
#minimap-container {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 300px;
}
#minimap-svg {
  width: 100%;
  height: 100%;
}
#minimap-legend {
  font-size: 0.75rem;
  color: var(--fg-dim);
  padding: 0.3rem 0;
  text-align: center;
  flex-shrink: 0;
}

/* Minimap node styling — grid-snap layout */
.minimap-node { cursor: pointer; }
.minimap-node rect {
  rx: 5;
  ry: 5;
  stroke-width: 1.5;
  transition: fill 0.2s, stroke 0.2s, opacity 0.2s;
}
.minimap-node:hover rect {
  stroke: var(--fg);
  stroke-width: 2;
  filter: brightness(1.4);
}
.minimap-node text {
  font-family: inherit;
  font-size: 9px;
  fill: var(--fg);
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
  /* IT299: halo plate behind every label (the IT162 pattern, applied via a
     stroked outline since these are SVG text nodes rather than canvas) —
     keeps names legible over any node fill color, including the compass
     letter that floats near a box's edge. */
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: 3px;
  stroke-linejoin: round;
}
.minimap-edge {
  stroke: var(--border);
  stroke-width: 1;
  stroke-opacity: 0.35;
  fill: none;
}
.minimap-edge.direct {
  stroke: var(--cyan);
  stroke-width: 1.5;
  stroke-opacity: 0.6;
}
.minimap-node.current rect {
  fill: var(--accent);
  stroke: var(--yellow);
  stroke-width: 2.5;
}
.minimap-node.current text {
  fill: #fff;
  font-weight: bold;
  font-size: 10px;
}
.minimap-node.adjacent rect {
  /* IT299: was flat --accent2 (#0f3460), close enough to --bg (#1a1a2e)
     that the box nearly disappeared into the dark field. Lifted toward
     --cyan for a fill that reads as a solid, clickable plate. */
  fill: color-mix(in srgb, var(--accent2) 55%, var(--cyan) 25%);
  stroke: var(--cyan);
  stroke-width: 1.5;
}
.minimap-node.adjacent text {
  fill: var(--fg);
}
.minimap-node.distant rect {
  fill: var(--bg3);
  stroke: var(--border);
  opacity: 0.7;
}
.minimap-node.distant text {
  fill: var(--fg-dim);
  font-size: 8px;
}
/* Undiscovered destinations show a masked "?????" label — dim + dashed so
   they read as "something's there, name unknown" rather than a real place.
   IT299: rounder corners (fog-blob) than the crisp rectangular real nodes,
   so the shape itself signals "not a normal place yet" at a glance. An
   undiscovered ADJACENT node is still a real, working exit (clicking walks
   you there and discovers it) — only DISTANT undiscovered nodes are
   non-interactive context (cursor forced to default server/client-side). */
.minimap-node.undiscovered rect {
  fill: var(--bg3);
  stroke: var(--fg-dim);
  stroke-dasharray: 3 2;
  opacity: 0.75;
  rx: 9;
  ry: 9;
}
.minimap-node.undiscovered text {
  fill: var(--fg-dim);
  font-style: italic;
}
.minimap-node.distant.undiscovered {
  cursor: default;
}
/* "+N more" affordance — informational, not clickable. */
.minimap-more {
  cursor: default;
}
.minimap-more rect {
  fill: transparent;
  stroke: var(--fg-dim);
  stroke-dasharray: 2 2;
  opacity: 0.6;
}
.minimap-more text {
  fill: var(--fg-dim);
  font-size: 8px;
}

/* IT364 V2: per-floor building navigator (SPEC_VERTICAL_BUILDINGS §2.4).
   Reuses .minimap-node / .minimap-edge for the floor plan itself (current /
   adjacent / distant rooms style identically to the town minimap); this
   block only covers what's new: the left-edge floor rail, stair chevron
   badges, and the transient "stairs toward" highlight. */
.floor-rail-sep {
  stroke: var(--border);
  stroke-width: 1;
  stroke-opacity: 0.5;
}
.floor-pip {
  cursor: pointer;
}
.floor-pip rect {
  fill: var(--bg3);
  stroke: var(--border);
  stroke-width: 1;
  transition: fill 0.2s, stroke 0.2s;
}
.floor-pip:hover rect {
  stroke: var(--fg);
}
.floor-pip-num {
  font-family: inherit;
  font-size: 9px;
  fill: var(--fg-dim);
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
}
.floor-pip.current rect {
  fill: var(--accent);
  stroke: var(--yellow);
  stroke-width: 1.5;
}
.floor-pip.current .floor-pip-num {
  fill: #fff;
  font-weight: bold;
}
.floor-pip.undiscovered rect {
  fill: var(--bg3);
  stroke: var(--fg-dim);
  stroke-dasharray: 2 2;
  opacity: 0.5;
}
/* Stair chevron badge: passive marker everywhere except the room the
   player currently stands in, where it becomes a direct go-up/go-down
   shortcut (SPEC: "elsewhere it is a passive marker"). */
.stair-badge {
  font-family: inherit;
  font-size: 9px;
  fill: var(--yellow);
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
}
.stair-badge.clickable {
  pointer-events: all;
  cursor: pointer;
  fill: var(--cyan);
}
.stair-badge.clickable:hover {
  fill: #fff;
}
/* Brief pulse on the stair room a floor-rail pip click points toward. */
.stair-highlight rect {
  animation: floorPipStairPulse 1.4s ease-out;
}
@keyframes floorPipStairPulse {
  0% { stroke: var(--yellow); stroke-width: 3; }
  100% { stroke-width: 1.5; }
}
.exit-badge rect {
  fill: color-mix(in srgb, var(--accent2) 45%, #1a4a2a 40%);
}

/* Equipment panel */
#equipment-list, #stats-list {
  font-size: 0.8rem;
  line-height: 1.6;
}
.equip-slot {
  display: flex;
  justify-content: space-between;
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
}
.equip-slot-name { color: var(--fg-dim); }
.equip-slot-item { color: var(--fg); }
.equip-slot-empty { color: var(--fg-dim); font-style: italic; }
.stats-class-header {
  font-weight: bold;
  color: var(--yellow);
  font-size: 0.85em;
  padding: 0.2rem 0 0.4rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.stat-category {
  font-size: 0.65em;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  margin-top: 0.4rem;
  margin-bottom: 0.1rem;
  opacity: 0.7;
}
.stat-row {
  display: flex;
  justify-content: space-between;
  padding: 0.15rem 0;
}
.stat-has-tip {
  cursor: help;
  border-radius: 3px;
  transition: background 0.15s;
}
.stat-has-tip:hover {
  background: rgba(255, 255, 255, 0.04);
}
.stat-name { color: var(--fg-dim); }
.stat-value { color: var(--cyan); }

/* Relationships panel */
.rel-entry {
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.rel-name {
  font-weight: bold;
  color: var(--fg);
  font-size: 0.8rem;
}
.rel-status {
  font-size: 0.7rem;
  margin-left: 0.3rem;
}
.rel-status.romantic { color: #f472b6; }
.rel-status.friend { color: var(--green); }
.rel-status.acquaintance { color: var(--fg-dim); }
.rel-status.close_friend { color: var(--cyan); }
.rel-status.dating, .rel-status.lover, .rel-status.partner { color: #f472b6; }
.rel-bars {
  display: flex;
  gap: 0.3rem;
  margin-top: 0.2rem;
  font-size: 0.65rem;
}
.rel-bar-group {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.rel-bar-label { color: var(--fg-dim); }
.rel-bar-wrap {
  height: 4px;
  background: var(--input-bg);
  border-radius: 2px;
  overflow: hidden;
}
.rel-bar-fill {
  height: 100%;
  border-radius: 2px;
  transition: width 0.3s ease;
}
.rel-bar-trust { background: var(--cyan); }
.rel-bar-fam { background: var(--green); }
.rel-bar-aff { background: #f472b6; }
.rel-mood {
  font-size: 0.65rem;
  color: var(--fg-dim);
  margin-top: 0.15rem;
}

/* Skills panel */
.skill-category {
  color: var(--yellow);
  font-size: 0.75rem;
  font-weight: bold;
  padding: 0.4rem 0 0.15rem;
  border-bottom: 1px solid var(--border);
}
.skill-entry {
  padding: 0.2rem 0;
  font-size: 0.8rem;
}
.skill-name { color: var(--fg); }
.skill-rank { color: var(--cyan); font-size: 0.7rem; margin-left: 0.3rem; }
.skill-sub {
  padding-left: 0.8rem;
  font-size: 0.7rem;
  color: var(--fg-dim);
}

/* BG87-D — Interactive UI: clickable cast buttons in Skills panel +
   target-lock badge in the input bar. Pure accelerators over text
   commands; nothing exclusive to the UI. */
.bg87d-spells-section {
  margin-top: 0.5rem;
  border-top: 1px solid var(--border);
  padding-top: 0.3rem;
}
.bg87d-spell-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.15rem 0;
  font-size: 0.8rem;
  gap: 0.4rem;
}
.bg87d-spell-name {
  flex: 1;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bg87d-spell-mana {
  color: var(--cyan);
  font-size: 0.7rem;
}
.bg87d-cast-btn {
  background: var(--input-bg);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: inherit;
  font-size: 0.7rem;
  padding: 0.1rem 0.45rem;
  cursor: pointer;
  border-radius: 2px;
  flex-shrink: 0;
}
.bg87d-cast-btn:hover:not(:disabled) {
  background: var(--accent);
  color: var(--input-bg);
}
.bg87d-cast-btn:disabled,
.bg87d-cast-btn.bg87d-disabled {
  border-color: var(--fg-dim);
  color: var(--fg-dim);
  cursor: not-allowed;
  opacity: 0.55;
}
.bg87d-spells-empty {
  color: var(--fg-dim);
  font-size: 0.7rem;
  font-style: italic;
  padding: 0.2rem 0;
}

/* Target-lock badge in input form */
#target-lock-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-right: 0.4rem;
  padding: 0.1rem 0.35rem;
  background: rgba(233, 196, 106, 0.12);
  border: 1px solid var(--yellow, #e9c46a);
  color: var(--yellow, #e9c46a);
  font-size: 0.78rem;
  border-radius: 3px;
  white-space: nowrap;
  max-width: 30%;
  overflow: hidden;
  text-overflow: ellipsis;
}
#target-lock-badge.hidden { display: none; }
#target-lock-name::before {
  content: "\1F512 ";
  font-size: 0.7rem;
  margin-right: 0.15rem;
}
#target-lock-clear {
  background: none;
  border: none;
  color: var(--yellow, #e9c46a);
  font-size: 0.95rem;
  cursor: pointer;
  padding: 0 0.15rem;
  line-height: 1;
}
#target-lock-clear:hover {
  color: var(--accent);
}
/* Narrow viewport — drop the badge to keep input usable on phones */
@media (max-width: 600px) {
  #target-lock-badge {
    max-width: 40%;
    font-size: 0.7rem;
  }
}

/* Stronger lock indicator on the NPC entry (BG87-D — reuses focused
   class state but adds an extra ring when explicitly target-locked). */
.npc-entry.bg87d-locked .portrait {
  outline: 2px solid var(--yellow, #e9c46a);
  outline-offset: 1px;
}

/* Factions panel */
.faction-entry {
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.faction-name {
  font-weight: bold;
  color: var(--fg);
  font-size: 0.8rem;
}
.faction-rank {
  font-size: 0.7rem;
  margin-left: 0.3rem;
}
.faction-rank.hostile { color: var(--accent); }
.faction-rank.unfriendly { color: var(--yellow); }
.faction-rank.neutral { color: var(--fg-dim); }
.faction-rank.friendly { color: var(--green); }
.faction-rank.honored { color: var(--cyan); }
.faction-rank.exalted { color: #a78bfa; }
.faction-bar-wrap {
  height: 6px;
  background: var(--input-bg);
  border-radius: 3px;
  overflow: hidden;
  margin-top: 0.2rem;
  position: relative;
}
.faction-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease;
}
.faction-bar-center {
  position: absolute;
  left: 50%;
  top: 0;
  width: 1px;
  height: 100%;
  background: var(--fg-dim);
  opacity: 0.5;
}

/* Alignment panel */
#alignment-display {
  padding: 0.5rem;
}
.align-axis {
  margin-bottom: 0.8rem;
}
.align-label {
  font-size: 0.75rem;
  color: var(--fg-dim);
  margin-bottom: 0.2rem;
}
.align-value {
  font-size: 0.9rem;
  font-weight: bold;
}
.align-bar-wrap {
  height: 8px;
  background: var(--input-bg);
  border-radius: 4px;
  overflow: hidden;
  margin-top: 0.2rem;
  position: relative;
}
.align-bar-fill {
  position: absolute;
  height: 100%;
  border-radius: 4px;
  transition: width 0.3s ease, left 0.3s ease;
}
.align-bar-center {
  position: absolute;
  left: 50%;
  top: 0;
  width: 2px;
  height: 100%;
  background: var(--fg-dim);
  opacity: 0.5;
  transform: translateX(-1px);
}
.align-honor { background: var(--cyan); }
.align-virtue { background: var(--green); }
.align-quadrant {
  margin-top: 0.8rem;
  padding: 0.5rem;
  background: var(--bg3);
  border-radius: 4px;
  border: 1px solid var(--border);
  text-align: center;
}
.align-quadrant-name {
  color: var(--yellow);
  font-weight: bold;
  font-size: 0.85rem;
}
.align-quadrant-flavor {
  color: var(--fg-dim);
  font-size: 0.7rem;
  margin-top: 0.2rem;
}
.panel-empty {
  color: var(--fg-dim);
  font-size: 0.8rem;
  font-style: italic;
  text-align: center;
  padding: 1rem;
}

/* Crafting panel */
.craft-hint {
  color: var(--green);
  font-size: 0.7rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.craft-station-header {
  color: var(--yellow);
  font-size: 0.75rem;
  font-weight: bold;
  padding: 0.4rem 0 0.15rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.craft-station-header:hover { color: var(--fg); }
.craft-station-header.craft-here { color: var(--green); }
.craft-category {
  color: var(--fg-dim);
  font-size: 0.65rem;
  text-transform: uppercase;
  padding: 0.3rem 0 0.1rem;
  letter-spacing: 0.05em;
}
.craft-recipe {
  padding: 0.2rem 0.3rem;
  cursor: pointer;
  font-size: 0.72rem;
}
.craft-recipe:hover { background: var(--bg-hover); }
.craft-recipe.craft-available .craft-recipe-name { color: var(--fg); }
.craft-recipe-name { color: var(--fg-dim); }
.craft-yes { color: var(--green); }
.craft-no { color: var(--accent); }
.craft-detail {
  background: var(--bg-raised, #1a1a2e);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.4rem;
  margin: 0.2rem 0;
  font-size: 0.7rem;
}
.craft-detail-label {
  color: var(--fg-dim);
  margin-top: 0.3rem;
  font-size: 0.68rem;
}
.craft-ingredient {
  padding-left: 0.5rem;
  font-size: 0.68rem;
}
.craft-have { color: var(--green); }
.craft-need { color: var(--accent); }
.craft-detail-skill {
  color: var(--fg-dim);
  font-size: 0.65rem;
  margin-top: 0.2rem;
}
.craft-btn {
  margin-top: 0.3rem;
  padding: 0.2rem 0.6rem;
  background: var(--green);
  color: var(--bg);
  border: none;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.68rem;
  font-family: inherit;
}
.craft-btn:hover { opacity: 0.85; }
.craft-btn:disabled,
.craft-btn.craft-btn-disabled {
  background: var(--fg-dim);
  cursor: not-allowed;
  opacity: 0.5;
}

/* Crafting search */
.craft-search {
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.craft-search-input {
  width: 100%;
  padding: 0.25rem 0.4rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--fg);
  font-size: 0.7rem;
  font-family: inherit;
  box-sizing: border-box;
}
.craft-search-input::placeholder { color: var(--fg-dim); }
.craft-search-input:focus {
  outline: none;
  border-color: var(--yellow);
}

/* Shop tab */
.shop-closed {
  color: var(--accent);
  font-size: 0.75rem;
  padding: 0.5rem;
  text-align: center;
}
.shop-gold {
  color: var(--yellow);
  font-size: 0.8rem;
  font-weight: bold;
  padding: 0.3rem 0.4rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.2rem;
}
.shop-tab-bar {
  display: flex;
  gap: 2px;
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.shop-tab-toggle {
  flex: 1;
  padding: 0.25rem 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--fg-dim);
  font-size: 0.7rem;
  font-family: inherit;
  cursor: pointer;
}
.shop-tab-toggle.active {
  background: var(--accent2);
  color: var(--fg);
  border-color: var(--yellow);
}
.shop-tab-toggle:hover { color: var(--fg); }
.shop-vendor {
  margin-bottom: 0.4rem;
}
.shop-vendor-name {
  color: var(--yellow);
  font-size: 0.75rem;
  font-weight: bold;
  padding: 0.3rem 0 0.15rem;
  border-bottom: 1px solid var(--border);
}
.shop-item {
  display: flex;
  align-items: flex-start;
  padding: 0.2rem 0.3rem;
  font-size: 0.72rem;
  gap: 0.3rem;
}
.shop-item:hover { background: var(--bg-hover, rgba(255,255,255,0.03)); }
/* BU86 #3: was overflow:hidden + text-overflow:ellipsis + white-space:nowrap,
   clipping long item names to "..." with no way to read the rest. The right
   panel already scrolls vertically (#right-panel overflow-y:auto), so wrap
   the name instead of clipping it and let that existing scroll handle any
   extra height, rather than losing text. */
.shop-item-name {
  flex: 1;
  min-width: 0;
  overflow: visible;
  white-space: normal;
  word-break: break-word;
  line-height: 1.25;
}
.shop-item-price {
  color: var(--yellow);
  font-size: 0.68rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.shop-sell-price {
  color: var(--green);
}
.shop-buy-btn,
.shop-sell-btn {
  padding: 0.15rem 0.5rem;
  background: var(--green);
  color: var(--bg);
  border: none;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.65rem;
  font-family: inherit;
  white-space: nowrap;
  flex-shrink: 0;
}
.shop-sell-btn {
  background: var(--yellow);
}
.shop-buy-btn:hover,
.shop-sell-btn:hover { opacity: 0.85; }
.shop-btn-disabled,
.shop-buy-btn:disabled {
  background: var(--fg-dim);
  cursor: not-allowed;
  opacity: 0.5;
}
.shop-category {
  color: var(--fg-dim);
  font-size: 0.65rem;
  text-transform: uppercase;
  padding: 0.3rem 0 0.1rem;
  letter-spacing: 0.05em;
  border-bottom: 1px solid var(--border);
}
.shop-empty {
  color: var(--fg-dim);
  font-size: 0.72rem;
  padding: 0.5rem;
  text-align: center;
}
/* Rarity colors for shop items */
.rarity-common { color: var(--fg); }
.rarity-uncommon { color: var(--green); }
.rarity-rare { color: #60a5fa; }
.rarity-epic { color: #a78bfa; }
.rarity-legendary { color: var(--yellow); }

/* Settings panel */
#settings-btn {
  background: transparent;
  border: none;
  color: var(--fg-dim);
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0 0.3rem;
  margin-left: auto;
}
#settings-btn:hover { color: var(--fg); }
#settings-panel {
  padding: 0.3rem;
}
.settings-section {
  margin-bottom: 0.8rem;
}
.settings-header {
  color: var(--yellow);
  font-size: 0.75rem;
  font-weight: bold;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.settings-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.25rem 0;
  font-size: 0.72rem;
  color: var(--fg);
  cursor: pointer;
}
.settings-row span { color: var(--fg-dim); }
.settings-value { color: var(--fg) !important; }
.settings-row select {
  background: var(--input-bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 3px;
  font-size: 0.68rem;
  font-family: inherit;
  padding: 0.1rem 0.3rem;
}
.settings-row input[type="checkbox"] {
  accent-color: var(--accent);
}
.settings-form {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 0.4rem;
}
.settings-form input {
  background: var(--input-bg);
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 0.3rem 0.4rem;
  border-radius: 3px;
  font-size: 0.68rem;
  font-family: inherit;
}
.settings-form button {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 3px;
  padding: 0.3rem;
  cursor: pointer;
  font-size: 0.68rem;
  font-family: inherit;
}
.settings-form button:hover { opacity: 0.85; }
.settings-status {
  font-size: 0.65rem;
  min-height: 1em;
}
.settings-status.ok { color: var(--green); }
.settings-status.err { color: var(--accent); }

/* PIN modal */
#pin-modal {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.75);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
}

/* Lightbox */
#lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.85);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 100;
  cursor: pointer;
}
#lightbox-img {
  max-width: 90vw;
  max-height: 85vh;
  border-radius: 8px;
}
#lightbox-label {
  color: #fff;
  font-size: 1.1rem;
  margin-top: 0.5rem;
  text-align: center;
  text-shadow: 0 1px 4px rgba(0,0,0,0.7);
}

/* Mobile */
@media (max-width: 700px) {
  #layout { flex-direction: column; }
  #sidebar {
    width: 100% !important;
    min-width: 100%;
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    max-height: 120px;
    border-right: none;
    border-bottom: 1px solid var(--border);
    gap: 0.3rem;
    padding: 0.3rem;
  }
  #location-name { display: none; }
  #location-bg-wrap { display: none; }
  .portrait { width: 80px; height: 80px; object-fit: cover; }
  #player-portrait-wrap { flex-shrink: 0; }
  .npc-entry { flex-shrink: 0; }
  #output { font-size: 13px; }
  .resize-handle { display: none; }
  #right-panel {
    width: 100% !important;
    min-width: 100%;
    max-height: 200px;
    border-left: none;
    border-top: 1px solid var(--border);
  }
}

/* Scrollbar */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* Prevent text selection while resizing */
body.resizing {
  user-select: none;
  cursor: col-resize;
}

/* Right panel footer — wiki link */
#right-panel-footer {
  margin-top: auto;
  padding: 6px 10px;
  border-top: 1px solid var(--border);
  text-align: center;
  flex-shrink: 0;
  display: flex;
  justify-content: center;
  gap: 8px;
  /* Wrap to a second row when the panel is narrowed instead of clipping the
     icons off the edge (they used to vanish on resize). */
  flex-wrap: wrap;
  row-gap: 4px;
}
#right-panel-footer a,
#right-panel-footer button {
  color: var(--dim);
  text-decoration: none;
  font-size: 0.85em;
  opacity: 0.7;
  transition: opacity 0.2s;
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 6px;
  font-family: inherit;
}
#right-panel-footer a:hover,
#right-panel-footer button:hover {
  opacity: 1;
  color: var(--cyan, #5af);
}

/* QW110: music + sound-effects mute toggles in the footer. */
.footer-audio {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}
#right-panel-footer .audio-toggle {
  position: relative;
  font-size: 1em;
  padding: 2px 4px;
  line-height: 1;
}
/* The music-note glyph reads smaller than the speaker emoji — bump it up to
   match the speaker's visual weight. */
#right-panel-footer #footer-music {
  font-size: 1.3em;
}
/* Red strike-through diagonal when that channel is muted. */
#right-panel-footer .audio-toggle.audio-off::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 130%;
  height: 2px;
  background: var(--red, #e44);
  transform: translate(-50%, -50%) rotate(-45deg);
  border-radius: 2px;
  pointer-events: none;
}
#right-panel-footer .audio-toggle.audio-off { opacity: 0.55; }

/* --- Quest panel --- */
#quests-list {
  padding: 0.3rem;
}
.quest-entry {
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.quest-title {
  font-weight: bold;
  color: var(--fg);
  font-size: 0.8rem;
}
.quest-type {
  font-size: 0.65rem;
  color: var(--fg-dim);
  margin-left: 0.3rem;
  text-transform: uppercase;
}
.quest-progress {
  font-size: 0.65rem;
  color: var(--cyan);
  margin-left: 0.3rem;
}
.quest-hint {
  font-size: 0.7rem;
  color: var(--fg-dim);
  margin-top: 0.2rem;
  line-height: 1.3;
  max-height: 3.9em;
  overflow: hidden;
}
.quest-obj {
  font-size: 0.68rem;
  padding-left: 0.5rem;
  margin-top: 0.1rem;
}
.quest-obj.done {
  color: var(--green);
}
.quest-obj.pending {
  color: var(--fg-dim);
}

/* --- Combat panel (redesigned S147) --- */
#combat-panel {
  padding: 10px;
  font-size: 0.85em;
}

/* Vitals block — HP/Fatigue/Mana */
.cm-vitals {
  margin-bottom: 8px;
}
.combat-vitals-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 4px;
}
.combat-vitals-label {
  width: 28px;
  font-size: 0.75em;
  color: var(--fg-dim);
  text-align: right;
  flex-shrink: 0;
}
.combat-vitals-num {
  font-size: 0.72em;
  color: var(--fg-dim);
  width: 50px;
  text-align: right;
  flex-shrink: 0;
}
.cm-equip-line {
  font-size: 0.7em;
  color: var(--fg-dim);
  margin-top: 2px;
  opacity: 0.7;
}

/* Combat bars */
.combat-bar-wrap {
  flex: 1;
  height: 10px;
  background: var(--input-bg);
  border-radius: 5px;
  overflow: hidden;
}
.combat-bar-fill {
  height: 100%;
  border-radius: 5px;
  transition: width 0.3s ease;
}
.combat-bar-fill.hp-high { background: var(--green); }
.combat-bar-fill.hp-mid { background: var(--yellow); }
.combat-bar-fill.hp-low { background: var(--accent); }
.combat-bar-fill.fatigue-fill { background: #f59e0b; }
.combat-bar-fill.mana-fill { background: #6366f1; }

/* Condition badges */
.combat-conditions {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-bottom: 6px;
}
.combat-condition-badge {
  font-size: 0.65em;
  padding: 1px 5px;
  border-radius: 3px;
  font-weight: bold;
}
.condition-wound {
  background: rgba(239, 68, 68, 0.2);
  color: #ef4444;
  border: 1px solid rgba(239, 68, 68, 0.4);
}
.condition-buff {
  background: rgba(74, 222, 128, 0.2);
  color: var(--green);
  border: 1px solid rgba(74, 222, 128, 0.4);
}
/* Fights lane K: a held stun or root, with its rounds left. */
.condition-control {
  background: rgba(250, 204, 21, 0.2);
  color: #facc15;
  border: 1px solid rgba(250, 204, 21, 0.4);
}
.cm-hostile-conds {
  margin: 2px 0 0 0;
}

/* Target block */
.cm-target {
  background: rgba(239, 68, 68, 0.06);
  border: 1px solid rgba(239, 68, 68, 0.25);
  border-radius: 6px;
  padding: 8px;
  margin-bottom: 8px;
}
.cm-target-name {
  font-weight: bold;
  color: var(--accent);
  margin-bottom: 4px;
  font-size: 0.95em;
}
.cm-target-conds {
  margin-top: 4px;
  margin-bottom: 0;
}

/* Section divider + title */
.combat-divider {
  height: 1px;
  background: var(--border);
  margin: 6px 0 4px;
}
.combat-section-title {
  font-size: 0.7em;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-dim);
  margin-bottom: 5px;
}

/* Section container */
.cm-section {
  margin-bottom: 4px;
}
.cm-sublabel {
  font-size: 0.7em;
  color: var(--fg-dim);
  margin: 4px 0 2px;
}

/* Button grid — flexible, wrapping */
.cm-btn-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

/* Base button */
.cm-btn {
  background: var(--bg2);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 5px 10px;
  cursor: pointer;
  font-size: 0.8em;
  font-family: inherit;
  transition: all 0.15s ease;
}
.cm-btn:hover {
  background: #2a2a4e;
  border-color: var(--fg-dim);
}

/* Attack buttons — red, prominent */
.cm-btn-attack {
  background: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.5);
  color: #f87171;
  font-weight: bold;
}
.cm-btn-attack:hover {
  background: rgba(239, 68, 68, 0.3);
  border-color: #ef4444;
  color: #fca5a5;
}

/* Aim buttons — amber */
.cm-btn-aim {
  background: rgba(250, 204, 21, 0.08);
  border-color: rgba(250, 204, 21, 0.4);
  color: var(--yellow);
  font-size: 0.75em;
}
.cm-btn-aim:hover {
  background: rgba(250, 204, 21, 0.2);
  border-color: var(--yellow);
}

/* Stance buttons — cyan accent when active */
.cm-btn-stance {
  font-size: 0.75em;
  padding: 3px 8px;
}
.cm-btn-stance.active {
  border-color: var(--cyan);
  color: var(--cyan);
  background: rgba(34, 211, 238, 0.1);
}

/* Defense buttons — muted blue */
.cm-btn-defense {
  background: rgba(99, 102, 241, 0.08);
  border-color: rgba(99, 102, 241, 0.4);
  color: #a5b4fc;
}
.cm-btn-defense:hover {
  background: rgba(99, 102, 241, 0.2);
  border-color: #6366f1;
}

/* Spell buttons — purple */
.cm-btn-spell {
  background: rgba(168, 85, 247, 0.1);
  border-color: rgba(168, 85, 247, 0.4);
  color: #c084fc;
}
.cm-btn-spell:hover {
  background: rgba(168, 85, 247, 0.25);
  border-color: #a855f7;
}
.cm-btn-disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Item buttons — teal */
.cm-btn-item {
  background: rgba(20, 184, 166, 0.08);
  border-color: rgba(20, 184, 166, 0.4);
  color: #5eead4;
  font-size: 0.75em;
}
.cm-btn-item:hover {
  background: rgba(20, 184, 166, 0.2);
  border-color: #14b8a6;
}

/* Enemy rows */
.cm-hostile {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 5px;
}
.cm-attack-btn {
  background: rgba(239, 68, 68, 0.15);
  border: 1px solid rgba(239, 68, 68, 0.5);
  color: #f87171;
  border-radius: 4px;
  padding: 5px 10px;
  cursor: pointer;
  font-size: 0.8em;
  font-family: inherit;
  font-weight: bold;
  white-space: nowrap;
  transition: all 0.15s ease;
}
.cm-attack-btn:hover {
  background: rgba(239, 68, 68, 0.35);
  border-color: #ef4444;
}
.cm-attack-btn.cm-current-target {
  border-color: #ef4444;
  box-shadow: 0 0 6px rgba(239, 68, 68, 0.3);
}
.cm-hostile-bar {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 4px;
}
.cm-hostile-hp {
  font-size: 0.7em;
  color: var(--fg-dim);
  white-space: nowrap;
}

/* Flee button — wide, distinct */
.cm-flee-btn {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 6px;
  background: rgba(250, 204, 21, 0.08);
  border: 1px solid rgba(250, 204, 21, 0.35);
  border-radius: 4px;
  color: var(--yellow);
  font-family: inherit;
  font-size: 0.8em;
  cursor: pointer;
  transition: all 0.15s ease;
}
.cm-flee-btn:hover {
  background: rgba(250, 204, 21, 0.2);
  border-color: var(--yellow);
}

/* --- Combat mode visual treatment --- */
#right-panel.combat-mode {
  border-left: 2px solid rgba(239, 68, 68, 0.6);
  box-shadow: inset 0 0 30px rgba(239, 68, 68, 0.06);
  background: linear-gradient(180deg, rgba(20, 10, 15, 0.4) 0%, transparent 30%);
}

/* Hide non-combat tabs */
.cm-tab-hidden {
  display: none !important;
}

/* Combat tab button glow when in combat */
body.in-combat .tab-btn[data-tab="combat"] {
  color: var(--accent);
  animation: combat-glow 2s ease-in-out infinite;
}
@keyframes combat-glow {
  0%, 100% { text-shadow: 0 0 4px rgba(233, 69, 96, 0.3); }
  50% { text-shadow: 0 0 12px rgba(233, 69, 96, 0.8); }
}

/* Pulse the prompt during combat */
body.in-combat #prompt-label {
  color: var(--accent);
}

/* De-emphasize non-combat hints during combat */
body.in-combat #status-bar {
  opacity: 0.4;
}

/* === Collapsible combat groups === */
.cm-group-header {
  font-size: 0.8em;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg);
  padding: 6px 4px;
  cursor: pointer;
  user-select: none;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  transition: color 0.15s;
}
.cm-group-header:hover {
  color: var(--cyan);
}
.cm-group-arrow {
  display: inline-block;
  width: 12px;
  font-size: 0.9em;
}
.cm-group-body {
  padding: 2px 0;
}

/* Distance buttons — orange/warm */
.cm-btn-distance {
  background: rgba(251, 146, 60, 0.08);
  border-color: rgba(251, 146, 60, 0.4);
  color: #fb923c;
  font-size: 0.75em;
}
.cm-btn-distance:hover {
  background: rgba(251, 146, 60, 0.2);
  border-color: #fb923c;
}

/* Distance badge on target block */
.cm-distance-badge {
  display: inline-block;
  font-size: 0.65em;
  color: #fb923c;
  background: rgba(251, 146, 60, 0.1);
  border: 1px solid rgba(251, 146, 60, 0.3);
  padding: 1px 6px;
  border-radius: 3px;
  margin-top: 4px;
}

/* Targeting hint — shown when hostiles present but no target */
.cm-targeting-hint {
  background: rgba(250, 204, 21, 0.06);
  border: 1px dashed rgba(250, 204, 21, 0.3);
  border-radius: 6px;
  padding: 8px 10px;
  margin-bottom: 8px;
  font-size: 0.78em;
  color: var(--yellow);
  line-height: 1.4;
}
.cm-targeting-hint code {
  background: rgba(250, 204, 21, 0.12);
  padding: 1px 4px;
  border-radius: 3px;
  font-family: inherit;
}
.cm-hint-icon {
  font-size: 1.1em;
}

/* === Combat text in output — make it POP === */

/* Hits — bigger and red-tinted */
#output .combat-hit {
  color: #f87171;
  font-size: 1.05em;
  font-weight: bold;
  text-shadow: 0 0 8px rgba(239, 68, 68, 0.15);
}

/* Critical hits — FLASHY */
#output .combat-crit {
  color: #fbbf24;
  font-size: 1.15em;
  font-weight: bold;
  text-shadow: 0 0 12px rgba(251, 191, 36, 0.4), 0 0 4px rgba(239, 68, 68, 0.3);
  animation: crit-flash 0.6s ease-out;
}
@keyframes crit-flash {
  0% { background: rgba(251, 191, 36, 0.2); }
  100% { background: transparent; }
}

/* Kills / KO — dramatic red */
#output .combat-kill {
  color: #ef4444;
  font-size: 1.1em;
  font-weight: bold;
  text-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
  animation: kill-pulse 0.8s ease-out;
}
@keyframes kill-pulse {
  0% { background: rgba(239, 68, 68, 0.15); transform: scale(1.01); }
  100% { background: transparent; transform: scale(1); }
}

/* Dodges/blocks/parries — cool blue/green */
#output .combat-dodge {
  color: #67e8f9;
  font-weight: bold;
}

/* Misses — dimmer */
#output .combat-miss {
  color: var(--fg-dim);
  font-style: italic;
}

/* Combat summary — boxed and distinct */
#output .combat-summary {
  color: var(--cyan);
  border-left: 3px solid var(--cyan);
  padding-left: 8px;
  margin: 4px 0;
}

/* Faded variants for combat text — mute toward --fg-dim at full opacity
   (readable) instead of fading toward transparent (too dark when scrolled up). */
#output > .faded.combat-hit { color: color-mix(in srgb, #f87171 50%, var(--fg-dim)); }
#output > .faded.combat-crit { color: color-mix(in srgb, #fbbf24 50%, var(--fg-dim)); }
#output > .faded.combat-kill { color: color-mix(in srgb, #ef4444 50%, var(--fg-dim)); }
#output > .faded.combat-dodge { color: color-mix(in srgb, #67e8f9 50%, var(--fg-dim)); }
#output > .faded.combat-miss { color: var(--fg-dim); opacity: 0.75; }
#output > .faded.combat-summary { color: color-mix(in srgb, var(--cyan) 50%, var(--fg-dim)); }

/* --- Class actions panel (sidebar) --- */
#class-actions-panel:empty { display: none; }
.class-actions-header {
  color: var(--yellow);
  font-size: 0.7rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.4rem 0.3rem 0.2rem;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
}
/* IT42 — customize-buttons toggle + editor panel */
.class-actions-customize-btn {
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 5px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.62rem;
  line-height: 1.4;
  text-transform: none;
  letter-spacing: 0;
}
.class-actions-customize-btn:hover {
  color: var(--fg);
  border-color: var(--fg-dim);
}
.class-customize-help {
  font-size: 0.6rem;
  color: var(--fg-dim);
  padding: 0.2rem 0.3rem 0.3rem;
  font-style: italic;
}
.class-customize-group {
  margin-bottom: 0.3rem;
}
.class-customize-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 1px 0.3rem;
  font-size: 0.66rem;
  color: var(--fg);
}
.class-customize-cb {
  margin: 0;
  cursor: pointer;
}
.class-customize-row-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.class-customize-controls {
  display: flex;
  gap: 2px;
}
.class-customize-move {
  background: var(--accent2);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0 3px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.55rem;
  line-height: 1.3;
}
.class-customize-move:hover:not(:disabled) {
  background: #1a4a80;
  border-color: var(--fg-dim);
}
.class-customize-move:disabled {
  opacity: 0.3;
  cursor: default;
}
.class-customize-reset {
  margin: 0.3rem 0.3rem 0.2rem;
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 2px 8px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.62rem;
}
.class-customize-reset:hover {
  color: var(--fg);
  border-color: var(--fg-dim);
}
.class-action-group {
  margin-bottom: 0.3rem;
}
.class-action-group-label {
  font-size: 0.65rem;
  color: var(--fg-dim);
  padding: 0.2rem 0.3rem;
  cursor: pointer;
  user-select: none;
}
.class-action-group-label:hover { color: var(--fg); }
.class-action-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 0 0.3rem 0.2rem;
}
.class-action-btn {
  background: var(--accent2);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 3px 6px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.68rem;
  display: flex;
  align-items: center;
  gap: 3px;
  transition: background 0.15s, border-color 0.15s;
}
.class-action-btn:hover {
  background: #1a4a80;
  border-color: var(--fg-dim);
}
.class-action-icon {
  font-size: 0.8rem;
}
.class-action-name {
  white-space: nowrap;
}

/* ====== Event Modal (conversations, confrontations, story choices) ====== */
/* --- Event Modal (conversations, confrontations, story choices) --- */
.event-overlay {
  display: none;
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 1000;
}
.event-modal {
  display: none;
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(0.95);
  opacity: 0;
  background: var(--bg2);
  border: 2px solid #4a4a6a;
  border-radius: 14px;
  padding: 28px;
  max-width: 720px;
  width: 92%;
  max-height: 85vh;
  overflow-y: auto;
  z-index: 1001;
  color: var(--fg);
  font-family: inherit;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255,255,255,0.04);
  flex-direction: column;
  gap: 14px;
  transition: transform 0.2s ease-out, opacity 0.2s ease-out;
}
.event-modal.event-modal-open {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}

/* --- Dual portrait layout --- */
.event-portraits {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 32px;
  margin-bottom: 8px;
}
.event-portrait-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.event-portrait {
  width: 180px;
  height: 180px;
  border-radius: 12px;
  border: 3px solid #4a4a6a;
  object-fit: cover;
  image-rendering: auto;
  flex-shrink: 0;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.55);
}
.event-npc-side .event-portrait {
  border-color: #cc6600;
  width: 200px;
  height: 200px;
}
.event-player-side .event-portrait {
  border-color: #4a8acc;
  /* Match NPC tile size — both portraits should be the same dimensions
     in the conversation modal; the orange-vs-blue border keeps them
     distinguishable. User-flagged 2026-05-28. */
  width: 200px;
  height: 200px;
}
.event-portrait-name {
  font-size: 0.85em;
  color: var(--fg-dim);
  text-align: center;
  white-space: nowrap;
}
.event-npc-name {
  font-size: 1.15em;
  font-weight: bold;
  color: #ffb300;
}
.event-player-label {
  color: #6aafdd;
}

/* --- NPC disposition dot --- */
.event-disposition-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-left: 6px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}
.event-disposition-dot.disposition-friendly {
  background: #4ade80;
  box-shadow: 0 0 6px rgba(74, 222, 128, 0.5);
}
.event-disposition-dot.disposition-neutral {
  background: #ffb300;
  box-shadow: 0 0 6px rgba(255, 179, 0, 0.4);
}
.event-disposition-dot.disposition-hostile {
  background: #ef4444;
  box-shadow: 0 0 6px rgba(239, 68, 68, 0.5);
}

/* --- Title and description --- */
.event-title {
  font-size: 0.95em;
  color: var(--fg-dim);
  font-style: italic;
  text-align: center;
  margin-bottom: 2px;
}
.event-description {
  line-height: 1.65;
  color: #d0d0d0;
  font-size: 0.95em;
  white-space: pre-wrap;
}
.event-separator {
  border: none;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  margin: 4px 0;
}

/* --- Conversation log --- */
.event-conv-log {
  display: none;
  max-height: 320px;
  overflow-y: auto;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 0.9em;
  line-height: 1.5;
  scroll-behavior: smooth;
}
.event-log-entry {
  padding: 4px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.event-log-entry:last-child {
  border-bottom: none;
}
.event-log-line {
  color: #b0b8c8;
  white-space: pre-wrap;
}

/* --- Text input bar --- */
.event-input-bar {
  display: none;
  padding: 0;
}
.event-input {
  width: 100%;
  padding: 10px 14px;
  background: var(--bg3);
  border: 1px solid #4a4a6a;
  border-radius: 6px;
  color: var(--fg);
  font-family: inherit;
  font-size: 0.95em;
  outline: none;
  transition: border-color 0.15s;
}
.event-input:focus {
  border-color: #6a8acc;
  box-shadow: 0 0 0 2px rgba(106, 138, 204, 0.2);
}
.event-input::placeholder {
  color: var(--fg-dim);
  opacity: 0.6;
}

/* --- TALK-P0: busy state + backpressure --- */
/* Busy shimmer ("<name> considers your words...") shown while the NPC is
   thinking (a say/ask is being voiced by the narrator). */
.event-busy-shimmer {
  display: none;
  margin: 6px 0 2px;
  padding: 6px 10px;
  font-size: 0.9em;
  font-style: italic;
  color: var(--fg-dim);
  border-left: 2px solid #6a8acc;
  background: linear-gradient(
    90deg,
    rgba(106, 138, 204, 0.06) 0%,
    rgba(106, 138, 204, 0.16) 50%,
    rgba(106, 138, 204, 0.06) 100%
  );
  background-size: 200% 100%;
  animation: event-busy-pulse 1.4s ease-in-out infinite;
}
@keyframes event-busy-pulse {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .event-busy-shimmer { animation: none; }
}
/* While busy, the whole modal reads as locked. */
.event-modal.event-modal-busy .event-choices,
.event-modal.event-modal-busy .event-input-bar {
  opacity: 0.55;
}
.event-choice-btn.event-choice-locked {
  cursor: wait;
  opacity: 0.5;
}
/* Backpressure badge on the input bar ("N queued"). */
.event-queue-badge {
  display: none;
  align-self: center;
  margin-left: 8px;
  padding: 2px 8px;
  font-size: 0.78em;
  color: #ffb300;
  border: 1px solid rgba(255, 179, 0, 0.5);
  border-radius: 10px;
  white-space: nowrap;
}

/* --- Choice buttons (2-column grid) --- */
.event-choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}
.event-choice-btn {
  background: var(--bg3);
  border: 1px solid #4a4a6a;
  border-left: 3px solid #4a4a6a;
  border-radius: 6px;
  padding: 8px 10px;
  color: var(--fg);
  font-size: 0.88em;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.event-choice-btn:hover:not(:disabled) {
  background: #2a3a5a;
  border-color: #6a6a8a;
  transform: translateX(2px);
}
.event-choice-btn:active:not(:disabled) {
  background: #3a4a6a;
  transform: translateX(0);
}
.event-choice-btn.disabled {
  opacity: 0.4;
  cursor: not-allowed;
  font-style: italic;
}

/* Skill check difficulty color-coding */
.event-choice-btn.difficulty-easy {
  border-left-color: #4ade80;
}
.event-choice-btn.difficulty-easy:hover:not(:disabled) {
  border-left-color: #4ade80;
  background: rgba(74, 222, 128, 0.08);
}
.event-choice-btn.difficulty-medium {
  border-left-color: #ffb300;
}
.event-choice-btn.difficulty-medium:hover:not(:disabled) {
  border-left-color: #ffb300;
  background: rgba(255, 179, 0, 0.08);
}
.event-choice-btn.difficulty-hard {
  border-left-color: #ef4444;
}
.event-choice-btn.difficulty-hard:hover:not(:disabled) {
  border-left-color: #ef4444;
  background: rgba(239, 68, 68, 0.08);
}

/* Structured button content */
.event-choice-content {
  display: flex;
  align-items: center;
  gap: 10px;
}
.event-choice-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
  font-size: 0.85em;
  font-weight: bold;
  color: var(--fg-dim);
  flex-shrink: 0;
}
.event-choice-label {
  flex: 1;
}
.event-choice-check {
  font-size: 0.82em;
  color: var(--fg-dim);
  white-space: nowrap;
  opacity: 0.8;
}
.difficulty-easy .event-choice-check { color: #4ade80; }
.difficulty-medium .event-choice-check { color: #ffb300; }
.difficulty-hard .event-choice-check { color: #ef4444; }

/* --- Leave button (footer, less prominent) --- */
.event-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 4px;
}
.event-leave-btn {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  padding: 6px 20px;
  color: var(--fg-dim);
  font-size: 0.82em;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.event-leave-btn:hover {
  background: rgba(255, 255, 255, 0.05);
  color: var(--fg);
}
/* --- Also-here line (bottom of modal) --- */
.event-also-here {
  font-size: 0.8em;
  color: var(--fg-dim);
  opacity: 0.7;
  text-align: center;
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

/* ------------------------------------------------------------------
   Bestiary tab (B1+B2+B3) — second diegetic-UI context, built on the
   Atlas-tab chassis. Cards in category sections; undiscovered show
   silhouette + ???. Detail dialog uses native <dialog>.
   ------------------------------------------------------------------ */

#tab-bestiary {
  padding: 8px;
  overflow-y: auto;
}

#bestiary-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

#bestiary-progress {
  font-size: 0.85em;
  color: var(--fg-dim);
  letter-spacing: 0.02em;
}

#bestiary-grid {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.bestiary-section {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.bestiary-cat-heading {
  margin: 0;
  font-size: 0.85em;
  font-weight: 600;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  padding-bottom: 3px;
}

.bestiary-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
  gap: 6px;
}

.bestiary-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 4px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 4px;
  cursor: pointer;
  text-align: center;
  font: inherit;
  color: inherit;
  transition: background 0.12s, border-color 0.12s;
}

.bestiary-card:hover,
.bestiary-card:focus-visible {
  background: rgba(255, 255, 255, 0.07);
  border-color: rgba(255, 255, 255, 0.18);
  outline: none;
}

.bestiary-card-icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.bestiary-card-silhouette {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Discovered cards show silhouette at full opacity (since for now we
     don't have per-creature portrait art). When per-creature art lands
     in B5+, swap the src on discovered cards instead. */
}

.bestiary-card.undiscovered .bestiary-card-silhouette {
  opacity: 0.55;
  filter: grayscale(1);
}

.bestiary-card.undiscovered .bestiary-card-name {
  color: var(--fg-dim);
  font-style: italic;
}

.bestiary-card-name {
  font-size: 0.78em;
  line-height: 1.15;
  word-break: break-word;
}

.bestiary-card-kills {
  font-size: 0.7em;
  color: var(--fg-dim);
  background: rgba(255, 255, 255, 0.04);
  padding: 1px 5px;
  border-radius: 8px;
}

/* --- Detail dialog (B3) ---
   Native <dialog> with .show() (decorate non-modal). Stays visible
   over the right panel; backdrop click or Esc closes. */
.bestiary-modal {
  position: fixed;
  inset: auto;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 480px;
  width: calc(100vw - 32px);
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  background: var(--bg, #0f0f12);
  color: var(--fg, #e3e3e3);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 6px;
  padding: 16px 18px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
}

.bestiary-modal:not([open]) {
  display: none;
}

#bestiary-detail-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.bestiary-detail-header,
.bestiary-detail-loading {
  display: flex;
  gap: 12px;
  align-items: center;
}

.bestiary-detail-icon-wrap,
.bestiary-detail-loading .bestiary-detail-icon {
  width: 72px;
  height: 72px;
  flex: 0 0 72px;
}

.bestiary-detail-icon {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.bestiary-detail-meta h2 {
  margin: 0 0 2px;
  font-size: 1.15em;
}

.bestiary-detail-cat,
.bestiary-detail-kills {
  margin: 0;
  font-size: 0.82em;
  color: var(--fg-dim);
}

.bestiary-detail-desc {
  margin: 0;
  font-style: italic;
  color: var(--fg-dim);
  line-height: 1.4;
}

.bestiary-detail-attrs {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 12px;
  margin: 0;
}

.bestiary-detail-attrs dt {
  color: var(--fg-dim);
  font-size: 0.82em;
}

.bestiary-detail-attrs dd {
  margin: 0;
  font-size: 0.9em;
}

.bestiary-detail-stats {
  margin: 0;
  font-family: ui-monospace, monospace;
  font-size: 0.85em;
  color: var(--fg-dim);
}

.bestiary-detail-abilities {
  margin: 0;
  padding-left: 18px;
  font-size: 0.88em;
}

.bestiary-detail-unseen,
.bestiary-detail-error {
  margin: 0;
  color: var(--fg-dim);
  font-style: italic;
  text-align: center;
  padding: 8px 4px;
}

/* ---- HOVER-1 (2026-05-27) — item-ref + tooltip styling ---- */

/* Inline item references — subtle underline + help cursor so the player
 * knows the name is interrogable without making narrator prose loud.
 * The dotted underline reads as "more info available" across most
 * Western typography conventions and stays out of the way during
 * normal reading. */
.item-ref {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--fg-dim);
  text-underline-offset: 2px;
  cursor: help;
  /* Don't recolor the underlying text — let narrator prose / shop
   * lists keep their own color (rarity-* spans, dim spans, etc). */
}
.item-ref:hover {
  text-decoration-color: var(--yellow);
  background: rgba(250, 204, 21, 0.06);
  border-radius: 2px;
}

/* The card itself — absolute-positioned overlay, fixed by JS. Uses the
 * same palette as combat-vitals + shop panels for visual consistency. */
.item-tooltip {
  position: fixed;
  z-index: 9999;
  min-width: 220px;
  max-width: 360px;
  padding: 10px 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-top: 3px solid var(--fg-dim);  /* default; rarity-* overrides */
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.55);
  font-size: 0.78rem;
  line-height: 1.35;
  pointer-events: auto;
}
.item-tooltip.hidden { display: none; }

/* Rarity-colored top border. Palette matches the existing rarity-*
 * text colors below + the legendary gold used elsewhere in style.css. */
.item-tooltip.rarity-common    { border-top-color: #888; }
.item-tooltip.rarity-uncommon  { border-top-color: #4a8; }
.item-tooltip.rarity-rare      { border-top-color: #60a5fa; }
.item-tooltip.rarity-epic      { border-top-color: #a78bfa; }
.item-tooltip.rarity-legendary { border-top-color: #caa040; }

.item-tooltip-name {
  font-size: 0.92rem;
  font-weight: bold;
  margin-bottom: 4px;
}
/* IT47: faint hint on the quick-hover chip that resting expands to the full card. */
.item-tooltip-mini-hint {
  color: var(--fg-dim);
  font-size: 0.6rem;
  font-style: italic;
  opacity: 0.6;
  margin-top: -2px;
}
.item-tooltip-sub {
  color: var(--fg-dim);
  font-size: 0.72rem;
  text-transform: lowercase;
  margin-bottom: 4px;
  letter-spacing: 0.02em;
}
.item-tooltip-desc {
  color: var(--fg);
  font-style: italic;
  margin-bottom: 6px;
  opacity: 0.85;
}
.item-tooltip-stats {
  color: var(--yellow);
  font-size: 0.78rem;
  margin-bottom: 4px;
}
.item-tooltip-effect {
  color: #6cf;
  font-size: 0.76rem;
  margin-bottom: 4px;
}
.item-tooltip-meta {
  display: flex;
  gap: 0.6em;
  margin-top: 6px;
  font-size: 0.72rem;
  color: var(--fg-dim);
  border-top: 1px dashed var(--border);
  padding-top: 5px;
}
.item-tooltip-price { color: var(--yellow); }
.item-tooltip-weight { color: var(--fg-dim); }
.item-tooltip-rarity { text-transform: uppercase; letter-spacing: 0.05em; }
.item-tooltip-tags {
  margin-top: 5px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.item-tooltip-tag {
  font-size: 0.66rem;
  background: rgba(255, 255, 255, 0.05);
  color: var(--fg-dim);
  padding: 1px 5px;
  border-radius: 3px;
}
.item-tooltip-sold {
  margin-top: 5px;
  font-size: 0.72rem;
  color: var(--fg-dim);
  border-top: 1px dashed var(--border);
  padding-top: 5px;
}
.item-tooltip-illicit  { color: var(--yellow); }
.item-tooltip-faction  { color: var(--yellow); }
.item-tooltip-locked   { color: #c66; }

/* Music mute toggle (procedural ambient — IT34 MVP) */
/* Landing "Next track" audition control (music MVP) */
.welcome-music {
  margin-top: 0.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}
.welcome-music-btn {
  background: rgba(20, 16, 12, 0.5);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 0.85rem;
  padding: 0.3rem 0.7rem;
  cursor: pointer;
  opacity: 0.8;
}
.welcome-music-btn:hover { opacity: 1; color: var(--fg); }
/* Muted-channel indication on the splash/welcome audio buttons. The JS already
   toggles `.audio-off` on these (welcome-sfx / welcome-music-toggle), but the
   red strike-through styling was scoped to the footer toggles only — so the
   splash buttons worked silently with no on/off cue. Mirror the footer look. */
.welcome-music-btn.audio-toggle { position: relative; }
.welcome-music-btn.audio-toggle.audio-off {
  opacity: 0.5;
  color: var(--fg-dim);
}
.welcome-music-btn.audio-toggle.audio-off::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 130%;
  height: 2px;
  background: var(--red, #e44);
  transform: translate(-50%, -50%) rotate(-45deg);
  border-radius: 2px;
  pointer-events: none;
}
.welcome-now-playing {
  color: var(--fg-dim);
  font-size: 0.8rem;
  font-style: italic;
  text-transform: capitalize;
}

/* ===================================================================
   IT413 - Dream-intro visual treatment.

   The dream tutorial is the FIRST screen a new player sees, so make it read as
   a dream: a soft haze glow over the text that LIFTS the instant they wake (the
   `in-dream` body class is removed on wake, so the real world snaps back crisp
   with zero extra work). Stage-direction lines (the [...] camera voice) sit
   apart in warm italic sepia; command words (rendered as bold-cyan spans by the
   **..** colorizer) become bordered KEYCAP chips so "this is a thing you type"
   reads instantly. All scoped to `body.in-dream #output`, so it is inert in the
   waking world.
   =================================================================== */

/* The killer detail: a soft warm haze over all dream output. `will-change` keeps
   it cheap; the glow simply disappears when `.in-dream` is dropped on waking. */
body.in-dream #output {
  --dream-haze: 0 0 7px rgba(255, 214, 150, 0.28);
  text-shadow: var(--dream-haze);
  transition: text-shadow 0.5s ease;
  line-height: 1.7;
}

/* Phaedro's spoken lines (the plain dream text) sit a touch warmer/brighter so
   the dialogue pops against the dimmer stage directions. */
body.in-dream #output > div {
  color: #f3e9d8;
}

/* Stage-direction lines ([The Rusty Tankard...], [Phaedro watches you...]) are
   the camera voice: dim warm sepia, italic, set apart from the dialogue. Beats
   the default green #output .bracket on specificity. */
body.in-dream #output .bracket,
body.in-dream #output > .bracket {
  color: #c9a878;
  font-style: italic;
  text-shadow: 0 0 5px rgba(201, 168, 120, 0.22);
}

/* Command words (bold-cyan spans from the **look** colorizer) become KEYCAP
   chips: a bordered pill that reads as "type this". Kept crisp (no haze blur) so
   the exact command is unmistakable. */
body.in-dream #output .ansi-bold.ansi-cyan {
  display: inline-block;
  padding: 0 0.4em;
  border: 1px solid rgba(139, 233, 253, 0.55);
  border-radius: 5px;
  background: rgba(139, 233, 253, 0.10);
  color: #aef2ff;
  font-weight: 600;
  line-height: 1.35;
  text-shadow: none;
  white-space: nowrap;
}

/* BU1581: the talk window's new lines, for screen readers only. */
.event-sr-new {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
