:root {
  --bg: #16140f;
  --panel: #221f18;
  --line: #3a352a;
  --text: #e8e0cc;
  --muted: #a59c86;
  --accent: #d08a2e;
  --hp: #b8432f;
  --st: #c9a94a;
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0; height: 100%; overflow: hidden; background: var(--bg); color: var(--text);
  font: 15px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  overscroll-behavior: none; touch-action: none;
}

#view { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

button { font: inherit; color: inherit; touch-action: manipulation; }

.screen {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(14, 12, 9, 0.92); z-index: 20; padding: 16px;
}
.screen[hidden] { display: none; }
.panel { max-width: 460px; width: 100%; text-align: center; }
.panel h1 { margin: 0; font-size: calc(34px * var(--ts, 1)); letter-spacing: 0.04em; color: var(--accent); }
.panel .sub { margin: 4px 0 18px; color: var(--muted); }
.panel .hint { margin-top: 22px; color: var(--muted); font-size: calc(13px * var(--ts, 1)); }

#progress { height: 6px; background: var(--line); border-radius: 3px; overflow: hidden; }
#progressFill { height: 100%; width: 0; background: var(--accent); transition: width 0.15s linear; }
#status { min-height: 1.4em; color: var(--muted); }

.big {
  min-width: 200px; min-height: 52px; margin-top: 10px; border: 1px solid var(--accent); border-radius: 8px;
  background: #3a2a14; color: var(--text); font-size: calc(18px * var(--ts, 1));
}
#errorText { text-align: left; white-space: pre-wrap; font-size: 12px; color: #e7a08f; max-height: 40vh; overflow: auto; }

#hud { position: fixed; inset: 0; pointer-events: none; z-index: 5; }
#hud[hidden] { display: none; }
.bars { position: absolute; left: calc(12px + var(--safe-l)); top: calc(10px + var(--safe-t)); width: min(260px, 42vw); }
.bar { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.bar .label { width: 22px; font-size: 12px; color: var(--muted); }
.track { flex: 1; height: 10px; background: rgba(0, 0, 0, 0.5); border: 1px solid var(--line); border-radius: 3px; overflow: hidden; }
.fill { height: 100%; width: 100%; }
.fill.hp { background: var(--hp); }
.fill.st { background: var(--st); }
.num { width: 54px; font-size: 12px; font-variant-numeric: tabular-nums; }
.top-right { position: absolute; right: calc(12px + var(--safe-r)); top: calc(10px + var(--safe-t)); pointer-events: auto; }

.chip {
  min-height: 44px; min-width: 44px; padding: 0 14px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); color: var(--text);
}
.chip.on { border-color: var(--accent); color: var(--accent); }
.chip.strong { border-color: var(--accent); }

#labels { position: absolute; inset: 0; }
.label3d {
  position: absolute; transform: translate(-50%, -100%); font-size: calc(12px * var(--ts, 1)); text-align: center; white-space: nowrap;
  text-shadow: 0 1px 2px #000;
}
.label3d .mini { width: 56px; height: 5px; margin: 2px auto 0; background: rgba(0, 0, 0, 0.6); border: 1px solid #000; }
.label3d .mini div { height: 100%; background: var(--hp); }
.float {
  position: absolute; transform: translate(-50%, -100%); font-weight: 700; font-size: calc(18px * var(--ts, 1)); text-shadow: 0 1px 3px #000;
  animation: rise 0.7s ease-out forwards;
}
.float.hurt { color: #ff8a6b; }
.float.deal { color: #f3e3b3; }
.float.miss { color: #9fb8c9; font-size: 14px; }
.float.heal { color: #8fe0a0; }
@keyframes rise { to { opacity: 0; transform: translate(-50%, -190%); } }
@media (prefers-reduced-motion: reduce) { .float { animation: fade 0.7s linear forwards; } @keyframes fade { to { opacity: 0; } } }

#toast {
  position: absolute; left: 50%; top: calc(12px + var(--safe-t)); transform: translateX(-50%);
  font-size: calc(13px * var(--ts, 1)); color: var(--muted);
}

#touch { position: fixed; inset: 0; z-index: 6; pointer-events: none; }
#touch[hidden] { display: none; }
#stickBase {
  position: absolute; width: 120px; height: 120px; margin: -60px 0 0 -60px; border-radius: 50%;
  border: 2px solid rgba(232, 224, 204, 0.35); background: rgba(0, 0, 0, 0.18); display: none;
}
#stickKnob {
  position: absolute; left: 50%; top: 50%; width: 54px; height: 54px; margin: -27px 0 0 -27px; border-radius: 50%;
  background: rgba(232, 224, 204, 0.55);
}
.act {
  position: absolute; pointer-events: auto; border-radius: 50%; border: 2px solid rgba(232, 224, 204, 0.55);
  background: rgba(30, 26, 18, 0.55); color: var(--text); font-size: calc(14px * var(--ts, 1)); touch-action: none;
}
.act.attack { width: 92px; height: 92px; right: calc(28px + var(--safe-r)); bottom: calc(28px + var(--safe-b)); border-color: var(--accent); }
.act.dodge { width: 70px; height: 70px; right: calc(136px + var(--safe-r)); bottom: calc(22px + var(--safe-b)); }
.act.pressed { background: rgba(208, 138, 46, 0.45); }

.sheet {
  position: fixed; z-index: 15; right: calc(10px + var(--safe-r)); top: calc(10px + var(--safe-t));
  width: min(440px, calc(100vw - 20px)); max-height: calc(100% - 20px); overflow: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
}
.sheet[hidden] { display: none; }
.sheet h2 { margin: 0 0 8px; font-size: calc(18px * var(--ts, 1)); }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0; }
.row > span:first-child { width: 84px; color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
.muted { color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
#resultsText {
  white-space: pre-wrap; word-break: break-word; font-size: 11px; line-height: 1.35; background: #15130e;
  border: 1px solid var(--line); border-radius: 6px; padding: 8px; max-height: 50vh; overflow: auto; user-select: text; -webkit-user-select: text;
}

#timer {
  position: absolute; left: 50%; bottom: calc(8px + var(--safe-b)); transform: translateX(-50%);
  font-size: calc(12px * var(--ts, 1)); color: var(--muted); font-variant-numeric: tabular-nums;
}

/* ---------------- Seal Run (CATACOMB_SEAL_RUN v0.1) ---------------- */
#objective {
  position: absolute; left: 50%; top: calc(10px + var(--safe-t)); transform: translateX(-50%);
  max-width: min(520px, 60vw); padding: 6px 12px; border: 1px solid var(--line); border-radius: 8px;
  background: rgba(22, 20, 15, 0.82); font-size: calc(14px * var(--ts, 1)); text-align: center;
}
#objective[hidden], #timer[hidden] { display: none; }
#toast { top: calc(56px + var(--safe-t)); }
.act.interact {
  width: 92px; height: 92px; right: calc(28px + var(--safe-r)); bottom: calc(132px + var(--safe-b));
  border-color: #8fb3c7; font-size: calc(13px * var(--ts, 1)); z-index: 7;
}
.act.interact[hidden] { display: none; }
.act.interact:disabled { opacity: 0.35; }
.screen.run { background: rgba(14, 12, 9, 0.78); }
.screen.run .panel { max-width: 560px; }
.screen.run h1 { font-size: calc(26px * var(--ts, 1)); }
.screen.run p { margin: 6px 0; }
.cards { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 14px 0 6px; }
.card {
  flex: 1 1 200px; max-width: 240px; min-height: 120px; padding: 12px; border: 2px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--text); text-align: left;
}
.card h3 { margin: 0 0 6px; font-size: calc(17px * var(--ts, 1)); color: var(--accent); }
.card p { margin: 0; font-size: calc(14px * var(--ts, 1)); }
.card.selected { border-color: var(--accent); background: #2e2617; }
.big:disabled { opacity: 0.4; }
.summary { margin: 10px auto; border-collapse: collapse; font-size: calc(14px * var(--ts, 1)); }
.summary td { padding: 3px 10px; text-align: left; }
.summary td:first-child { color: var(--muted); }
.notice { color: #e7c48f; font-size: calc(13px * var(--ts, 1)); }

/* ---------------- Batch 1 campaign: hub, sheets, run panels ---------------- */
.hub {
  position: fixed; inset: 0; z-index: 12; overflow: auto; background: rgba(14, 12, 9, 0.94);
  padding: calc(12px + var(--safe-t)) calc(16px + var(--safe-r)) calc(24px + var(--safe-b)) calc(16px + var(--safe-l));
}
.hub[hidden] { display: none; }
.hub-inner { max-width: 980px; margin: 0 auto; }
.hub h1 { margin: 0 0 6px; font-size: calc(26px * var(--ts, 1)); color: var(--accent); letter-spacing: 0.04em; }
.hub h2 { margin: 18px 0 6px; font-size: calc(18px * var(--ts, 1)); }
.hub h3 { margin: 10px 0 4px; font-size: calc(14px * var(--ts, 1)); color: var(--muted); }
.hub section { border-top: 1px solid var(--line); padding-top: 4px; }
.hub-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 6px 0; }
.dcards { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.dcard { border: 1px solid var(--line); border-radius: 10px; padding: 12px; background: var(--panel); }
.dcard h3 { margin: 0 0 6px; font-size: calc(17px * var(--ts, 1)); color: var(--text); }
.dcard p { margin: 4px 0; font-size: calc(14px * var(--ts, 1)); }
.dcard .big { width: 100%; min-width: 0; }
.hub .cards, .sheet .cards, .screen.run .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; justify-content: stretch; }
.item { border: 1px solid var(--line); border-left-width: 4px; border-radius: 8px; padding: 8px 10px; background: var(--panel); text-align: left; font-size: calc(14px * var(--ts, 1)); }
.item[data-item] { cursor: pointer; }
.item.empty { opacity: 0.6; }
.item.equipped { box-shadow: inset 0 0 0 1px var(--accent); }
.item-head { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.item .tag { font-size: calc(12px * var(--ts, 1)); color: var(--muted); white-space: nowrap; }
.item ul { margin: 6px 0 4px; padding-left: 18px; }
.item .big { width: 100%; min-width: 0; font-size: calc(16px * var(--ts, 1)); }
/* Named items (named.js): a word mark, never colour alone. */
.named-line { margin: 6px 0 2px; font-size: calc(14px * var(--ts, 1)); }
.named-mark, .named-pip { display: inline-block; border: 1px solid currentColor; border-radius: 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.named-mark { padding: 1px 6px; margin-right: 4px; }
.named-pip { position: absolute; left: 3px; top: 3px; padding: 0 3px; line-height: 14px; background: var(--panel); }
.named-status { margin: 0 0 4px; font-size: calc(13px * var(--ts, 1)); }
.named-changes { margin: 6px 0; padding-left: 18px; font-size: calc(13px * var(--ts, 1)); }
.r-common { border-left-color: #bdb6a6; }
.r-uncommon { border-left-color: #6fbf73; }
.r-rare { border-left-color: #5b8fd9; }
.r-epic { border-left-color: #b07ad6; }
.stats, .diff { border-collapse: collapse; font-size: calc(13px * var(--ts, 1)); margin: 6px 0; }
.stats td, .diff td { padding: 2px 8px 2px 0; vertical-align: top; }
.stats td:nth-child(odd) { color: var(--muted); }
.diff .good td:nth-child(3) { color: #8fc98f; }
.diff .bad td:nth-child(3) { color: #e08a72; }
.warn { color: #e08a72; font-size: calc(13px * var(--ts, 1)); }
.bench { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.bench select, .bench input, .sheet input, .sheet textarea {
  min-height: 40px; background: #15130e; color: var(--text); border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; font-size: calc(14px * var(--ts, 1));
}
.bench input { width: 18ch; font-family: ui-monospace, monospace; }
.sheet.tall { left: 50%; right: auto; transform: translateX(-50%); width: min(620px, calc(100vw - 20px)); z-index: 30; } /* above run panels (review R2) */
#paused { z-index: 40; } /* focus loss covers everything, including an open sheet */
.sheet textarea { width: 100%; min-height: 110px; box-sizing: border-box; user-select: text; -webkit-user-select: text; }
.sheet input { width: 100%; box-sizing: border-box; margin-top: 6px; }
.sheet ul.notes { padding-left: 18px; font-size: calc(13px * var(--ts, 1)); }
.sheet ul.notes li { margin: 6px 0; }
.sheet ul.sources { font-size: calc(13px * var(--ts, 1)); }
.panel.wide { max-width: 760px; }
/* Overflowing panels scroll from their top instead of being centred above the scroll origin (review R3). */
.screen.run { overflow: auto; align-items: flex-start; justify-content: flex-start; -webkit-overflow-scrolling: touch; }
.screen.run > .panel { margin: auto; }

/* ---------------- Gameplay correction: Vanguard kit, crowd labels, boss bar, route map ---------------- */
/* Action bar (expedition): a framed row of square slots, the same on touch and desktop. */
.action-bar {
  position: fixed; z-index: 7; bottom: calc(10px + var(--safe-b)); left: 50%; transform: translateX(-50%);
  display: flex; align-items: flex-end; gap: 6px; padding: 7px; pointer-events: auto; touch-action: none;
  background: linear-gradient(#2a251d, #17140f); border: 1px solid #5a4e3a; border-radius: 12px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 230, 180, 0.08);
  --s: clamp(50px, 7.2vw, 62px);
}
.action-bar[hidden] { display: none; }
.action-bar.touch { left: auto; right: calc(10px + var(--safe-r)); transform: none; }
.action-bar .slot {
  position: relative; width: var(--s); height: var(--s); padding: 0; overflow: hidden; touch-action: none; cursor: pointer;
  display: grid; place-items: center; border-radius: 9px; border: 1px solid #6b5d44;
  background: radial-gradient(circle at 50% 35%, #3b3428, #1d1a14 75%); color: #ecdcb8;
  box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.45), inset 0 -6px 10px rgba(0, 0, 0, 0.35);
}
.action-bar .slot.attack { --s2: calc(var(--s) * 1.25); width: var(--s2); height: var(--s2); border-color: var(--accent); }
.action-bar .slot svg { width: 58%; height: 58%; margin-top: -10%; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.action-bar .slot svg .fill { stroke: #c0503c; }
.action-bar .slot .name { position: absolute; bottom: 3px; left: 0; right: 0; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: #cdbf9e; }
.action-bar .slot .key { position: absolute; top: 2px; left: 4px; font-size: 10px; color: var(--accent); }
.action-bar.touch .slot .key { display: none; }
.action-bar .slot .cost { position: absolute; top: 2px; right: 4px; font-size: 10px; color: #9fc6ec; }
.action-bar .slot .count { position: absolute; top: 2px; right: 4px; min-width: 16px; height: 16px; border-radius: 8px; background: #8a2f22; color: #fff; font-size: 11px; line-height: 16px; }
.action-bar .slot .pips { position: absolute; top: 4px; right: 5px; display: flex; gap: 3px; }
.action-bar .slot .pips i { width: 6px; height: 6px; transform: rotate(45deg); border: 1px solid #c9a24a; }
.action-bar .slot .pips i.on { background: #f0c27a; }
.action-bar .slot::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  background: conic-gradient(rgba(8, 6, 4, 0.72) calc(var(--cd, 0) * 1turn), transparent 0);
}
.action-bar .slot .cdtext { position: absolute; inset: 0; display: grid; place-items: center; z-index: 1; font-size: 18px; font-weight: 700; color: #fff; text-shadow: 0 1px 3px #000; pointer-events: none; }
.action-bar .slot.cooling svg { opacity: 0.45; }
.action-bar .slot.low svg { opacity: 0.4; } .action-bar .slot.low .cost { color: #f1886f; }
.action-bar .slot.empty { filter: grayscale(1); opacity: 0.5; }
.action-bar .slot.active { border-color: #9fc6ec; box-shadow: 0 0 0 2px #9fc6ec, 0 0 14px rgba(143, 196, 232, 0.6); }
.action-bar .slot.attack.active { border-color: #f0c27a; box-shadow: 0 0 0 2px #f0c27a; }
.action-bar .slot.free { border-color: #f0c27a; box-shadow: 0 0 12px rgba(240, 194, 122, 0.7); }
.action-bar .slot.pressed { transform: translateY(1px) scale(0.96); background: radial-gradient(circle at 50% 35%, #5a4a30, #2a2216 75%); }
.action-bar .slot.ready { animation: slotReady 0.45s ease-out; }
@keyframes slotReady { 0% { box-shadow: 0 0 0 0 rgba(240, 194, 122, 0.9); } 100% { box-shadow: 0 0 0 10px rgba(240, 194, 122, 0); } }
.action-bar .slot.refused { border-color: #d05a4a !important; animation: refuse 0.3s linear; }
.action-bar .slot:focus-visible { outline: 3px solid #91d1bd; outline-offset: 2px; }
@keyframes refuse { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
@media (prefers-reduced-motion: reduce) { .action-bar .slot.ready, .action-bar .slot.refused { animation: none; } }
body.kit #attackBtn, body.kit #dodgeBtn { display: none; }
body.kit .act.interact { right: calc(14px + var(--safe-r)); bottom: calc(108px + var(--safe-b)); width: 84px; height: 84px; }
body.kit #toast { bottom: auto; }

#bossBar {
  position: absolute; left: 50%; top: calc(48px + var(--safe-t)); transform: translateX(-50%);
  width: min(420px, 56vw); padding: 4px 10px; border: 1px solid var(--line); border-radius: 8px; background: rgba(22, 20, 15, 0.82);
  font-size: calc(13px * var(--ts, 1));
}
#bossBar[hidden], #bossChannel[hidden] { display: none; }
#bossBar .boss-name { display: flex; justify-content: space-between; }
#bossBar .track { height: 8px; background: rgba(0, 0, 0, 0.55); border: 1px solid #000; margin-top: 3px; }
#bossBar .track.thin { height: 5px; }
#bossBar .fill { height: 100%; }
#bossBar .fill.channel { background: #8fc4e8; }
#bossChannel span { font-size: 12px; color: #8fc4e8; }
body.boss #toast { top: calc(104px + var(--safe-t)); }

.route-map {
  position: absolute; right: calc(10px + var(--safe-r)); top: calc(48px + var(--safe-t)); pointer-events: auto;
  width: 132px; height: 150px; padding: 4px; border: 1px solid var(--line); border-radius: 8px; background: rgba(22, 20, 15, 0.78);
}
.route-map[hidden] { display: none; }
.route-map.big { width: min(320px, 48vw); height: min(330px, 70vh); background: rgba(22, 20, 15, 0.94); z-index: 8; }
.route-map svg { width: 100%; height: 100%; display: block; }

.label3d.priority > div:first-child { color: #f0c27a; font-weight: 600; }
/* A marked enemy: its full name, with a diamond before it (the shape says it; the colour only agrees). */
.label3d.marked > div:first-child { color: #fff0b8; font-weight: 700; font-size: 13px; }
.label3d.marked > div:first-child::before {
  content: ''; display: inline-block; width: 7px; height: 7px; margin: 0 7px 1px 0; transform: rotate(45deg);
  border: 2px solid currentColor; box-sizing: border-box; vertical-align: middle;
}
.label3d.boss > div:first-child { display: none; }
.label3d.plain > div:first-child { display: none; }
.label3d.plain .mini { width: 34px; height: 4px; }

.runes { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin: 6px 0; }
.runes .rune { padding: 3px 8px; border: 1px solid #8fc4e8; border-radius: 12px; font-size: calc(12px * var(--ts, 1)); }
.controls { text-align: left; font-size: calc(13px * var(--ts, 1)); columns: 2; column-gap: 18px; margin: 8px 0; }
.controls div { break-inside: avoid; margin: 2px 0; }
.controls b { color: var(--accent); }
.rooms td:last-child, .rooms td:nth-child(2) { text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 520px) { .controls { columns: 1; } }

/* ---------------- Camp (docs/ui/PLAYER_FLOW.md, #50) ---------------- */
.hub.camp { padding: 0; display: flex; flex-direction: column; overflow: hidden; height: 100dvh; background: var(--bg); z-index: 13; }
.hub.camp[hidden] { display: none; }
.camp { --gold: #e6bf72; font-size: calc(16px * var(--ts, 1)); -webkit-user-select: text; user-select: text; touch-action: pan-y; }
.camp button { min-height: 48px; min-width: 44px; padding: 10px 16px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); color: var(--text); font: inherit; cursor: pointer; }
.camp button:focus-visible, .camp summary:focus-visible { outline: 3px solid #91d1bd; outline-offset: 3px; }
.camp button[disabled] { opacity: 0.5; cursor: default; }
.camp .primary { background: var(--gold); color: #201b11; border-color: var(--gold); font-weight: 700; }
.camp .quiet { background: transparent; }
.camp .danger { color: #f1b2a8; }
.camp .small { min-height: 36px; padding: 4px 10px; font-size: calc(13px * var(--ts, 1)); }
.camp .wide { width: 100%; }
.camp .link { background: transparent; border-color: transparent; color: var(--gold); padding-left: 0; text-align: left; }
.camp h1 { margin: 0; font-size: clamp(24px, 5vw, 34px); line-height: 1.15; color: var(--text); letter-spacing: 0; }
.camp h2 { margin: 0; font-size: calc(20px * var(--ts, 1)); } .camp h3 { margin: 0; font-size: calc(17px * var(--ts, 1)); color: var(--text); }
.camp p { margin: 0; } .camp .stack { display: grid; gap: 14px; }
.camp .eyebrow { font-size: calc(12px * var(--ts, 1)); letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold); margin: 0; }
.camp .muted, .camp small { color: var(--muted); }
.camp .warn { color: #f1b2a8; }
.camp .badge { display: inline-block; margin-left: 6px; font-size: calc(12px * var(--ts, 1)); border: 1px solid var(--line); border-radius: 50px; padding: 4px 10px; color: var(--muted); }
.camp .badge.warn { color: #f1b2a8; border-color: #8a4a40; }
#campMain { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 10px calc(16px + var(--safe-r)) 20px calc(16px + var(--safe-l)); max-width: 960px; width: 100%; margin: 0 auto; outline: none; }
#campMain h1:focus { outline: none; }
#campFooter { border-top: 1px solid var(--line); background: rgba(16, 15, 12, 0.98); padding: 8px calc(14px + var(--safe-r)) calc(8px + var(--safe-b)) calc(14px + var(--safe-l)); }
#campFooter[hidden] { display: none; }
@media (min-width: 700px) {
  .camp-grid { grid-template-columns: 0.85fr 1.3fr; align-items: start; }
}
@media (max-height: 430px) and (orientation: landscape) { .camp-grid { grid-template-columns: 0.85fr 1.3fr; } .dungeon-art { height: 96px; } }
.camp .card { border: 1px solid var(--line); background: var(--panel); border-radius: 14px; overflow: hidden; max-width: none; min-height: 0; padding: 0; flex: none; }
.camp .card h3 { color: var(--text); margin: 0; } .camp .card p { font-size: calc(15px * var(--ts, 1)); }
.camp .pad { padding: 16px; }
.camp-grid { display: grid; gap: 14px; }
.camp .hero { display: flex; gap: 14px; align-items: center; }
.camp .seal { width: 56px; height: 66px; display: grid; place-items: center; flex-shrink: 0; border: 1px solid #a69264; border-radius: 10px 10px 26px 26px; background: #31382d; font: 28px Georgia, serif; color: var(--gold); }
.camp .build-line { margin-top: 12px; }
.dungeon-art { position: relative; height: 140px; background: radial-gradient(ellipse at 50% 92%, #7a5a3a 0, transparent 62%), linear-gradient(#22201c, #121110); display: grid; align-items: end; padding: 14px; overflow: hidden; }
.dungeon-art::before, .dungeon-art::after { content: ""; position: absolute; top: 14px; bottom: -30px; width: 26%; border: 10px solid #4a453d; border-top-left-radius: 70px; border-top-right-radius: 70px; background: #141210; opacity: 0.7; }
.dungeon-art::before { left: 17%; } .dungeon-art::after { right: 17%; }
.dungeon-art span { position: relative; z-index: 1; letter-spacing: 0.17em; font-size: 12px; color: #e0d8c0; text-transform: uppercase; }
.camp .tags { display: flex; gap: 8px; flex-wrap: wrap; }
.camp .tag { font-size: calc(13px * var(--ts, 1)); background: #2e2a22; padding: 4px 9px; border-radius: 6px; color: #e4dcc6; }
.camp .blocker { border-color: #a07a3a; }
.camp .choice { width: 100%; text-align: left; padding: 14px; display: grid; gap: 4px; }
.camp .choice[aria-checked=true] { border: 2px solid var(--gold); background: #332d22; }
.camp .choice b { font-size: calc(18px * var(--ts, 1)); } .camp .choice span { color: var(--muted); } .camp .check { color: var(--gold) !important; font-size: calc(13px * var(--ts, 1)); }
.camp .slot-row { width: 100%; display: grid; grid-template-columns: 50px 1fr auto; align-items: center; gap: 12px; text-align: left; padding: 10px 12px; }
.camp .slot-row:not(:has(.token)) { grid-template-columns: 1fr auto; }
.camp .slot-row.empty { opacity: 0.7; }
.camp .token { width: 44px; height: 44px; display: grid; place-items: center; background: #3a342a; border-radius: 8px; color: var(--gold); font: 20px Georgia, serif; }
.camp .filters { display: flex; gap: 6px; flex-wrap: wrap; }
.camp .filters button[aria-pressed=true] { border-color: var(--gold); color: var(--gold); }
.camp .filters button[aria-pressed=true]::before { content: "✓ "; }
.camp .comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.camp .compare-item { padding: 14px; } .camp .compare-item small { display: block; margin-bottom: 6px; } .camp .compare-item p { color: var(--muted); font-size: calc(14px * var(--ts, 1)); margin-top: 6px; }
.camp .diffs { list-style: none; margin: 0; padding: 0; }
.camp .diffs li { padding: 9px 0; border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; gap: 10px; }
.camp .good { color: #a9dbb2; } .camp .bad { color: #f1b2a8; }
.camp details { padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px; }
.camp summary { cursor: pointer; min-height: 32px; } .camp details p, .camp details ul { margin-top: 8px; font-size: calc(14px * var(--ts, 1)); color: var(--muted); }
.camp details button { margin: 6px 6px 0 0; }
.camp .ability-detail dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 10px 0 0; font-size: calc(15px * var(--ts, 1)); }
.camp .ability-detail dt { color: var(--muted); }
.camp .ability-detail dd { margin: 0; }
.camp .keys { border-collapse: collapse; width: 100%; font-size: calc(14px * var(--ts, 1)); }
.camp .keys th, .camp .keys td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }
.camp .intro { max-width: 520px; margin: 10vh auto; text-align: center; display: grid; gap: 12px; }
.camp .intro h1 { font-family: Georgia, serif; font-size: clamp(38px, 8vw, 64px); letter-spacing: 0.04em; color: var(--accent); }
.camp .notice { margin-bottom: 12px; padding: 10px 12px; border: 1px solid #6a5a3a; border-radius: 10px; background: #2a2418; font-size: calc(14px * var(--ts, 1)); }
.camp .row { display: flex; align-items: center; gap: 10px; margin: 0; } .camp .between { justify-content: space-between; } .camp .wrap { flex-wrap: wrap; }
.camp .bench { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.camp select, .camp input { min-height: 48px; font: inherit; color: var(--text); background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 8px; }
@media (max-width: 420px) { .camp .comparison { grid-template-columns: 1fr; } }

/* First-run tips in play: one at a time, never blocking. */
#tip { position: absolute; left: 50%; top: calc(52px + var(--safe-t)); transform: translateX(-50%); pointer-events: auto; z-index: 7;
  display: flex; align-items: center; gap: 10px; max-width: min(480px, 70vw); padding: 8px 10px 8px 14px; border: 1px solid #8fc4e8; border-radius: 10px; background: rgba(22, 20, 15, 0.92); font-size: calc(15px * var(--ts, 1)); }
#tip[hidden] { display: none; }
#tip button { min-height: 44px; }
body.boss #tip { top: calc(112px + var(--safe-t)); }
.camp section { border-top: 0; padding-top: 0; }
.camp h2 { margin: 0; color: var(--text); } .camp h3 { color: var(--text); }
.sheet .menu-list { display: grid; gap: 8px; margin: 8px 0 4px; }
.sheet .menu-list .chip, #pmLeave, #pmGo, #pmStay { min-height: 48px; }
.chip.danger { border-color: #b8432f; color: #f1b2a8; }

/* ---------------- In-play HUD layout (review F3) ----------------
   Top-left: health/stamina, then one stacked column (objective, boss, tip, toast). Top-right: menu, then the map (a
   small preview on large screens, a Map button on phones). Bottom: the action bar, with Interact above its right end. */
#hudStack {
  position: absolute; left: calc(12px + var(--safe-l)); top: calc(64px + var(--safe-t));
  width: min(440px, calc(100vw - 24px - 80px - var(--safe-l) - var(--safe-r)));
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px; pointer-events: none;
}
#hudStack > * { position: static !important; transform: none !important; left: auto !important; top: auto !important; max-width: 100%; }
#hudStack #objective { width: auto; font-size: calc(13px * var(--ts, 1)); text-align: left; padding: 5px 10px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
#hudStack #objective[hidden] { display: none; }
#hudStack #bossBar { width: 100%; box-sizing: border-box; }
#hudStack #tip { pointer-events: auto; max-width: 100%; box-sizing: border-box; font-size: calc(14px * var(--ts, 1)); }
#hudStack #toast:empty { display: none; }
/* A style's own rule in a run (the Breaker's shrug): a small label that says ready or spent in words; the mark and the
   border change with it, so colour is never the only sign. */
#hudStack .rule-badge { display: inline-flex; align-items: center; gap: 7px; align-self: flex-start; width: fit-content; padding: 4px 10px; border-radius: 6px;
  font-size: calc(13px * var(--ts, 1)); font-weight: 700; letter-spacing: 0.03em; color: #f3e6c4; background: rgba(22, 20, 15, 0.82); border: 2px solid #c9a24a; }
#hudStack .rule-badge::before { content: ""; width: 9px; height: 9px; transform: rotate(45deg); background: #f0c27a; border: 1px solid #f0c27a; }
#hudStack .rule-badge.spent { color: #b9ad94; font-weight: 600; border: 2px dashed #6b5d44; }
#hudStack .rule-badge.spent::before { background: none; border-color: #8c8067; }
#hudStack .rule-badge[hidden] { display: none; }
/* Held runes: a plain button under the badge (a press lists them); the card rows it opens, and a pair rune's "forged from" line. */
#hudStack .rune-bar { pointer-events: auto; align-self: flex-start; width: fit-content; min-height: 44px; padding: 4px 12px; border-radius: 6px;
  font: inherit; font-size: calc(13px * var(--ts, 1)); font-weight: 700; letter-spacing: 0.03em; color: #d7e6f2; background: rgba(15, 20, 26, 0.82); border: 2px solid #5f87a6; cursor: pointer; }
#hudStack .rune-bar:focus-visible { outline: 2px solid #f0c27a; outline-offset: 2px; }
#hudStack .rune-bar[hidden] { display: none; }
#cardBody .rune-row { text-align: left; padding: 8px 0; border-top: 1px solid rgba(143, 196, 232, 0.25); }
#cardBody .rune-row h3 { margin: 0 0 2px; font-size: calc(16px * var(--ts, 1)); color: #d7e6f2; }
#cardBody .rune-row.pair h3 { color: #f0c27a; }
#cardBody .rune-row p { margin: 0; font-size: calc(14px * var(--ts, 1)); }
#cardBody .forged { color: #f0c27a; font-size: calc(14px * var(--ts, 1)); font-weight: 600; }
#hudStack #toast { font-size: calc(13px * var(--ts, 1)); padding: 3px 8px; border-radius: 6px; background: rgba(22, 20, 15, 0.7); color: var(--text); }
@media (min-width: 900px) and (min-height: 560px) { #hudStack { width: min(480px, calc(100vw - 24px - 170px)); } }
.route-map { top: calc(62px + var(--safe-t)); }
.route-map.icon { width: 56px; height: 48px; padding: 0; font-size: 13px; color: var(--text); }
.route-map.big { position: fixed; left: 50%; top: 50%; right: auto; transform: translate(-50%, -50%); width: min(340px, 86vw); height: min(360px, 78vh); }

/* ---------------- Interaction prompt and centred decision card (owner notes n4, n8) ---------------- */
body.kit .act.interact {
  left: 50%; right: auto; transform: translateX(-50%); bottom: calc(112px + var(--safe-b));
  width: auto; height: auto; min-height: 48px; min-width: 180px; max-width: min(440px, calc(100vw - 32px));
  display: inline-flex; align-items: center; justify-content: center; gap: 10px; padding: 10px 20px; border-radius: 26px;
  font-size: calc(15px * var(--ts, 1)); font-weight: 600; background: rgba(28, 25, 19, 0.94); border: 2px solid #8fb3c7; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}
body.kit .act.interact.gate { border-color: var(--accent); }
body.kit .act.interact .key { font-size: calc(12px * var(--ts, 1)); padding: 2px 7px; border: 1px solid currentColor; border-radius: 5px; opacity: 0.85; }
.center-card {
  position: fixed; z-index: 40; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(420px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); overflow: auto;
  background: linear-gradient(#262119, #16130e); border: 1px solid #8a7550; border-radius: 16px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.7); color: var(--text); text-align: center;
}
.center-card[hidden] { display: none; }
.center-card .card-art { height: 72px; background: radial-gradient(ellipse at 50% 120%, rgba(230, 191, 114, 0.35), transparent 65%), linear-gradient(#2c271e, #1a1712); border-bottom: 1px solid #4a4030; }
.center-card .card-art[data-art=chest] { height: 64px; }
#cardBody { --card-pad-x: 20px; --card-pad-b: 20px; padding: 16px var(--card-pad-x) var(--card-pad-b); display: grid; gap: 10px; }
#cardBody h2 { margin: 0; font-size: calc(22px * var(--ts, 1)); }
#cardBody p { margin: 0; }
#cardBody .eyebrow { font-size: calc(12px * var(--ts, 1)); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
#cardBody .tags { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; }
#cardBody .tag { font-size: calc(12px * var(--ts, 1)); padding: 3px 9px; border-radius: 6px; background: #2e2a22; color: #e4dcc6; }
#cardBody .card-actions { display: flex; gap: 10px; justify-content: center; margin-top: 6px; }
#cardBody .card-actions button { min-height: 48px; min-width: 120px; font-size: calc(16px * var(--ts, 1)); }
@media (max-height: 430px) and (orientation: landscape) { .center-card .card-art { height: 36px; } #cardBody { --card-pad-x: 16px; --card-pad-b: 14px; padding: 10px var(--card-pad-x) var(--card-pad-b); gap: 6px; } }

/* ---------------- Combat HUD (owner notes n2, n3; #56) ----------------
   Expedition: no corner bars. Stamina (left) and health (right) are orbs flanking the action bar; the boss's name and
   health sit at top centre; a boss's committed move is called out briefly above the hero. The orbs carry a number and a
   name, never colour alone. */
body.kit .bars { display: none; }
body.kit #hudStack { top: calc(10px + var(--safe-t)); }
body.kit.boss #hudStack { top: calc(76px + var(--safe-t)); }
body.kit #bossBar {
  top: calc(8px + var(--safe-t)); width: min(560px, calc(100vw - 200px - var(--safe-l) - var(--safe-r))); min-width: 180px;
  padding: 6px 12px 8px; text-align: center; border-color: #7a3a2e; background: rgba(20, 14, 11, 0.9); z-index: 6;
}
body.kit #bossBar .boss-name { justify-content: center; gap: 10px; font-size: 16px; font-weight: 700; letter-spacing: 0.04em; color: #f1d9b0; }
body.kit #bossBar .boss-name .muted { font-weight: 400; font-size: 12px; align-self: center; }
body.kit #bossBar .track { height: 12px; margin-top: 4px; }
body.kit #bossBar #bossChannel span { font-size: 12px; }
#alert {
  position: fixed; left: 50%; top: 30%; transform: translate(-50%, -50%); z-index: 9; pointer-events: none;
  max-width: min(520px, calc(100vw - 32px)); padding: 8px 18px; border-radius: 10px; text-align: center;
  background: rgba(30, 12, 8, 0.86); border: 2px solid #e0703c; color: #ffe6c8; font-size: calc(20px * var(--ts, 1)); font-weight: 700;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.6);
}
#alert[hidden] { display: none; }
#alert.hazard { border-color: #e0b03c; background: rgba(28, 22, 8, 0.86); font-size: calc(17px * var(--ts, 1)); }
.world-label { position: fixed; z-index: 6; pointer-events: none; transform: translate(-50%, -100%); padding: 3px 8px; border-radius: 6px;
  background: rgba(22, 20, 15, 0.85); border: 1px solid #a08a5a; font-size: calc(13px * var(--ts, 1)); color: var(--text); white-space: nowrap; }
.world-label[hidden] { display: none; }

.action-bar .slots { display: flex; align-items: flex-end; gap: 6px; }
@media (orientation: portrait) and (max-width: 560px) {
  /* Portrait phone: a compact 2 x 3 grid of actions between the two orbs, centred above the home bar. */
  .action-bar, .action-bar.touch { left: 50%; right: auto; transform: translateX(-50%); --s: 50px; gap: 8px; padding: 6px; }
  .orb { --globe: 78px; }
  .action-bar .slots { display: grid; grid-template-columns: repeat(3, var(--s)); gap: 5px; }
  .action-bar .slot.attack { --s2: var(--s); }
  body.kit .act.interact { bottom: calc(132px + var(--safe-b)); }
}
body.kit .act.interact[hidden] { display: none; }

/* ---------------- Rewards and gear during a run (owner notes n5, n6, n8; #58) ---------------- */
#hudStack #pickup { pointer-events: auto; display: flex; align-items: center; gap: 10px; padding: 6px 8px 6px 12px; border-radius: 8px;
  background: rgba(22, 30, 18, 0.92); border: 1px solid #6fbf73; font-size: calc(14px * var(--ts, 1)); }
#hudStack #pickup[hidden] { display: none; }
#hudStack #pickup button { min-height: 40px; }
#cardBody .reward { text-align: left; display: grid; gap: 8px; padding: 10px; border: 1px solid var(--line); border-radius: 10px; background: rgba(0, 0, 0, 0.18); }
#cardBody .reward .item { border: none; padding: 0; background: none; }
#cardBody .reward details { font-size: calc(13px * var(--ts, 1)); }
#cardBody .reward .wide { width: 100%; min-height: 48px; font-size: calc(16px * var(--ts, 1)); }
#cardBody .good, .sheet .good { color: #a9dbb2; }
#cardBody .warn, .sheet .warn { color: #f1b2a8; }
.sheet .run-gear h3 { margin: 14px 0 6px; }
.sheet .run-gear .item.focus { outline: 2px solid var(--accent); outline-offset: 2px; }
.sheet .run-gear .chips button[disabled] { opacity: 0.45; }

/* ---------------- Controllers (gamepad.js; Kenney Input Prompts, CC0) ---------------- */
[data-pad="south"] { --pad-icon: var(--pad-south); }
[data-pad="east"] { --pad-icon: var(--pad-east); }
[data-pad="west"] { --pad-icon: var(--pad-west); }
[data-pad="north"] { --pad-icon: var(--pad-north); }
[data-pad="leftBumper"] { --pad-icon: var(--pad-leftBumper); }
[data-pad="rightBumper"] { --pad-icon: var(--pad-rightBumper); }
[data-pad="leftTrigger"] { --pad-icon: var(--pad-leftTrigger); }
[data-pad="rightTrigger"] { --pad-icon: var(--pad-rightTrigger); }
[data-pad="back"] { --pad-icon: var(--pad-back); }
[data-pad="start"] { --pad-icon: var(--pad-start); }
[data-pad="leftStick"] { --pad-icon: var(--pad-leftStick); }
[data-pad="rightStick"] { --pad-icon: var(--pad-rightStick); }
[data-pad="rightStickPress"] { --pad-icon: var(--pad-rightStickPress); }
[data-pad="dpad"] { --pad-icon: var(--pad-dpad); }
.padicon { display: inline-block; width: 26px; height: 26px; vertical-align: middle; background: var(--pad-icon) center / contain no-repeat; }
.padicon + .padicon { margin-left: 2px; }
/* While a pad is in use, its buttons replace the key hints. */
body.pad-on .action-bar .slot .key { display: block; font-size: 0; width: 22px; height: 22px; top: 1px; left: 2px; background: var(--pad-icon) center / contain no-repeat; }
body.pad-on #interactBtn::before, body.pad-on #menuBtn::before, body.pad-on #tipOk::before, body.pad-on .route-map.icon::before {
  content: ""; display: inline-block; width: 22px; height: 22px; margin-right: 6px; vertical-align: middle; background: var(--pad-icon) center / contain no-repeat; }
/* The controller's highlight must always be visible (programmatic focus may not show :focus-visible). */
body.pad-on button:focus, body.pad-on summary:focus, body.pad-on select:focus, body.pad-on a:focus { outline: 3px solid #91d1bd; outline-offset: 3px; }
body.pad-on #interactBtn .key { display: none; } /* the pad icon (::before) replaces the E key in the prompt */

/* ---------------- Health and stamina globes (candidate notes n1, n2) ----------------
   Large globes, health left and stamina right, each with its number and name. These are the base rules (the corners);
   on desktop the block after them moves the globes to either end of the action bar. */
.orb { --globe: clamp(92px, 11vw, 140px); position: fixed; z-index: 7; bottom: calc(8px + var(--safe-b)); width: var(--globe); height: var(--globe);
  border-radius: 50%; overflow: hidden; display: grid; place-items: center; pointer-events: none;
  background: radial-gradient(circle at 50% 40%, #1b1612, #050403 80%);
  border: 4px solid #6b5a3e; box-shadow: 0 0 0 2px #1a140c, 0 0 0 5px #8a7550, 0 6px 18px rgba(0, 0, 0, 0.7), inset 0 0 18px rgba(0, 0, 0, 0.9); }
.orb.hp { left: calc(10px + var(--safe-l)); }
.orb.st { right: calc(10px + var(--safe-r)); }
.action-bar[hidden] ~ .orb { display: none; }
.orb .liquid { position: absolute; left: 0; right: 0; bottom: 0; height: var(--fill, 100%); transition: height 0.15s linear; }
.orb.hp .liquid { background: radial-gradient(ellipse at 50% 0%, #ff7a5c 0, transparent 40%), linear-gradient(#c2321e, #5e0e08); }
.orb.st .liquid { background: radial-gradient(ellipse at 50% 0%, #ffe39a 0, transparent 40%), linear-gradient(#d9a73a, #6a4710); }
.orb .glass { position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(ellipse 45% 30% at 38% 22%, rgba(255, 255, 255, 0.35), transparent 70%), radial-gradient(circle at 50% 50%, transparent 60%, rgba(0, 0, 0, 0.45) 100%); }
.orb.low { border-color: #e0503c; }
.orb .orb-val { position: relative; z-index: 1; font-size: clamp(16px, 1.9vw, 22px); font-weight: 800; color: #fff; text-shadow: 0 1px 2px #000, 0 0 6px #000; }
.orb .orb-val small { font-size: 0.62em; font-weight: 600; opacity: 0.85; }
.orb .orb-name { position: absolute; z-index: 1; bottom: 16%; left: 0; right: 0; text-align: center; font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: #fff; text-shadow: 0 1px 2px #000; }
body.kit .action-bar.touch { left: 50%; right: auto; transform: translateX(-50%); } /* centred between the globes on touch too */
@media (max-height: 430px) and (orientation: landscape) { .orb { --globe: 86px; } }

/* ---------------- Desktop bar as one unit (owner, 2026-11-10) ----------------
   Mouse and keyboard: the health globe sits at the left end of the action bar and the stamina globe at the right end, all
   three together at the bottom centre. The bar's width is worked out from its slots (five of --bar-s, Attack a quarter
   larger, five 6px gaps, 7px padding and the border), so the globes can be placed from the centre without a wrapper.
   Phones keep their own layout: everything here is fenced off from .touch / body.touch-ui. */
body { --bar-s: clamp(50px, 7.2vw, 62px); --bar-w: calc(var(--bar-s) * 6.25 + 46px); }
.action-bar:not(.touch) { --s: var(--bar-s); }
body:not(.touch-ui) .orb { --globe: clamp(88px, 9vw, 124px); bottom: calc(6px + var(--safe-b)); }
body:not(.touch-ui) .orb.hp { left: auto; right: calc(50% + var(--bar-w) / 2 + 14px); }
body:not(.touch-ui) .orb.st { right: auto; left: calc(50% + var(--bar-w) / 2 + 14px); }
@media (max-width: 620px) { body:not(.touch-ui) .orb { --globe: 76px; } }
@media (max-height: 430px) and (orientation: landscape) { body:not(.touch-ui) .orb { --globe: 84px; } }
@media (orientation: portrait) and (max-width: 560px) { body { --bar-s: 50px; --bar-w: 174px; } body:not(.touch-ui) .orb { --globe: 78px; } } /* the 2 x 3 grid above */
/* Key hints: a small plate at the foot of each slot; the mouse buttons are drawn (bar-tips.js mouseGlyph). */
.action-bar:not(.touch) .slot > svg { margin-top: -16%; }
.action-bar:not(.touch) .slot .key { top: auto; bottom: 2px; left: 50%; transform: translateX(-50%); z-index: 1; display: grid; place-items: center; min-width: 16px; height: 15px; padding: 0 4px;
  border: 1px solid #5a4e3a; border-radius: 4px; background: rgba(10, 8, 5, 0.8); font-size: 10px; line-height: 1; white-space: nowrap; color: #f0c27a; }
.action-bar .slot .key svg { display: block; width: 9px; height: 12px; margin: 0; stroke-width: 1.2; }
.action-bar .slot .key svg .on { fill: currentColor; stroke: none; }
body.pad-on .action-bar:not(.touch) .slot .key { bottom: auto; transform: none; min-width: 0; padding: 0; border: 0; border-radius: 0; }
body.pad-on .action-bar .slot .key svg { display: none; }
/* A slot's card: what it is and does, under the mouse or the keyboard focus (expedition.js places it; never on touch). */
.slot-tip { position: fixed; z-index: 9; left: 0; top: 0; width: max-content; max-width: min(320px, calc(100vw - 16px)); padding: 10px 12px; pointer-events: none; text-align: left;
  border: 1px solid #8a7550; border-radius: 8px; background: rgba(22, 19, 14, 0.97); box-shadow: 0 8px 22px rgba(0, 0, 0, 0.6); color: var(--text); font-size: calc(14px * var(--ts, 1)); line-height: 1.35; }
.slot-tip[hidden], .action-bar[hidden] ~ .slot-tip, body.in-hall .slot-tip, body.title-live .slot-tip { display: none; }
.slot-tip .tip-name { display: block; font-size: calc(16px * var(--ts, 1)); color: #f0c27a; }
.slot-tip p { margin: 4px 0 0; }
.slot-tip dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; margin: 8px 0 0; padding-top: 8px; border-top: 1px solid var(--line); }
.slot-tip dt { color: var(--muted); }
.slot-tip dd { margin: 0; }

/* ---------------- Inventory (candidate note n3) ----------------
   Hero with equipped slots and stats | bag grid of item tiles | selected item. Stacks on narrow screens. */
.inv { display: flex; flex-direction: column; height: 100%; gap: 8px; }
.inv-head { display: flex; align-items: center; gap: 10px; }
.inv-head h2 { margin: 0; }
.inv-head #gBack { margin-left: auto; min-height: 44px; }
.inv-head .gold { font-variant-numeric: tabular-nums; }
.inv-status { margin: 0; font-size: calc(14px * var(--ts, 1)); }
.inv-body { flex: 1; min-height: 0; display: grid; grid-template-columns: 250px 1fr 300px; gap: 12px; }
.inv-body > section { min-height: 0; overflow: auto; border: 1px solid var(--line); border-radius: 10px; padding: 10px; background: rgba(0, 0, 0, 0.18); }
.doll { position: relative; height: 230px; }
.doll .hero { position: absolute; left: 50%; top: 6px; height: 210px; transform: translateX(-50%); fill: #2c2720; stroke: #4a4030; stroke-width: 2; }
.doll .eq { position: absolute; display: grid; justify-items: center; gap: 2px; }
.doll .eq-name { font-size: calc(11px * var(--ts, 1)); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.inv-stats { margin: 6px 0 0; display: grid; gap: 4px; font-size: calc(13px * var(--ts, 1)); }
.inv-stats div { display: flex; justify-content: space-between; gap: 8px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); padding: 2px 0; }
.inv-stats dt { color: var(--muted); }
.inv-stats dd { margin: 0; text-align: right; }
.inv-bag .chips { margin-bottom: 8px; }
.bag-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 6px; }
.tile { position: relative; width: 54px; height: 54px; padding: 0; display: grid; place-items: center; border-radius: 8px; cursor: pointer;
  border: 2px solid var(--rc, #4a4030); background: radial-gradient(circle at 50% 35%, #34302a, #16130f 80%); color: #e8dcc0; }
.tile img.osrs-icon { width: 46px; height: auto; image-rendering: pixelated; }
.tile svg { width: 30px; height: 30px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tile .mark { position: absolute; right: 3px; bottom: 1px; font-size: 10px; font-weight: 700; color: var(--rc, #888); }
.tile.empty { cursor: default; border: 1px dashed #3a332a; background: rgba(0, 0, 0, 0.25); }
.tile.selected { box-shadow: 0 0 0 3px var(--accent); }
.tile.large { width: 64px; height: 64px; min-width: 64px; flex: none; cursor: default; }
.tile.r-common { --rc: #bdb6a6; } .tile.r-uncommon { --rc: #6fbf73; } .tile.r-rare { --rc: #5b8fd9; } .tile.r-epic { --rc: #b07ad6; }
/* Buy back: the last items sold, in the bag's place. One row an item: what it is, then its button and (if it cannot be used) why. */
.tile.static { cursor: default; flex: none; }
.buy-back .bb-note { margin: 0 0 8px; font-size: calc(13px * var(--ts, 1)); }
.buy-back .bb-none { margin: 12px 0; }
.buy-back .bb-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.buy-back .bb-row { display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 6px 10px; align-items: start; padding: 8px; border-radius: 8px; background: rgba(0, 0, 0, 0.25); border: 1px solid #3a332a; }
.buy-back .bb-what { min-width: 0; font-size: calc(14px * var(--ts, 1)); }
.buy-back .bb-lines, .buy-back .bb-trait { font-size: calc(12px * var(--ts, 1)); margin-top: 2px; }
.buy-back .bb-act { grid-column: 1 / -1; }
.buy-back .bb-act button { width: 100%; min-height: 44px; }
.buy-back .bb-act button[disabled] { opacity: 0.45; cursor: default; }
.buy-back .bb-why { margin: 4px 0 0; font-size: calc(12px * var(--ts, 1)); }
.inv-detail .detail-head { display: flex; gap: 10px; align-items: center; margin-bottom: 6px; }
.inv-detail .lines { margin: 6px 0; padding-left: 18px; font-size: calc(14px * var(--ts, 1)); }
.inv-detail h4 { margin: 10px 0 4px; font-size: calc(13px * var(--ts, 1)); color: var(--muted); }
.inv-detail .chips { margin-top: 10px; }
.inv-detail .chips button { min-height: 44px; }
.inv-detail .small { font-size: calc(12px * var(--ts, 1)); margin-top: 6px; }
@media (max-width: 860px) {
  .inv { height: auto; flex: 1; }
  .inv-body { grid-template-columns: 1fr; grid-template-rows: auto auto 1fr; }
  .inv-body > .inv-bag { align-self: stretch; }
  .inv-body > section { overflow: visible; }
  .inv-char { display: grid; grid-template-columns: 170px 1fr; gap: 8px; align-items: start; }
  .doll { height: 200px; }
  .doll .hero { height: 180px; }
  .inv-detail { order: -1; }
}

/* The hero between two columns of equipped slots: weapon on the left, amulet and armor on the right (no overlap at any width). */
.doll { position: static; height: auto; display: grid; grid-template-columns: 64px 1fr 64px; grid-template-rows: auto auto; gap: 8px 6px; align-items: center; justify-items: center; }
.doll .hero { position: static; transform: none; grid-column: 2; grid-row: 1 / span 2; height: 190px; width: 100%; max-width: 120px; }
.doll .eq { position: static; transform: none; }
.doll .eq.weapon { grid-column: 1; grid-row: 1 / span 2; }
.doll .eq.amulet { grid-column: 3; grid-row: 1; }
.doll .eq.chest { grid-column: 3; grid-row: 2; }
@media (max-width: 860px) {
  .inv-char { grid-template-columns: 220px 1fr; }
  .doll .hero { height: 160px; }
}
@media (max-width: 520px) { .inv-char { grid-template-columns: 1fr; } }

/* Phone portrait review: the boss bar stays one line tall, and a critical boss/hazard call outranks routine messages
   (tips, toasts, pickups wait underneath while it shows) instead of covering them. */
body.kit #bossBar .boss-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 520px) { body.kit #bossBar .boss-name .muted { display: none; } body.kit #bossBar .boss-name { font-size: 15px; } }
#alert { top: max(96px, calc(50% - 130px)); }
body.alerting #hudStack #toast, body.alerting #hudStack #pickup, body.alerting #hudStack #tip, body.alerting #hudStack #objective { visibility: hidden; }

/* ---------------- Touch layout (owner, 2026-11-09: MOBA-style thumb arc) ----------------
   Phones: a large round Attack in the bottom-right corner with the other actions on an arc around it, in thumb reach.
   Health and stamina sit side by side at the bottom centre, where the moving left thumb does not cover them.
   Desktop keeps the centred bar with a globe at either end. */
body.kit .action-bar.touch {
  left: auto; right: calc(10px + var(--safe-r)); bottom: calc(10px + var(--safe-b)); transform: none;
  --a: 92px; --k: 58px; --r: 160px; width: calc(var(--a) / 2 + var(--r) + var(--k) / 2 + 4px); height: calc(var(--a) / 2 + var(--r) + var(--k) / 2 + 4px);
  padding: 0; background: none; border: none; box-shadow: none; display: block; pointer-events: none;
}
body.kit .action-bar.touch .slots { display: block; position: relative; width: 100%; height: 100%; }
body.kit .action-bar.touch .slot {
  position: absolute; width: var(--k); height: var(--k); border-radius: 50%; pointer-events: auto;
  right: calc(var(--a) / 2 - var(--r) * cos(var(--ang)) - var(--k) / 2); bottom: calc(var(--a) / 2 + var(--r) * sin(var(--ang)) - var(--k) / 2);
  border-width: 2px; background: radial-gradient(circle at 50% 35%, rgba(70, 60, 45, 0.92), rgba(24, 20, 15, 0.92) 75%);
}
body.kit .action-bar.touch .slot.attack { --s2: var(--a); width: var(--a); height: var(--a); right: 0; bottom: 0; }
body.kit .action-bar.touch .slot.dodge { --ang: 180deg; }
body.kit .action-bar.touch .slot.whirl { --ang: 157.5deg; }
body.kit .action-bar.touch .slot.rush { --ang: 135deg; }
body.kit .action-bar.touch .slot.guard { --ang: 112.5deg; }
body.kit .action-bar.touch .slot.heal { --ang: 90deg; }
body.kit .action-bar.touch .slot .name { font-size: 9px; bottom: 5px; }
body.kit .action-bar.touch .slot svg { width: 50%; height: 50%; margin-top: -14%; }
body.kit .action-bar.touch .slot.attack svg { width: 54%; height: 54%; }
body.touch-ui .orb { --globe: 66px; bottom: calc(8px + var(--safe-b)); }
body.touch-ui .orb.hp { left: calc(50% - 72px); right: auto; }
body.touch-ui .orb.st { left: calc(50% + 6px); right: auto; }
body.touch-ui .orb .orb-val { font-size: 15px; }
body.touch-ui .orb .orb-name { font-size: 8px; bottom: 13%; }
body.kit.touch-ui .act.interact { bottom: calc(86px + var(--safe-b)); max-width: min(340px, calc(100vw - 32px)); }
@media (orientation: portrait) {
  /* Narrow screens: the arc is a little tighter and the globes sit just above it, still centred. */
  body.kit .action-bar.touch { --a: 80px; --k: 50px; --r: 148px; }
  body.touch-ui .orb { bottom: calc(242px + var(--safe-b)); }
  body.kit.touch-ui .act.interact { bottom: calc(318px + var(--safe-b)); }
}
body.kit .action-bar.touch .slot .cost { top: 5px; right: auto; left: 50%; transform: translateX(-50%); font-size: 10px; } /* inside the round button, not clipped at its edge */
body.kit .action-bar.touch .slot svg { margin-top: 6%; width: 44%; height: 44%; }
body.kit .action-bar.touch .slot.attack svg { margin-top: 0; width: 50%; height: 50%; }
body.kit .action-bar.touch .slot .pips { top: 9px; right: auto; left: 50%; transform: translateX(-50%); }

/* ---------------- Touch combat pad (owner sketch, 2026-11-09) ----------------
   Phones: Attack, Dodge and Guard are segments of one big circle in the bottom-right corner (Attack the large lower part,
   Dodge upper-left, Guard upper-right), so the three most-used actions are one thumb slide apart. Heal, Whirlcut and Shield
   Rush sit around it (the sketch's positions 1-3; position 4 is free). Segments are clipped so each one's touch area is
   exactly its drawn shape. Overrides the earlier arc. */
body.kit .action-bar.touch { --B: 180px; --k: 58px; --R: calc(var(--B) / 2 + var(--k) / 2 + 12px);
  width: calc(var(--B) + var(--k) + 40px); height: calc(var(--B) + var(--k) + 40px); }
body.kit .action-bar.touch .slot.attack, body.kit .action-bar.touch .slot.dodge, body.kit .action-bar.touch .slot.guard {
  --ang: 0deg; right: 0; bottom: 0; width: var(--B); height: var(--B); border-radius: 0; border: none; box-shadow: none; display: block; }
body.kit .action-bar.touch .slot.attack { clip-path: polygon(100.0% 50.0%, 99.9% 53.3%, 99.6% 56.5%, 99.0% 59.8%, 98.3% 62.9%, 97.3% 66.1%, 96.2% 69.1%, 94.8% 72.1%, 93.3% 75.0%, 91.6% 77.8%, 89.7% 80.4%, 87.6% 83.0%, 85.4% 85.4%, 83.0% 87.6%, 80.4% 89.7%, 77.8% 91.6%, 75.0% 93.3%, 72.1% 94.8%, 69.1% 96.2%, 66.1% 97.3%, 62.9% 98.3%, 59.8% 99.0%, 56.5% 99.6%, 53.3% 99.9%, 50.0% 100.0%, 46.7% 99.9%, 43.5% 99.6%, 40.2% 99.0%, 37.1% 98.3%, 33.9% 97.3%, 30.9% 96.2%, 27.9% 94.8%, 25.0% 93.3%, 22.2% 91.6%, 19.6% 89.7%, 17.0% 87.6%, 14.6% 85.4%, 12.4% 83.0%, 10.3% 80.4%, 8.4% 77.8%, 6.7% 75.0%, 6.0% 73.8%, 87.4% 16.8%, 87.6% 17.0%, 89.7% 19.6%, 91.6% 22.2%, 93.3% 25.0%, 94.8% 27.9%, 96.2% 30.9%, 97.3% 33.9%, 98.3% 37.1%, 99.0% 40.2%, 99.6% 43.5%, 99.9% 46.7%); background: radial-gradient(circle at 66% 70%, rgba(92, 72, 40, 0.95), rgba(34, 26, 16, 0.95) 70%); }
body.kit .action-bar.touch .slot.dodge { clip-path: polygon(6.0% 73.8%, 5.2% 72.1%, 3.8% 69.1%, 2.7% 66.1%, 1.7% 62.9%, 1.0% 59.8%, 0.4% 56.5%, 0.1% 53.3%, 0.0% 50.0%, 0.1% 46.7%, 0.4% 43.5%, 1.0% 40.2%, 1.7% 37.1%, 2.7% 33.9%, 3.8% 30.9%, 5.2% 27.9%, 6.7% 25.0%, 8.4% 22.2%, 10.3% 19.6%, 12.4% 17.0%, 14.6% 14.6%, 17.0% 12.4%, 19.6% 10.3%, 22.2% 8.4%, 25.0% 6.7%, 27.9% 5.2%, 29.4% 4.5%, 43.0% 47.9%); background: rgba(40, 52, 62, 0.94); }
body.kit .action-bar.touch .slot.guard { clip-path: polygon(29.4% 4.5%, 30.9% 3.8%, 33.9% 2.7%, 37.1% 1.7%, 40.2% 1.0%, 43.5% 0.4%, 46.7% 0.1%, 50.0% 0.0%, 53.3% 0.1%, 56.5% 0.4%, 59.8% 1.0%, 62.9% 1.7%, 66.1% 2.7%, 69.1% 3.8%, 72.1% 5.2%, 75.0% 6.7%, 77.8% 8.4%, 80.4% 10.3%, 83.0% 12.4%, 85.4% 14.6%, 87.4% 16.8%, 43.0% 47.9%); background: rgba(44, 58, 46, 0.94); }
body.kit .action-bar.touch .slot.attack, body.kit .action-bar.touch .slot.dodge, body.kit .action-bar.touch .slot.guard { --icx: 50%; --icy: 50%; }
body.kit .action-bar.touch .slot.attack { --icx: 64%; --icy: 66%; }
body.kit .action-bar.touch .slot.dodge { --icx: 19%; --icy: 44%; }
body.kit .action-bar.touch .slot.guard { --icx: 60%; --icy: 17%; }
body.kit .action-bar.touch .slot.attack svg, body.kit .action-bar.touch .slot.dodge svg, body.kit .action-bar.touch .slot.guard svg {
  position: absolute; left: var(--icx); top: var(--icy); transform: translate(-50%, -60%); margin: 0; width: 34px; height: 34px; }
body.kit .action-bar.touch .slot.attack svg { width: 46px; height: 46px; }
body.kit .action-bar.touch .slot.attack .name, body.kit .action-bar.touch .slot.dodge .name, body.kit .action-bar.touch .slot.guard .name {
  position: absolute; left: var(--icx); top: calc(var(--icy) + 14px); right: auto; bottom: auto; transform: translateX(-50%); width: auto; }
body.kit .action-bar.touch .slot.attack .name { top: calc(var(--icy) + 20px); }
body.kit .action-bar.touch .slot.dodge .cost, body.kit .action-bar.touch .slot.guard .cost { left: var(--icx); top: calc(var(--icy) - 34px); }
body.kit .action-bar.touch .slot.attack .pips { left: var(--icx); top: calc(var(--icy) - 38px); }
body.kit .action-bar.touch .slot.dodge .cdtext, body.kit .action-bar.touch .slot.guard .cdtext { position: absolute; left: var(--icx); top: var(--icy); transform: translate(-50%, -50%); }
body.kit .action-bar.touch .pad-lines { display: block; position: absolute; right: 0; bottom: 0; width: var(--B); height: var(--B); pointer-events: none; z-index: 2; }
.pad-lines { display: none; }
.pad-lines circle { fill: none; stroke: #8a7550; stroke-width: 1.6; }
.pad-lines line { stroke: #c9b07a; stroke-width: 1.2; stroke-opacity: 0.8; }
body.kit .action-bar.touch .slot.heal { --ang: 193deg; }
body.kit .action-bar.touch .slot.whirl { --ang: 141deg; }
body.kit .action-bar.touch .slot.rush { --ang: 87deg; }
body.kit .action-bar.touch .slot.heal, body.kit .action-bar.touch .slot.whirl, body.kit .action-bar.touch .slot.rush {
  right: calc(var(--B) / 2 - var(--R) * cos(var(--ang)) - var(--k) / 2); bottom: calc(var(--B) / 2 + var(--R) * sin(var(--ang)) - var(--k) / 2); }
@media (orientation: portrait) { body.kit .action-bar.touch { --B: 172px; --k: 54px; } }

/* Phones: health and stamina as bars at the bottom centre (owner), not globes. */
body.touch-ui .orb { --globe: auto; width: min(240px, 34vw); height: 22px; border-radius: 6px; border-width: 2px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
  left: 50% !important; right: auto !important; transform: translateX(-50%); display: flex; align-items: center; justify-content: flex-end; padding: 0 8px; }
body.touch-ui .orb.hp { bottom: calc(36px + var(--safe-b)); }
body.touch-ui .orb.st { bottom: calc(8px + var(--safe-b)); }
body.touch-ui .orb .liquid { top: 0; bottom: 0; right: auto; height: 100%; width: var(--fill, 100%); transition: width 0.15s linear; }
body.touch-ui .orb .glass { border-radius: 4px; background: linear-gradient(rgba(255, 255, 255, 0.18), transparent 55%); }
body.touch-ui .orb .orb-name { position: absolute; left: 8px; right: auto; bottom: auto; top: 50%; transform: translateY(-50%); font-size: 10px; text-align: left; }
body.touch-ui .orb .orb-val { font-size: 13px; margin: 0; }
body.kit.touch-ui .act.interact { bottom: calc(70px + var(--safe-b)); }
@media (orientation: portrait) {
  body.touch-ui .orb { width: min(260px, 66vw); }
  body.touch-ui .orb.hp { bottom: calc(318px + var(--safe-b)); }
  body.touch-ui .orb.st { bottom: calc(290px + var(--safe-b)); }
  body.kit.touch-ui .act.interact { bottom: calc(350px + var(--safe-b)); }
}
body.kit .action-bar.touch .slot.guard .cost { left: calc(var(--icx) + 28px); top: calc(var(--icy) - 6px); } /* beside the shield: the segment is shallow at the top */

/* Owner, phone run: tips are quieter (smaller, short), and on phones the boss call sits just under the boss bar instead of
   the middle of the screen. */
#hudStack #tip { font-size: calc(13px * var(--ts, 1)); padding: 6px 8px 6px 10px; gap: 6px; max-width: min(380px, 100%); }
#hudStack #tip button { min-height: 40px; padding: 4px 10px; font-size: calc(13px * var(--ts, 1)); }
body.touch-ui #alert { top: calc(70px + var(--safe-t)); transform: translateX(-50%); font-size: calc(15px * var(--ts, 1)); padding: 6px 12px; border-width: 1px; max-width: min(460px, calc(100vw - 180px)); }
body.touch-ui.boss #alert { top: calc(76px + var(--safe-t)); }
body.touch-ui #bossBar #bossChannel span { display: none; } /* the call above says it; the bar keeps the progress */

/* Owner: the action buttons are icons only (names stay as aria-labels for screen readers). */
.action-bar .slot .name { display: none; }
.action-bar .slot svg { margin-top: 0; }
body.kit .action-bar.touch .slot svg { margin-top: 0; }
body.kit .action-bar.touch .slot.attack svg, body.kit .action-bar.touch .slot.dodge svg, body.kit .action-bar.touch .slot.guard svg { transform: translate(-50%, -50%); }
.action-bar .slot .cost { display: none; } /* icons and cooldowns only; a refused press still says why */
.action-bar .slot .cdtext { font-size: 20px; font-weight: 800; text-shadow: 0 1px 3px #000; }

/* Live hero in the inventory (owner decision): the Knight model turns in the space between the equipped slots. */
.doll .hero-slot { grid-column: 2; grid-row: 1 / span 2; width: 100%; max-width: 160px; height: 200px; display: grid; place-items: center; }
.doll .hero-slot .hero { grid-column: auto; grid-row: auto; height: 180px; }
.doll .hero-slot .hero3d { width: 100%; height: 100%; display: block; }
.inv.in-camp { height: auto; }
.inv.in-camp .inv-body > section { max-height: none; }
.doll .hero-slot { max-width: none; min-width: 0; overflow: hidden; } /* the turning hero stays inside its column */

/* Generated runs: door promise icon (#59). */
#cardBody .reward-icon { color: var(--accent); }
#cardBody .reward-icon svg { width: 0.95em; height: 0.95em; vertical-align: -0.12em; }
/* A door to a chamber that asks for something else (asks.js): the word and what it means, said in the card's own text. */
#cardBody .door-ask { font-weight: 600; }

/* Review R5: abandoning a reward or spring at a one-way door. */
#cardBody .left-behind { text-align: left; margin: 0 auto; padding-left: 20px; }
#cardBody .card-actions.stack-actions { flex-wrap: wrap; }
/* Review R4: while a profile change is saving, its controls can't start another one. */
body.saving, body.saving * { pointer-events: none !important; }
body.saving .inv button[data-equip], body.saving .inv button[data-discard], body.saving .inv button[data-sell], body.saving .menu-action .primary { pointer-events: none; opacity: 0.5; }

/* Notebook: add a note to its run report (#71 review R3); a full-height touch row. */
label.check { display: flex; align-items: center; gap: 10px; min-height: 44px; font-size: calc(14px * var(--ts, 1)); }
label.check input { width: 22px; height: 22px; }

/* Cards in a run: a disclosure is a touch target like any other. */
#cardBody details > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; color: var(--brass); }
#cardBody summary:focus-visible { outline: 3px solid #91d1bd; outline-offset: 3px; }
/* The flex row drops the native triangle, so open or closed is said with a sign. */
#cardBody details > summary::before { content: "+"; display: inline-block; width: 1.1em; font-weight: 700; }
#cardBody details[open] > summary::before { content: "-"; }

/* Badly hurt: the vignette closes in red and breathes (still under reduced motion). The health bar and number carry the fact. */
body.low-health.low-health #vignette { display: block; background: radial-gradient(ellipse 78% 72% at 50% 50%, transparent 46%, rgba(120, 14, 10, 0.5) 100%); animation: lowHealthPulse 1.4s ease-in-out infinite; }
@keyframes lowHealthPulse { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { body.low-health.low-health #vignette { animation: none; } }

/* A tip about a skill points at its button: a second ring that breathes around it (a still, brighter button under reduced motion). */
.action-bar .slot.tip-here { outline: 3px solid #f3e6c4; outline-offset: 3px; animation: tipHere 1.1s ease-in-out infinite; }
@keyframes tipHere { 0%, 100% { outline-offset: 3px; filter: brightness(1); } 50% { outline-offset: 7px; filter: brightness(1.7); } } /* the touch buttons are clipped to their shapes, where an outline cannot show: there the button itself brightens */
@media (prefers-reduced-motion: reduce) { .action-bar .slot.tip-here { animation: none; filter: brightness(1.5); } }

/* A long card's deciding row (any hall card that ends in its buttons) stays at the bottom of the card as it scrolls (the stair, once a hero has a great deal to
   choose): the buttons that act are never a scroll away. A line above it and the card's own ground behind it. */
#cardBody > .chips:last-child, #cardBody .card-stick { position: sticky; bottom: 0; z-index: 2; margin: 0 calc(-1 * var(--card-pad-x, 20px)) calc(-1 * var(--card-pad-b, 20px)); padding: 12px var(--card-pad-x, 20px) calc(14px + var(--safe-b, 0px));
  background: #1a1712; border-top: 1px solid #4a4030; border-radius: 0 0 16px 16px; }

/* Links inside the camp screens (Save and backup: the privacy and terms pages) read as text, underlined. */
.camp a { color: inherit; text-decoration: underline; }

/* The Saving mark (campaign.js saveMark): cloud save only, in the hall and the camp, never during a descent. It sits in
   a corner, takes no input and covers nothing that can be pressed through it. The word carries the meaning; the turning
   ring is only a ring, and it stands still for anyone who asked for less motion. */
#saveMark {
  position: fixed; z-index: 16; left: calc(10px + var(--safe-l, 0px)); bottom: calc(66px + var(--safe-b));
  display: flex; align-items: center; gap: 8px; max-width: min(340px, calc(100vw - 20px)); box-sizing: border-box;
  padding: 7px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); color: var(--text);
  font-size: calc(13px * var(--ts, 1)); line-height: 1.3; pointer-events: none;
}
#saveMark[hidden] { display: none; }
.spoken-only { position: fixed; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
#saveMark .save-glyph { flex: none; width: 12px; height: 12px; box-sizing: border-box; border: 2px solid var(--muted); border-radius: 50%; }
#saveMark[data-state="saving"] .save-glyph { border-top-color: var(--brass); animation: saveTurn 0.9s linear infinite; }
#saveMark[data-state="saved"] .save-glyph { width: 7px; height: 12px; border: solid var(--brass); border-width: 0 2px 2px 0; border-radius: 0; transform: rotate(45deg) translate(-1px, -2px); }
#saveMark[data-state="failed"] { border-color: #7a3a2e; }
#saveMark[data-state="failed"] .save-glyph { width: 12px; height: 2px; border: 0; border-radius: 0; background: #f1b2a8; }
/* The new version notice (campaign.js updateNote): at the title and in the hall, never during a descent. Words and one
   button; it reloads nothing by itself. */
#updateNote {
  position: fixed; z-index: 39; left: 50%; top: calc(8px + var(--safe-t)); transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px; width: max-content; max-width: calc(100vw - 20px); box-sizing: border-box;
  padding: 6px 6px 6px 14px; border: 1px solid var(--accent); border-radius: 8px; background: var(--panel); color: var(--text);
  font-size: calc(14px * var(--ts, 1)); line-height: 1.3;
}
#updateNote[hidden] { display: none; }
#updateNote .chip { flex: none; }
/* On a narrow screen the top row is the quest line and the menu button, with the small map under them: the notice sits below those. */
@media (max-width: 900px) { #updateNote { top: calc(196px + var(--safe-t)); } }
/* At the title the top of the screen is the game's name, so the notice sits at the foot there. The menu has no free
   edge (tabs along the top, a page that scrolls under the foot), so it waits until the menu is shut. */
#front:not([hidden]) ~ #updateNote { top: auto; bottom: calc(56px + var(--safe-b)); }
#hub:not([hidden]) ~ #updateNote { display: none; }
@keyframes saveTurn { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { #saveMark[data-state="saving"] .save-glyph { animation: none; } }

/* The loot card (loot-plan.js): one card wherever gear is found or offered. The item, then the change against what is
   worn as rows of name, signed number and a word with a drawn mark (never colour alone), then its actions, largest
   first. It sits inside the centred card, the stall's offers and the choice as a descent ends. */
.loot { display: grid; gap: 8px; text-align: left; padding: 10px; border: 1px solid var(--line); border-left: 4px solid var(--rc, var(--line)); border-radius: 10px; background: rgba(0, 0, 0, 0.18); font-size: calc(14px * var(--ts, 1)); min-width: 0; }
.loot.r-common { --rc: #bdb6a6; } .loot.r-uncommon { --rc: #6fbf73; } .loot.r-rare { --rc: #5b8fd9; } .loot.r-epic { --rc: #b07ad6; }
.loot p { margin: 0; }
.loot-head { display: flex; gap: 10px; align-items: center; min-width: 0; }
.loot-what { display: grid; gap: 2px; min-width: 0; }
.loot-name { font-size: calc(17px * var(--ts, 1)); overflow-wrap: anywhere; }
.loot-kind, .loot-style { color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
.loot .style-line, .loot .gate-line, .loot .named-line, .loot .named-status { margin: 0; }
.loot-compare { display: grid; gap: 4px; padding-top: 8px; border-top: 1px solid var(--line); }
.loot-vs { color: var(--muted); font-size: calc(13px * var(--ts, 1)); overflow-wrap: anywhere; }
.loot-verdict { font-weight: 700; overflow-wrap: anywhere; }
.loot-rows, .loot-own { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.loot-own { color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
#cardBody .loot-rows li, .loot-rows li { color: var(--text); }
.loot-rows li { display: grid; grid-template-columns: 1fr auto minmax(4.6em, auto); gap: 10px; align-items: baseline; padding: 3px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
.loot-rows .lr-delta { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.loot-rows .lr-word { white-space: nowrap; }
.loot-rows .good .lr-delta, .loot-rows .good .lr-word { color: #a9dbb2; }
.loot-rows .bad .lr-delta, .loot-rows .bad .lr-word { color: #f1b2a8; }
.lr-mark { display: inline-block; width: 0; height: 0; margin-right: 5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 8px solid currentColor; }
.bad .lr-mark { border-bottom: 0; border-top: 8px solid currentColor; }
.loot .named-changes { margin: 2px 0; }
.loot details > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
.loot details .diff { margin: 0 0 4px; }
.loot-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.loot-actions button { flex: 1 1 96px; min-height: 48px; padding: 6px 10px; font-size: calc(15px * var(--ts, 1)); }
.loot-actions .loot-main { flex: 1 0 100%; min-height: 52px; font-size: calc(17px * var(--ts, 1)); font-weight: 700; background: #3a2a14; }
.loot-actions button[aria-disabled="true"], #cardBody [data-buy][aria-disabled="true"] { opacity: 0.45; cursor: default; }
.loot-actions button:focus-visible { outline: 3px solid #91d1bd; outline-offset: 2px; }
.loot-why { color: #f1b2a8; font-size: calc(13px * var(--ts, 1)); }
.loot-actions .loot-why { flex: 1 0 100%; }
.loot-rows.loot-full li { grid-template-columns: 1fr auto auto minmax(4.6em, auto); }
.loot-rows .lr-from { color: var(--muted); font-size: calc(12px * var(--ts, 1)); white-space: nowrap; }
.loot-nochange { color: var(--muted); font-size: calc(13px * var(--ts, 1)); }
#cardBody .loot ~ .wide + .wide { margin-top: 6px; } /* the stall: Buy under Buy and equip */
.screen.run .cards.loot-choice { align-items: start; grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr)); }
/* With room beside it (a desktop, a phone on its side) the card widens and the comparison stands next to the item, so the
   buttons are in view without scrolling. On a short screen they share one row. */
@media (min-width: 760px) {
  .center-card:has(> #cardBody > .loot) { width: min(720px, calc(100vw - 32px)); }
  #cardBody > .loot { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 16px; align-items: start; }
  #cardBody > .loot > * { grid-column: 1; }
  #cardBody > .loot > .loot-compare { grid-column: 2; grid-row: 1 / span 4; padding-top: 0; border-top: 0; }
  #cardBody > .loot > .loot-actions, #cardBody > .loot > .loot-why { grid-column: 1 / -1; }
}
@media (min-width: 760px) and (max-height: 430px) {
  #cardBody > .loot > .loot-actions { flex-wrap: wrap; }
  #cardBody > .loot > .loot-actions button { flex: 1 1 0; }
  #cardBody > .loot .loot-actions .loot-main { flex: 2 1 0; min-height: 48px; }
  .center-card:has(> #cardBody > .loot) .card-art { display: none; }
  .center-card:has(> #cardBody > .loot) #cardBody h2 { font-size: calc(17px * var(--ts, 1)); }
  #cardBody > .loot { padding: 8px 10px; }
  #cardBody > .loot .loot-rows li { padding: 1px 0; }
  #cardBody > .loot .tile.large { width: 54px; height: 54px; min-width: 54px; }
}
/* One item on the card: its buttons stay in view while the rest scrolls under them (large text, a short screen). */
#cardBody > .loot:only-of-type > .loot-actions { position: sticky; bottom: 0; z-index: 2; margin: 0 -10px -10px; padding: 8px 10px 10px; background: #1a1712; border-top: 1px solid #4a4030; border-radius: 0 0 8px 8px; }
.loot-choice .loot { background: var(--panel); }

/* ---------------- Assisted combat controls (assist-plan.js) ----------------
   A slot that acts by itself carries the word "Auto" (the attack reads "Held" while fire is held): a word, with a
   solid plate for Auto and a dashed outline for Held, so it is never told by color alone. The word is 11px, dark on
   light for Auto and light on dark for Held. The button under the objective says the same of the attack and switches
   it. Nothing here shows in Manual: the words are empty and the button is hidden. */
.action-bar .slot .auto { position: absolute; top: 0; right: 0; z-index: 2; padding: 0 3px; border-radius: 0 8px 0 5px; font-size: 11px; font-weight: 800; line-height: 14px;
  letter-spacing: 0.03em; text-transform: uppercase; color: #17140f; background: #f0c27a; border: 1px solid #f0c27a; pointer-events: none; }
.action-bar .slot .auto:empty { display: none; }
.action-bar .slot .auto.held { color: #f0c27a; background: #17140f; border-style: dashed; }
/* Keys and mouse: the word is tucked into the slot's top right corner, and the icon gives it a little room. */
.action-bar:not(.touch) .slot:has(.auto:not(:empty)) > svg { transform: translate(-2px, 2px); }
/* Touch: the slots are round and the three large ones are cut to the pad's shape, so a word in a corner would be cut off.
   On a cut slot it sits by the icon, inside the shape: under the sword, and beside the shield (that segment narrows
   downward, so the shield moves over to make room). On a small round slot it sits across the bottom rim, and the slot
   lets it show past its edge. */
body.kit .action-bar.touch .slot .auto { top: calc(var(--icy, 50%) + 15px); right: auto; left: var(--icx, 50%); transform: translateX(-50%); padding: 0 2px; border-radius: 3px; letter-spacing: 0.02em; }
body.kit .action-bar.touch .slot.whirl, body.kit .action-bar.touch .slot.rush { overflow: visible; }
body.kit .action-bar.touch .slot.whirl .auto, body.kit .action-bar.touch .slot.rush .auto { top: auto; bottom: -5px; }
body.kit .action-bar.touch .slot.attack .auto { top: calc(var(--icy) + 25px); }
body.kit .action-bar.touch .slot.guard:has(.auto:not(:empty)) { --icx: 50%; }
body.kit .action-bar.touch .slot.guard .auto { top: calc(var(--icy) - 10px); left: calc(var(--icx) + 20px); transform: none; }
#hudStack .assist-bar { color: #17140f; background: #f0c27a; border-color: #f0c27a; }
#hudStack .assist-bar::before { content: ""; display: inline-block; width: 9px; height: 9px; margin-right: 7px; border-radius: 50%; background: #17140f; vertical-align: 1px; }
#hudStack .assist-bar.held { color: #f0c27a; background: rgba(22, 20, 15, 0.86); border-style: dashed; }
#hudStack .assist-bar.held::before { width: 3px; height: 10px; border-radius: 0; background: #f0c27a; box-shadow: 6px 0 0 #f0c27a; margin-right: 13px; } /* two bars: held */
.slot-tip .tip-auto { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.slot-tip .tip-auto b { display: inline-block; margin-right: 4px; padding: 0 5px; border-radius: 3px; font-size: 0.85em; letter-spacing: 0.04em; text-transform: uppercase; color: #17140f; background: #f0c27a; }

/* Report a problem (report-issue.js): a sheet over the menu. The line that says a report is public is set apart by a
   rule down its side and its own weight, not by color alone. */
.sheet .ri { display: grid; gap: 8px; }
.sheet .ri h2 { margin: 0; }
.sheet .ri p { margin: 0; }
.sheet .ri-open { padding: 8px 12px; border-left: 4px solid var(--accent); background: rgba(0, 0, 0, 0.25); font-weight: 600; font-size: calc(15px * var(--ts, 1)); }
.sheet .ri-field { display: grid; gap: 2px; margin-top: 4px; font-size: calc(15px * var(--ts, 1)); }
.sheet .ri textarea { font-size: 16px; } /* (smaller, and a phone zooms the page when the box is entered) */
.sheet .ri textarea.ri-short { min-height: 66px; }
.sheet .ri textarea:focus-visible, .sheet .ri input:focus-visible, .sheet .ri summary:focus-visible, .sheet .ri button:focus-visible { outline: 3px solid #91d1bd; outline-offset: 2px; }
body.pad-on .sheet .ri textarea:focus { outline: 3px solid #91d1bd; outline-offset: 2px; }
.sheet .ri-shot img { display: block; max-width: 100%; max-height: 150px; border: 1px solid var(--line); }
.sheet .ri-shot img[hidden] { display: none; }
.sheet .ri-sent { border: 1px solid var(--line); border-radius: 8px; padding: 0 12px; }
.sheet .ri-sent > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; }
.sheet .ri-sent > summary::before { content: "+"; display: inline-block; width: 1.1em; font-weight: 700; }
.sheet .ri-sent[open] > summary::before { content: "-"; }
.sheet .ri-sent p { margin: 6px 0 10px; font-size: calc(14px * var(--ts, 1)); }
.sheet .ri-sent dl { display: grid; grid-template-columns: minmax(7.5em, auto) minmax(0, 1fr); gap: 4px 12px; margin: 0 0 10px; font-size: calc(13px * var(--ts, 1)); }
.sheet .ri-sent dt { color: var(--muted); }
.sheet .ri-sent dd { margin: 0; overflow-wrap: anywhere; user-select: text; -webkit-user-select: text; }
.sheet .ri-say { min-height: 1.4em; font-weight: 600; }
.sheet .ri .chips { display: flex; flex-wrap: wrap; gap: 8px; }
